!3 Fix CVE-2019-12779
From: @yang_zhuang_zhuang Reviewed-by: @overweight,@liqingqing_1229 Signed-off-by: @overweight,@liqingqing_1229
This commit is contained in:
commit
c0dc12575b
@ -0,0 +1,134 @@
|
||||
From e322e98dc264bc5911d6fe1d371e55ac9f95a71e Mon Sep 17 00:00:00 2001
|
||||
From: Christine Caulfield <ccaulfie@redhat.com>
|
||||
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 <ccaulfie@redhat.com>
|
||||
---
|
||||
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));
|
||||
106
backport-0002-CVE-2019-12779-ipc-fixes.patch
Normal file
106
backport-0002-CVE-2019-12779-ipc-fixes.patch
Normal file
@ -0,0 +1,106 @@
|
||||
From 7cd7b06d52ac80c343f362c7e39ef75495439dfc Mon Sep 17 00:00:00 2001
|
||||
From: Christine Caulfield <ccaulfie@redhat.com>
|
||||
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;
|
||||
@ -0,0 +1,228 @@
|
||||
From 6a4067c1d1764d93d255eccecfd8bf9f43cb0b4d Mon Sep 17 00:00:00 2001
|
||||
From: Christine Caulfield <ccaulfie@redhat.com>
|
||||
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;
|
||||
@ -0,0 +1,189 @@
|
||||
From 75ab31bdd05a15947dc56edf4d6b7f377355435e Mon Sep 17 00:00:00 2001
|
||||
From: Chrissie Caulfield <ccaulfie@redhat.com>
|
||||
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 <ccaulfie@redhat.com>
|
||||
Reviewed by: Jan Friesse <jfriesse@redhat.com>
|
||||
---
|
||||
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 <poll.h>
|
||||
+#include <signal.h>
|
||||
+#include <setjmp.h>
|
||||
|
||||
#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
|
||||
11
libqb.spec
11
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 <yangzhuangzhuang1@huawei.com> - 1.0.3-7
|
||||
- Fix CVE-2019-12779
|
||||
|
||||
* Tue Apr 27 2020 wangerfeng <wangerfeng5@huawei.com> - 1.0.3-6
|
||||
- Package init
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user