From cb6b9699b7afcc26f8bea47157a9ad01be1ff6c5 Mon Sep 17 00:00:00 2001 From: yang_zhuang_zhuang <1162011203@qq.com> Date: Fri, 5 Feb 2021 16:32:51 +0800 Subject: [PATCH 1/2] Fix CVE-2019-12779 (cherry picked from commit faf539cd904475e89895b8058c7aad211a3daf17) --- ...on-SHM-files-and-randomize-the-names.patch | 134 ++++++++++ backport-0002-CVE-2019-12779-ipc-fixes.patch | 106 ++++++++ ...se-mkdtemp-for-more-secure-IPC-files.patch | 228 ++++++++++++++++++ ...uncate-SHM-files-of-an-active-server.patch | 189 +++++++++++++++ libqb.spec | 11 +- 5 files changed, 667 insertions(+), 1 deletion(-) create mode 100644 backport-0001-CVE-2019-12779-ipc-use-O_EXCL-on-SHM-files-and-randomize-the-names.patch create mode 100644 backport-0002-CVE-2019-12779-ipc-fixes.patch create mode 100644 backport-0003-CVE-2019-12779-ipc-Use-mkdtemp-for-more-secure-IPC-files.patch create mode 100644 backport-ipc_shm-Don-t-truncate-SHM-files-of-an-active-server.patch diff --git a/backport-0001-CVE-2019-12779-ipc-use-O_EXCL-on-SHM-files-and-randomize-the-names.patch b/backport-0001-CVE-2019-12779-ipc-use-O_EXCL-on-SHM-files-and-randomize-the-names.patch new file mode 100644 index 0000000..eb09013 --- /dev/null +++ b/backport-0001-CVE-2019-12779-ipc-use-O_EXCL-on-SHM-files-and-randomize-the-names.patch @@ -0,0 +1,134 @@ +From e322e98dc264bc5911d6fe1d371e55ac9f95a71e Mon Sep 17 00:00:00 2001 +From: Christine Caulfield +Date: Tue, 12 Mar 2019 10:15:41 +0000 +Subject: [PATCH] ipc: use O_EXCL on SHM files, and randomize the names + +Signed-off-by: Christine Caulfield +--- + lib/ipc_setup.c | 14 ++++++++++++-- + lib/ipc_socket.c | 2 +- + lib/ipcs.c | 14 ++++++++++++++ + lib/log_blackbox.c | 2 +- + lib/ringbuffer.c | 2 +- + 5 files changed, 29 insertions(+), 5 deletions(-) + +diff --git a/lib/ipc_setup.c b/lib/ipc_setup.c +index 0e169643..36ae2cfb 100644 +--- a/lib/ipc_setup.c ++++ b/lib/ipc_setup.c +@@ -43,6 +43,9 @@ + #include "util_int.h" + #include "ipc_int.h" + ++/* Maximum number of times we generate a random socket name before giving up */ ++#define MAX_NAME_RETRY_COUNT 20 ++ + struct ipc_auth_ugp { + uid_t uid; + gid_t gid; +@@ -619,6 +622,7 @@ handle_new_connection(struct qb_ipcs_service *s, + struct qb_ipc_connection_request *req = msg; + int32_t res = auth_result; + int32_t res2 = 0; ++ uint32_t retry_count = 0; + uint32_t max_buffer_size = QB_MAX(req->max_msg_size, s->max_buffer_size); + struct qb_ipc_connection_response response; + +@@ -643,8 +647,6 @@ handle_new_connection(struct qb_ipcs_service *s, + c->auth.gid = c->egid = ugp->gid; + c->auth.mode = 0600; + c->stats.client_pid = ugp->pid; +- snprintf(c->description, CONNECTION_DESCRIPTION, +- "%d-%d-%d", s->pid, ugp->pid, c->setup.u.us.sock); + + if (auth_result == 0 && c->service->serv_fns.connection_accept) { + res = c->service->serv_fns.connection_accept(c, +@@ -657,9 +659,17 @@ handle_new_connection(struct qb_ipcs_service *s, + qb_util_log(LOG_DEBUG, "IPC credentials authenticated (%s)", + c->description); + ++retry_description: ++ snprintf(c->description, CONNECTION_DESCRIPTION, ++ "%d-%d-%lu", s->pid, ugp->pid, (unsigned long)(random()%65536)); ++ + memset(&response, 0, sizeof(response)); + if (s->funcs.connect) { + res = s->funcs.connect(s, c, &response); ++ if (res == -EEXIST && ++retry_count < MAX_NAME_RETRY_COUNT) { ++ qb_util_log(LOG_DEBUG, "Retrying socket name %s (count=%ld)\n", c->description, retry_count); ++ goto retry_description; ++ } + if (res != 0) { + goto send_response; + } +diff --git a/lib/ipc_socket.c b/lib/ipc_socket.c +index fe2040e2..1f7cde38 100644 +--- a/lib/ipc_socket.c ++++ b/lib/ipc_socket.c +@@ -790,7 +790,7 @@ qb_ipcs_us_connect(struct qb_ipcs_service *s, + + fd_hdr = qb_sys_mmap_file_open(path, r->request, + SHM_CONTROL_SIZE, +- O_CREAT | O_TRUNC | O_RDWR); ++ O_CREAT | O_TRUNC | O_RDWR | O_EXCL); + if (fd_hdr < 0) { + res = fd_hdr; + errno = -fd_hdr; +diff --git a/lib/ipcs.c b/lib/ipcs.c +index 4a375fca..573b4276 100644 +--- a/lib/ipcs.c ++++ b/lib/ipcs.c +@@ -40,6 +40,8 @@ qb_ipcs_create(const char *name, + enum qb_ipc_type type, struct qb_ipcs_service_handlers *handlers) + { + struct qb_ipcs_service *s; ++ int fd; ++ unsigned int seed; + + s = calloc(1, sizeof(struct qb_ipcs_service)); + if (s == NULL) { +@@ -75,6 +77,18 @@ qb_ipcs_create(const char *name, + qb_list_init(&s->list); + qb_list_add(&s->list, &qb_ipc_services); + ++ /* Randomise socket names */ ++ fd = open("/dev/urandom", O_RDONLY); ++ if (fd == -1) { ++ seed = (time_t)time(NULL); ++ } else { ++ if (read(fd, &seed, sizeof(seed)) != 4) { ++ seed = (time_t)time(NULL); ++ } ++ close(fd); ++ } ++ srand(seed); ++ + return s; + } + +diff --git a/lib/log_blackbox.c b/lib/log_blackbox.c +index 64c30fe..a451742 100644 +--- a/lib/log_blackbox.c ++++ b/lib/log_blackbox.c +@@ -165,7 +165,7 @@ qb_log_blackbox_write_to_file(const char *filename) + { + ssize_t written_size = 0; + struct qb_log_target *t; +- int fd = open(filename, O_CREAT | O_RDWR, 0700); ++ int fd = open(filename, O_CREAT | O_RDWR | O_EXCL, 0700); + + if (fd < 0) { + return -errno; +diff --git a/lib/ringbuffer.c b/lib/ringbuffer.c +index 81411cb1..8852ff5b 100644 +--- a/lib/ringbuffer.c ++++ b/lib/ringbuffer.c +@@ -155,7 +155,7 @@ qb_rb_open_2(const char *name, size_t size, uint32_t flags, + sizeof(struct qb_ringbuffer_shared_s) + shared_user_data_size; + + if (flags & QB_RB_FLAG_CREATE) { +- file_flags |= O_CREAT | O_TRUNC; ++ file_flags |= O_CREAT | O_TRUNC | O_EXCL; + } + + rb = calloc(1, sizeof(struct qb_ringbuffer_s)); diff --git a/backport-0002-CVE-2019-12779-ipc-fixes.patch b/backport-0002-CVE-2019-12779-ipc-fixes.patch new file mode 100644 index 0000000..315739c --- /dev/null +++ b/backport-0002-CVE-2019-12779-ipc-fixes.patch @@ -0,0 +1,106 @@ +From 7cd7b06d52ac80c343f362c7e39ef75495439dfc Mon Sep 17 00:00:00 2001 +From: Christine Caulfield +Date: Tue, 12 Mar 2019 14:08:47 +0000 +Subject: [PATCH] ipc: fixes + +Use O_EXCL on IPC files +--- + lib/ipc_setup.c | 14 ++------------ + lib/ipcs.c | 14 -------------- + lib/log_blackbox.c | 2 +- + 3 files changed, 3 insertions(+), 27 deletions(-) + +diff --git a/lib/ipc_setup.c b/lib/ipc_setup.c +index 36ae2cfb..0e169643 100644 +--- a/lib/ipc_setup.c ++++ b/lib/ipc_setup.c +@@ -43,9 +43,6 @@ + #include "util_int.h" + #include "ipc_int.h" + +-/* Maximum number of times we generate a random socket name before giving up */ +-#define MAX_NAME_RETRY_COUNT 20 +- + struct ipc_auth_ugp { + uid_t uid; + gid_t gid; +@@ -622,7 +619,6 @@ handle_new_connection(struct qb_ipcs_service *s, + struct qb_ipc_connection_request *req = msg; + int32_t res = auth_result; + int32_t res2 = 0; +- uint32_t retry_count = 0; + uint32_t max_buffer_size = QB_MAX(req->max_msg_size, s->max_buffer_size); + struct qb_ipc_connection_response response; + +@@ -647,6 +643,8 @@ handle_new_connection(struct qb_ipcs_service *s, + c->auth.gid = c->egid = ugp->gid; + c->auth.mode = 0600; + c->stats.client_pid = ugp->pid; ++ snprintf(c->description, CONNECTION_DESCRIPTION, ++ "%d-%d-%d", s->pid, ugp->pid, c->setup.u.us.sock); + + if (auth_result == 0 && c->service->serv_fns.connection_accept) { + res = c->service->serv_fns.connection_accept(c, +@@ -659,17 +657,9 @@ handle_new_connection(struct qb_ipcs_service *s, + qb_util_log(LOG_DEBUG, "IPC credentials authenticated (%s)", + c->description); + +-retry_description: +- snprintf(c->description, CONNECTION_DESCRIPTION, +- "%d-%d-%lu", s->pid, ugp->pid, (unsigned long)(random()%65536)); +- + memset(&response, 0, sizeof(response)); + if (s->funcs.connect) { + res = s->funcs.connect(s, c, &response); +- if (res == -EEXIST && ++retry_count < MAX_NAME_RETRY_COUNT) { +- qb_util_log(LOG_DEBUG, "Retrying socket name %s (count=%ld)\n", c->description, retry_count); +- goto retry_description; +- } + if (res != 0) { + goto send_response; + } +diff --git a/lib/ipcs.c b/lib/ipcs.c +index 573b4276..4a375fca 100644 +--- a/lib/ipcs.c ++++ b/lib/ipcs.c +@@ -40,8 +40,6 @@ qb_ipcs_create(const char *name, + enum qb_ipc_type type, struct qb_ipcs_service_handlers *handlers) + { + struct qb_ipcs_service *s; +- int fd; +- unsigned int seed; + + s = calloc(1, sizeof(struct qb_ipcs_service)); + if (s == NULL) { +@@ -77,18 +75,6 @@ qb_ipcs_create(const char *name, + qb_list_init(&s->list); + qb_list_add(&s->list, &qb_ipc_services); + +- /* Randomise socket names */ +- fd = open("/dev/urandom", O_RDONLY); +- if (fd == -1) { +- seed = (time_t)time(NULL); +- } else { +- if (read(fd, &seed, sizeof(seed)) != 4) { +- seed = (time_t)time(NULL); +- } +- close(fd); +- } +- srand(seed); +- + return s; + } + +diff --git a/lib/log_blackbox.c b/lib/log_blackbox.c +index a451742..9727b4c 100644 +--- a/lib/log_blackbox.c ++++ b/lib/log_blackbox.c +@@ -165,7 +165,7 @@ qb_log_blackbox_write_to_file(const char *filename) + { + ssize_t written_size = 0; + struct qb_log_target *t; +- int fd = open(filename, O_CREAT | O_RDWR | O_EXCL, 0700); ++ int fd = open(filename, O_CREAT | O_RDWR, 0700); + + if (fd < 0) { + return -errno; diff --git a/backport-0003-CVE-2019-12779-ipc-Use-mkdtemp-for-more-secure-IPC-files.patch b/backport-0003-CVE-2019-12779-ipc-Use-mkdtemp-for-more-secure-IPC-files.patch new file mode 100644 index 0000000..c3c64ad --- /dev/null +++ b/backport-0003-CVE-2019-12779-ipc-Use-mkdtemp-for-more-secure-IPC-files.patch @@ -0,0 +1,228 @@ +From 6a4067c1d1764d93d255eccecfd8bf9f43cb0b4d Mon Sep 17 00:00:00 2001 +From: Christine Caulfield +Date: Mon, 8 Apr 2019 16:24:19 +0100 +Subject: [PATCH] ipc: Use mkdtemp for more secure IPC files + +Use mkdtemp makes sure that IPC files are only visible to the +owning (client) process and do not use predictable names outside +of that. + +This is not meant to be the last word on the subject, it's mainly a +simple way of making the current libqb more secure. Importantly, it's +backwards compatible with an old server. + +It calls rmdir on the directory created by mkdtemp way too often, but +it seems to be the only way to be sure that things get cleaned up on +the various types of server/client exit. I'm sure we can come up with +something tidier for master but I hope this, or something similar, will +be OK for 1.0.x. +--- + lib/ipc_int.h | 4 +++- + lib/ipc_setup.c | 39 +++++++++++++++++++++++++++++++++++++++ + lib/ipc_shm.c | 9 ++++++--- + lib/ipc_socket.c | 13 ++++++++++--- + lib/ipcs.c | 3 ++- + lib/ringbuffer.c | 4 ++-- + lib/unix.c | 4 +++- + 7 files changed, 65 insertions(+), 11 deletions(-) + +diff --git a/lib/ipc_int.h b/lib/ipc_int.h +index 9cd06cfe..c8904487 100644 +--- a/lib/ipc_int.h ++++ b/lib/ipc_int.h +@@ -161,7 +161,7 @@ enum qb_ipcs_connection_state { + QB_IPCS_CONNECTION_SHUTTING_DOWN, + }; + +-#define CONNECTION_DESCRIPTION (34) /* INT_MAX length + 3 */ ++#define CONNECTION_DESCRIPTION NAME_MAX + + struct qb_ipcs_connection_auth { + uid_t uid; +@@ -208,4 +208,6 @@ int32_t qb_ipc_us_sock_error_is_disconnected(int err); + + int use_filesystem_sockets(void); + ++void remove_tempdir(const char *name, size_t namelen); ++ + #endif /* QB_IPC_INT_H_DEFINED */ +diff --git a/lib/ipc_setup.c b/lib/ipc_setup.c +index 0e169643..43dc3e78 100644 +--- a/lib/ipc_setup.c ++++ b/lib/ipc_setup.c +@@ -643,8 +643,28 @@ handle_new_connection(struct qb_ipcs_service *s, + c->auth.gid = c->egid = ugp->gid; + c->auth.mode = 0600; + c->stats.client_pid = ugp->pid; ++ ++#if defined(QB_LINUX) || defined(QB_CYGWIN) ++ snprintf(c->description, CONNECTION_DESCRIPTION, ++ "/dev/shm/qb-%d-%d-%d-XXXXXX", s->pid, ugp->pid, c->setup.u.us.sock); ++ if (mkdtemp(c->description) == NULL) { ++ res = errno; ++ goto send_response; ++ } ++ res = chown(c->description, c->auth.uid, c->auth.gid); ++ if (res != 0) { ++ res = errno; ++ goto send_response; ++ } ++ ++ /* We can't pass just a directory spec to the clients */ ++ strncat(c->description,"/qb", CONNECTION_DESCRIPTION); ++#else + snprintf(c->description, CONNECTION_DESCRIPTION, + "%d-%d-%d", s->pid, ugp->pid, c->setup.u.us.sock); ++#endif ++ ++ + + if (auth_result == 0 && c->service->serv_fns.connection_accept) { + res = c->service->serv_fns.connection_accept(c, +@@ -865,3 +885,22 @@ qb_ipcs_us_connection_acceptor(int fd, int revent, void *data) + qb_ipcs_uc_recv_and_auth(new_fd, s); + return 0; + } ++ ++void remove_tempdir(const char *name, size_t namelen) ++{ ++#if defined(QB_LINUX) || defined(QB_CYGWIN) ++ char dirname[PATH_MAX]; ++ char *slash; ++ memcpy(dirname, name, namelen); ++ ++ slash = strrchr(dirname, '/'); ++ if (slash) { ++ *slash = '\0'; ++ /* This gets called more than it needs to be really, so we don't check ++ * the return code. It's more of a desperate attempt to clean up after ourself ++ * in either the server or client. ++ */ ++ (void)rmdir(dirname); ++ } ++#endif ++} +diff --git a/lib/ipc_shm.c b/lib/ipc_shm.c +index 9f237b6e..758a2b51 100644 +--- a/lib/ipc_shm.c ++++ b/lib/ipc_shm.c +@@ -265,6 +265,9 @@ qb_ipcs_shm_disconnect(struct qb_ipcs_connection *c) + c->setup.u.us.sock = -1; + } + } ++ ++ remove_tempdir(c->description, CONNECTION_DESCRIPTION); ++ + end_disconnect: + sigaction(SIGBUS, &old_sa, NULL); + } +@@ -313,11 +316,11 @@ qb_ipcs_shm_connect(struct qb_ipcs_service *s, + qb_util_log(LOG_DEBUG, "connecting to client [%d]", c->pid); + + snprintf(r->request, NAME_MAX, "%s-request-%s", +- s->name, c->description); ++ c->description, s->name); + snprintf(r->response, NAME_MAX, "%s-response-%s", +- s->name, c->description); ++ c->description, s->name); + snprintf(r->event, NAME_MAX, "%s-event-%s", +- s->name, c->description); ++ c->description, s->name); + + res = qb_ipcs_shm_rb_open(c, &c->request, + r->request); +diff --git a/lib/ipc_socket.c b/lib/ipc_socket.c +index 1f7cde38..59492323 100644 +--- a/lib/ipc_socket.c ++++ b/lib/ipc_socket.c +@@ -374,6 +374,10 @@ qb_ipcc_us_disconnect(struct qb_ipcc_connection *c) + free(base_name); + } + } ++ ++ /* Last-ditch attempt to tidy up after ourself */ ++ remove_tempdir(c->request.u.us.shared_file_name, PATH_MAX); ++ + qb_ipcc_us_sock_close(c->event.u.us.sock); + qb_ipcc_us_sock_close(c->request.u.us.sock); + qb_ipcc_us_sock_close(c->setup.u.us.sock); +@@ -765,7 +769,10 @@ qb_ipcs_us_disconnect(struct qb_ipcs_connection *c) + c->state == QB_IPCS_CONNECTION_ACTIVE) { + munmap(c->request.u.us.shared_data, SHM_CONTROL_SIZE); + unlink(c->request.u.us.shared_file_name); ++ ++ + } ++ remove_tempdir(c->description, CONNECTION_DESCRIPTION); + } + + static int32_t +@@ -784,9 +791,9 @@ qb_ipcs_us_connect(struct qb_ipcs_service *s, + c->request.u.us.sock = c->setup.u.us.sock; + c->response.u.us.sock = c->setup.u.us.sock; + +- snprintf(r->request, NAME_MAX, "qb-%s-control-%s", +- s->name, c->description); +- snprintf(r->response, NAME_MAX, "qb-%s-%s", s->name, c->description); ++ snprintf(r->request, NAME_MAX, "%s-control-%s", ++ c->description, s->name); ++ snprintf(r->response, NAME_MAX, "%s-%s", c->description, s->name); + + fd_hdr = qb_sys_mmap_file_open(path, r->request, + SHM_CONTROL_SIZE, +diff --git a/lib/ipcs.c b/lib/ipcs.c +index 4a375fca..29f3431b 100644 +--- a/lib/ipcs.c ++++ b/lib/ipcs.c +@@ -642,12 +642,13 @@ qb_ipcs_disconnect(struct qb_ipcs_connection *c) + scheduled_retry = 1; + } + } +- ++ remove_tempdir(c->description, CONNECTION_DESCRIPTION); + if (scheduled_retry == 0) { + /* This removes the initial alloc ref */ + qb_ipcs_connection_unref(c); + } + } ++ + } + + static void +diff --git a/lib/ringbuffer.c b/lib/ringbuffer.c +index 8852ff5b..f85ad979 100644 +--- a/lib/ringbuffer.c ++++ b/lib/ringbuffer.c +@@ -166,7 +166,7 @@ qb_rb_open_2(const char *name, size_t size, uint32_t flags, + /* + * Create a shared_hdr memory segment for the header. + */ +- snprintf(filename, PATH_MAX, "qb-%s-header", name); ++ snprintf(filename, PATH_MAX, "%s-header", name); + fd_hdr = qb_sys_mmap_file_open(path, filename, + shared_size, file_flags); + if (fd_hdr < 0) { +@@ -217,7 +217,7 @@ qb_rb_open_2(const char *name, size_t size, uint32_t flags, + * They have to be separate. + */ + if (flags & QB_RB_FLAG_CREATE) { +- snprintf(filename, PATH_MAX, "qb-%s-data", name); ++ snprintf(filename, PATH_MAX, "%s-data", name); + fd_data = qb_sys_mmap_file_open(path, + filename, + real_size, file_flags); +diff --git a/lib/unix.c b/lib/unix.c +index 3c8f327c..49701a33 100644 +--- a/lib/unix.c ++++ b/lib/unix.c +@@ -81,7 +81,9 @@ qb_sys_mmap_file_open(char *path, const char *file, size_t bytes, + (void)strlcpy(path, file, PATH_MAX); + } else { + #if defined(QB_LINUX) || defined(QB_CYGWIN) +- snprintf(path, PATH_MAX, "/dev/shm/%s", file); ++ /* This is only now called when talking to an old libqb ++ where we need to add qb- to the name */ ++ snprintf(path, PATH_MAX, "/dev/shm/qb-%s", file); + #else + snprintf(path, PATH_MAX, "%s/%s", SOCKETDIR, file); + is_absolute = path; diff --git a/backport-ipc_shm-Don-t-truncate-SHM-files-of-an-active-server.patch b/backport-ipc_shm-Don-t-truncate-SHM-files-of-an-active-server.patch new file mode 100644 index 0000000..1fd32ce --- /dev/null +++ b/backport-ipc_shm-Don-t-truncate-SHM-files-of-an-active-server.patch @@ -0,0 +1,189 @@ +From 75ab31bdd05a15947dc56edf4d6b7f377355435e Mon Sep 17 00:00:00 2001 +From: Chrissie Caulfield +Date: Fri, 20 Apr 2018 09:48:04 +0100 +Subject: [PATCH] ipc_shm: Don't truncate SHM files of an active server (#307) + +* ipc_shm: Don't truncate SHM files of an active server + +I've put in an extra check so that clients don't truncate the +SHM file if the server still exists. Sadly on FreeBSD we can't +get the server PID for the client (unless someone has a patch handy!) +so we still do the truncate when disconnected. As a backstop (and also +to cover the BSD issue) I've added a SIGBUS trap to the server shutdown +so that it doesn't cause a server crash. + +Signed-off-by: Christine Caulfield +Reviewed by: Jan Friesse +--- + include/qb/qbipcs.h | 4 ++++ + lib/ipc_int.h | 1 + + lib/ipc_setup.c | 1 + + lib/ipc_shm.c | 48 +++++++++++++++++++++++++++++++++++---------- + tests/check_ipc.c | 24 +++++++++++++++++------ + 5 files changed, 62 insertions(+), 16 deletions(-) + +diff --git a/include/qb/qbipcs.h b/include/qb/qbipcs.h +index 55c0f815..7b4daa7d 100644 +--- a/include/qb/qbipcs.h ++++ b/include/qb/qbipcs.h +@@ -142,6 +142,10 @@ typedef void (*qb_ipcs_connection_created_fn) (qb_ipcs_connection_t *c); + * successfully created. + * @note if you return anything but 0 this function will be + * repeatedly called (until 0 is returned). ++ * ++ * With SHM connections libqb will briefly trap SIGBUS during the ++ * disconnect process to guard against server crashes if the mapped ++ * file is truncated. The signal will be restored afterwards. + */ + typedef int32_t (*qb_ipcs_connection_closed_fn) (qb_ipcs_connection_t *c); + +diff --git a/lib/ipc_int.h b/lib/ipc_int.h +index 67fc444c..9cd06cfe 100644 +--- a/lib/ipc_int.h ++++ b/lib/ipc_int.h +@@ -92,6 +92,7 @@ struct qb_ipcc_connection { + char name[NAME_MAX]; + int32_t needs_sock_for_poll; + gid_t egid; ++ pid_t server_pid; + struct qb_ipc_one_way setup; + struct qb_ipc_one_way request; + struct qb_ipc_one_way response; +diff --git a/lib/ipc_setup.c b/lib/ipc_setup.c +index 57d755b4..0e169643 100644 +--- a/lib/ipc_setup.c ++++ b/lib/ipc_setup.c +@@ -494,6 +494,7 @@ qb_ipcc_us_setup_connect(struct qb_ipcc_connection *c, + + qb_ipc_auth_creds(data); + c->egid = data->ugp.gid; ++ c->server_pid = data->ugp.pid; + + destroy_ipc_auth_data(data); + return r->hdr.error; +diff --git a/lib/ipc_shm.c b/lib/ipc_shm.c +index 699f4e47..9f237b6e 100644 +--- a/lib/ipc_shm.c ++++ b/lib/ipc_shm.c +@@ -20,6 +20,8 @@ + */ + #include "os_base.h" + #include ++#include ++#include + + #include "ipc_int.h" + #include "util_int.h" +@@ -36,9 +38,12 @@ + static void + qb_ipcc_shm_disconnect(struct qb_ipcc_connection *c) + { +- void (*rb_destructor)(struct qb_ringbuffer_s *) = c->is_connected +- ? qb_rb_close +- : qb_rb_force_close; ++ void (*rb_destructor)(struct qb_ringbuffer_s *); ++ ++ rb_destructor = qb_rb_close; ++ if (!c->is_connected && (!c->server_pid || (kill(c->server_pid, 0) == -1 && errno == ESRCH))) { ++ rb_destructor = qb_rb_force_close; ++ } + + qb_ipcc_us_sock_close(c->setup.u.us.sock); + +@@ -215,18 +220,30 @@ qb_ipcc_shm_connect(struct qb_ipcc_connection * c, + * service functions + * -------------------------------------------------------- + */ ++static jmp_buf sigbus_jmpbuf; ++static void catch_sigbus(int signal) ++{ ++ longjmp(sigbus_jmpbuf, 1); ++} + + static void + qb_ipcs_shm_disconnect(struct qb_ipcs_connection *c) + { +- if (c->state == QB_IPCS_CONNECTION_ESTABLISHED || +- c->state == QB_IPCS_CONNECTION_ACTIVE) { +- if (c->setup.u.us.sock > 0) { +- (void)c->service->poll_fns.dispatch_del(c->setup.u.us.sock); +- qb_ipcc_us_sock_close(c->setup.u.us.sock); +- c->setup.u.us.sock = -1; +- } ++ struct sigaction sa; ++ struct sigaction old_sa; ++ ++ /* Don't die if the client has truncated the SHM under us */ ++ memset(&old_sa, 0, sizeof(old_sa)); ++ memset(&sa, 0, sizeof(sa)); ++ sa.sa_handler = catch_sigbus; ++ sigemptyset(&sa.sa_mask); ++ sa.sa_flags = 0; ++ sigaction(SIGBUS, &sa, &old_sa); ++ ++ if (setjmp(sigbus_jmpbuf) == 1) { ++ goto end_disconnect; + } ++ + if (c->state == QB_IPCS_CONNECTION_SHUTTING_DOWN || + c->state == QB_IPCS_CONNECTION_ACTIVE) { + if (c->response.u.shm.rb) { +@@ -239,6 +256,17 @@ qb_ipcs_shm_disconnect(struct qb_ipcs_connection *c) + qb_rb_close(qb_rb_lastref_and_ret(&c->request.u.shm.rb)); + } + } ++ ++ if (c->state == QB_IPCS_CONNECTION_ESTABLISHED || ++ c->state == QB_IPCS_CONNECTION_ACTIVE) { ++ if (c->setup.u.us.sock > 0) { ++ (void)c->service->poll_fns.dispatch_del(c->setup.u.us.sock); ++ qb_ipcc_us_sock_close(c->setup.u.us.sock); ++ c->setup.u.us.sock = -1; ++ } ++ } ++end_disconnect: ++ sigaction(SIGBUS, &old_sa, NULL); + } + + static int32_t +diff --git a/tests/check_ipc.c b/tests/check_ipc.c +index f8af2c5e..46c3b404 100644 +--- a/tests/check_ipc.c ++++ b/tests/check_ipc.c +@@ -444,18 +444,30 @@ run_ipc_server(void) + static pid_t + run_function_in_new_process(void (*run_ipc_server_fn)(void)) + { +- pid_t pid = fork (); ++ pid_t pid1 = fork (); ++ pid_t pid2; + +- if (pid == -1) { ++ if (pid1 == -1) { + fprintf (stderr, "Can't fork\n"); + return -1; + } + +- if (pid == 0) { +- run_ipc_server_fn(); +- exit(0); ++ /* Double-fork so the servers can be reaped in a timely manner */ ++ if (pid1 == 0) { ++ pid2 = fork(); ++ if (pid2 == -1) { ++ fprintf (stderr, "Can't fork twice\n"); ++ exit(0); ++ } ++ if (pid2 == 0) { ++ run_ipc_server_fn(); ++ exit(0); ++ } else { ++ waitpid(pid2, NULL, 0); ++ exit(0); ++ } + } +- return pid; ++ return pid1; + } + + static void diff --git a/libqb.spec b/libqb.spec index 32bc3b8..527c21b 100644 --- a/libqb.spec +++ b/libqb.spec @@ -1,11 +1,17 @@ Name: libqb Version: 1.0.3 -Release: 6 +Release: 7 Summary: High performance servers IPC library Group: System Environment/Libraries License: LGPLv2+ URL: https://github.com/ClusterLabs/libqb Source0: https://github.com/ClusterLabs/libqb/releases/download/v%{version}/libqb-%{version}.tar.xz + +Patch1: backport-ipc_shm-Don-t-truncate-SHM-files-of-an-active-server.patch +Patch2: backport-0001-CVE-2019-12779-ipc-use-O_EXCL-on-SHM-files-and-randomize-the-names.patch +Patch3: backport-0002-CVE-2019-12779-ipc-fixes.patch +Patch4: backport-0003-CVE-2019-12779-ipc-Use-mkdtemp-for-more-secure-IPC-files.patch + BuildRequires: autoconf automake libtool doxygen procps check-devel gcc %description @@ -69,5 +75,8 @@ help documents for libqb package %{_mandir}/man3/qb*3* %changelog +* Fri Feb 5 2021 yangzhuangzhuang - 1.0.3-7 +- Fix CVE-2019-12779 + * Tue Apr 27 2020 wangerfeng - 1.0.3-6 - Package init -- Gitee From b31ddc5f29fd482dfb0dd5a410d11a55761be10a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=E6=9D=A8=E5=A3=AE=E5=A3=AE?= <1162011203@qq.com> Date: Mon, 8 Feb 2021 11:49:08 +0800 Subject: [PATCH 2/2] =?UTF-8?q?=E6=B7=BB=E5=8A=A0=E8=AF=B4=E6=98=8E?= =?UTF-8?q?=E4=BF=AE=E5=A4=8D=E7=9A=84=E9=97=AE=E9=A2=98=EF=BC=8C=E5=B9=B6?= =?UTF-8?q?=E9=99=84=E4=B8=8Acve=E9=93=BE=E6=8E=A5=E4=BB=A5=E5=8F=8A?= =?UTF-8?q?=E6=98=AF=E7=A4=BE=E5=8C=BA=E4=BF=AE=E5=A4=8D=E8=A1=A5=E4=B8=81?= =?UTF-8?q?=E9=93=BE=E6=8E=A5?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- libqb.spec | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/libqb.spec b/libqb.spec index 527c21b..45b392f 100644 --- a/libqb.spec +++ b/libqb.spec @@ -76,7 +76,12 @@ help documents for libqb package %changelog * Fri Feb 5 2021 yangzhuangzhuang - 1.0.3-7 -- Fix CVE-2019-12779 +- Fix CVE-2019-12779 libqb before 1.0.5 allows local users to overwrite arbitrary files via a symlink attack。 + CVE Link:https://nvd.nist.gov/vuln/detail/CVE-2019-12779 + Community Patch Link: + https://github.com/ClusterLabs/libqb/commit/e322e98dc264bc5911d6fe1d371e55ac9f95a71e + https://github.com/ClusterLabs/libqb/commit/7cd7b06d52ac80c343f362c7e39ef75495439dfc + https://github.com/ClusterLabs/libqb/commit/6a4067c1d1764d93d255eccecfd8bf9f43cb0b4d * Tue Apr 27 2020 wangerfeng - 1.0.3-6 - Package init -- Gitee