diff --git a/SOURCES/bz1682119-install-tests.patch b/SOURCES/bz1682119-install-tests.patch new file mode 100644 index 0000000..fa611d9 --- /dev/null +++ b/SOURCES/bz1682119-install-tests.patch @@ -0,0 +1,145 @@ +diff -urp libqb-1.0.3.orig/configure.ac libqb-1.0.3/configure.ac +--- libqb-1.0.3.orig/configure.ac 2019-03-19 12:37:55.207208435 +0000 ++++ libqb-1.0.3/configure.ac 2019-03-19 12:38:31.947311047 +0000 +@@ -526,6 +526,17 @@ AC_ARG_WITH([force-sockets-config-file], + [ FORCESOCKETSFILE="$withval" ], + [ FORCESOCKETSFILE="$sysconfdir/libqb/force-filesystem-sockets" ]) + ++AC_ARG_ENABLE([install-tests], ++ [AS_HELP_STRING([--enable-install-tests],[install tests])],, ++ [ enable_install_tests="no" ]) ++AM_CONDITIONAL([INSTALL_TESTS], [test x$enable_install_tests = xyes]) ++ ++AC_ARG_WITH([testdir], ++ [AS_HELP_STRING([--with-testdir=DIR],[path to /usr/lib../libqb/tests/ dir where to install the test suite])], ++ [ TESTDIR="$withval" ], ++ [ TESTDIR="$libdir/libqb/tests" ]) ++AC_SUBST([TESTDIR]) ++ + AC_SUBST(CP) + # *FLAGS handling goes here + +diff -urp libqb-1.0.3.orig/libqb.spec.in libqb-1.0.3/libqb.spec.in +--- libqb-1.0.3.orig/libqb.spec.in 2017-12-14 09:25:16.000000000 +0000 ++++ libqb-1.0.3/libqb.spec.in 2019-03-19 12:38:31.948311049 +0000 +@@ -1,4 +1,5 @@ + %bcond_without check ++%bcond_without testsrpm + + %global alphatag @alphatag@ + %global numcomm @numcomm@ +@@ -26,7 +27,11 @@ and polling. + + %build + ./autogen.sh +-%configure --disable-static ++%configure \ ++%if %{with testsrpm} ++ --enable-install-tests \ ++%endif ++ --disable-static + make %{?_smp_mflags} + + %if 0%{?with_check} +@@ -67,6 +72,20 @@ developing applications that use %{name} + %{_libdir}/pkgconfig/libqb.pc + %{_mandir}/man3/qb*3* + ++%if %{with testsrpm} ++%package tests ++Summary: Test suite for %{name} ++Group: Development/Libraries ++Requires: %{name}%{?_isa} = %{version}-%{release} ++ ++%files tests ++%doc COPYING ++%{_libdir}/libqb/tests/* ++ ++%description tests ++The %{name}-tests package contains the %{name} test suite. ++%endif ++ + %changelog + * @date@ Autotools generated version - @version@-1-@numcomm@.@alphatag@.@dirty@ + - Autotools generated version +diff -urp libqb-1.0.3.orig/tests/blackbox-segfault.sh libqb-1.0.3/tests/blackbox-segfault.sh +--- libqb-1.0.3.orig/tests/blackbox-segfault.sh 2017-11-17 13:31:14.000000000 +0000 ++++ libqb-1.0.3/tests/blackbox-segfault.sh 2019-03-19 12:44:06.650325170 +0000 +@@ -1,25 +1,31 @@ +-#!/bin/sh ++#!/bin/sh ++# ++# Needs PATH to be set to find accompanying test programs ++# - including qb-blackbox which for in-tree tests should be ++# - in ../tools ++ + # + # create a normal blackbox ++# + rm -f crash-test-dummy.fdata +-./crash_test_dummy ++crash_test_dummy ++rm -f core* + +-. ./test.conf ++. test.conf + + # first test that reading the valid + # blackbox data actually works. +-../tools/qb-blackbox crash-test-dummy.fdata ++qb-blackbox crash-test-dummy.fdata + if [ $? -ne 0 ]; then + exit 1 + fi + +- + for i in $(seq $NUM_BB_TESTS) + do + rm -f butchered_blackbox.fdata + echo " ==== Corrupt blackbox test $i/$NUM_BB_TESTS ====" +- ./file_change_bytes -i crash-test-dummy.fdata -o butchered_blackbox.fdata -n 1024 +- ../tools/qb-blackbox butchered_blackbox.fdata ++ file_change_bytes -i crash-test-dummy.fdata -o butchered_blackbox.fdata -n 1024 ++ qb-blackbox butchered_blackbox.fdata + [ $? -gt 127 ] && exit 1 || true + done + +diff -urp libqb-1.0.3.orig/tests/Makefile.am libqb-1.0.3/tests/Makefile.am +--- libqb-1.0.3.orig/tests/Makefile.am 2017-12-14 09:25:16.000000000 +0000 ++++ libqb-1.0.3/tests/Makefile.am 2019-03-19 12:39:40.658511799 +0000 +@@ -23,10 +23,13 @@ CLEANFILES = + + SUBDIRS = functional + ++export SOCKETDIR ++ + AM_CPPFLAGS = -I$(top_builddir)/include -I$(top_srcdir)/include + + noinst_PROGRAMS = bmc bmcpt bms rbreader rbwriter \ +- bench-log format_compare_speed loop print_ver ++ bench-log format_compare_speed loop print_ver \ ++ $(check_PROGRAMS) + + noinst_HEADERS = check_common.h + +@@ -107,6 +110,7 @@ EXTRA_DIST += resources.test + EXTRA_DIST += blackbox-segfault.sh + + TESTS = array.test map.test rb.test log.test blackbox-segfault.sh loop.test ipc.test resources.test ++TESTS_ENVIRONMENT = export PATH=.:../tools:$$PATH; + + resources.log: rb.log log.log ipc.log + +@@ -119,6 +123,12 @@ TESTS += util.test + check_PROGRAMS += util.test + endif + ++if INSTALL_TESTS ++testsuitedir = $(TESTDIR) ++testsuite_PROGRAMS = $(check_PROGRAMS) ++testsuite_SCRIPTS = $(dist_check_SCRIPTS) test.conf ++endif ++ + file_change_bytes_SOURCES = file_change_bytes.c + + crash_test_dummy_SOURCES = crash_test_dummy.c $(top_builddir)/include/qb/qblog.h diff --git a/SOURCES/bz1714854-improve-shm-security.patch b/SOURCES/bz1714854-improve-shm-security.patch new file mode 100644 index 0000000..5eff40b --- /dev/null +++ b/SOURCES/bz1714854-improve-shm-security.patch @@ -0,0 +1,238 @@ +diff -rup libqb-1.0.3.orig/lib/ipc_int.h libqb-1.0.3/lib/ipc_int.h +--- libqb-1.0.3.orig/lib/ipc_int.h 2017-11-17 13:31:14.000000000 +0000 ++++ libqb-1.0.3/lib/ipc_int.h 2019-05-30 14:51:44.758129831 +0100 +@@ -160,7 +160,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; +@@ -207,4 +207,6 @@ int32_t qb_ipc_us_sock_error_is_disconne + + int use_filesystem_sockets(void); + ++void remove_tempdir(const char *name); ++ + #endif /* QB_IPC_INT_H_DEFINED */ +Only in libqb-1.0.3/lib: ipc_int.h.orig +diff -rup libqb-1.0.3.orig/lib/ipcs.c libqb-1.0.3/lib/ipcs.c +--- libqb-1.0.3.orig/lib/ipcs.c 2017-11-17 13:31:14.000000000 +0000 ++++ libqb-1.0.3/lib/ipcs.c 2019-05-30 14:51:44.759129833 +0100 +@@ -642,12 +642,13 @@ qb_ipcs_disconnect(struct qb_ipcs_connec + scheduled_retry = 1; + } + } +- ++ remove_tempdir(c->description); + if (scheduled_retry == 0) { + /* This removes the initial alloc ref */ + qb_ipcs_connection_unref(c); + } + } ++ + } + + static void +diff -rup libqb-1.0.3.orig/lib/ipc_setup.c libqb-1.0.3/lib/ipc_setup.c +--- libqb-1.0.3.orig/lib/ipc_setup.c 2017-11-17 13:31:14.000000000 +0000 ++++ libqb-1.0.3/lib/ipc_setup.c 2019-05-30 14:51:44.759129833 +0100 +@@ -620,6 +620,8 @@ handle_new_connection(struct qb_ipcs_ser + int32_t res2 = 0; + uint32_t max_buffer_size = QB_MAX(req->max_msg_size, s->max_buffer_size); + struct qb_ipc_connection_response response; ++ const char suffix[] = "/qb"; ++ int desc_len; + + c = qb_ipcs_connection_alloc(s); + if (c == NULL) { +@@ -642,8 +644,45 @@ handle_new_connection(struct qb_ipcs_ser + 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 defined(QB_LINUX) || defined(QB_CYGWIN) ++ desc_len = snprintf(c->description, CONNECTION_DESCRIPTION - sizeof suffix, ++ "/dev/shm/qb-%d-%d-%d-XXXXXX", s->pid, ugp->pid, c->setup.u.us.sock); ++ if (desc_len < 0) { ++ res = -errno; ++ goto send_response; ++ } ++ if (desc_len >= CONNECTION_DESCRIPTION - sizeof suffix) { ++ res = -ENAMETOOLONG; ++ goto send_response; ++ } ++ if (mkdtemp(c->description) == NULL) { ++ res = -errno; ++ goto send_response; ++ } ++ if (chmod(c->description, 0770)) { ++ res = -errno; ++ goto send_response; ++ } ++ /* chown can fail because we might not be root */ ++ (void)chown(c->description, c->auth.uid, c->auth.gid); ++ ++ /* We can't pass just a directory spec to the clients */ ++ memcpy(c->description + desc_len, suffix, sizeof suffix); ++#else ++ desc_len = snprintf(c->description, CONNECTION_DESCRIPTION, ++ "%d-%d-%d", s->pid, ugp->pid, c->setup.u.us.sock); ++ if (desc_len < 0) { ++ res = -errno; ++ goto send_response; ++ } ++ if (desc_len >= CONNECTION_DESCRIPTION) { ++ res = -ENAMETOOLONG; ++ goto send_response; ++ } ++#endif ++ ++ + + if (auth_result == 0 && c->service->serv_fns.connection_accept) { + res = c->service->serv_fns.connection_accept(c, +@@ -864,3 +903,21 @@ retry_accept: + qb_ipcs_uc_recv_and_auth(new_fd, s); + return 0; + } ++ ++void remove_tempdir(const char *name) ++{ ++#if defined(QB_LINUX) || defined(QB_CYGWIN) ++ char dirname[PATH_MAX]; ++ char *slash = strrchr(name, '/'); ++ ++ if (slash && slash - name < sizeof dirname) { ++ memcpy(dirname, name, slash - name); ++ dirname[slash - name] = '\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 ++} +Only in libqb-1.0.3/lib: ipc_setup.c.orig +diff -rup libqb-1.0.3.orig/lib/ipc_shm.c libqb-1.0.3/lib/ipc_shm.c +--- libqb-1.0.3.orig/lib/ipc_shm.c 2017-11-17 13:31:14.000000000 +0000 ++++ libqb-1.0.3/lib/ipc_shm.c 2019-05-30 14:58:42.582211045 +0100 +@@ -239,6 +239,7 @@ qb_ipcs_shm_disconnect(struct qb_ipcs_co + qb_rb_close(qb_rb_lastref_and_ret(&c->request.u.shm.rb)); + } + } ++ remove_tempdir(c->description); + } + + static int32_t +@@ -285,11 +286,11 @@ qb_ipcs_shm_connect(struct qb_ipcs_servi + 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); +Only in libqb-1.0.3/lib: ipc_shm.c~ +Only in libqb-1.0.3/lib: ipc_shm.c.orig +Only in libqb-1.0.3/lib: ipc_shm.c.rej +diff -rup libqb-1.0.3.orig/lib/ipc_socket.c libqb-1.0.3/lib/ipc_socket.c +--- libqb-1.0.3.orig/lib/ipc_socket.c 2017-11-17 13:31:14.000000000 +0000 ++++ libqb-1.0.3/lib/ipc_socket.c 2019-05-30 14:51:44.761129838 +0100 +@@ -374,6 +374,10 @@ qb_ipcc_us_disconnect(struct qb_ipcc_con + free(base_name); + } + } ++ ++ /* Last-ditch attempt to tidy up after ourself */ ++ remove_tempdir(c->request.u.us.shared_file_name); ++ + 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_con + 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); + } + + static int32_t +@@ -784,13 +791,13 @@ qb_ipcs_us_connect(struct qb_ipcs_servic + 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, +- O_CREAT | O_TRUNC | O_RDWR); ++ O_CREAT | O_TRUNC | O_RDWR | O_EXCL); + if (fd_hdr < 0) { + res = fd_hdr; + errno = -fd_hdr; +Only in libqb-1.0.3/lib: ipc_socket.c.orig +diff -rup libqb-1.0.3.orig/lib/ringbuffer.c libqb-1.0.3/lib/ringbuffer.c +--- libqb-1.0.3.orig/lib/ringbuffer.c 2017-12-21 09:02:11.000000000 +0000 ++++ libqb-1.0.3/lib/ringbuffer.c 2019-05-30 14:51:44.761129838 +0100 +@@ -155,7 +155,7 @@ qb_rb_open_2(const char *name, size_t si + 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)); +@@ -166,7 +166,7 @@ qb_rb_open_2(const char *name, size_t si + /* + * 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 si + * 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 -rup libqb-1.0.3.orig/lib/unix.c libqb-1.0.3/lib/unix.c +--- libqb-1.0.3.orig/lib/unix.c 2017-11-17 13:31:14.000000000 +0000 ++++ libqb-1.0.3/lib/unix.c 2019-05-30 14:51:44.761129838 +0100 +@@ -81,7 +81,9 @@ qb_sys_mmap_file_open(char *path, const + (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/SOURCES/bz1718773-avoid-ipc-deadlock.patch b/SOURCES/bz1718773-avoid-ipc-deadlock.patch new file mode 100644 index 0000000..31bcbc6 --- /dev/null +++ b/SOURCES/bz1718773-avoid-ipc-deadlock.patch @@ -0,0 +1,23 @@ +diff --git a/lib/ipc_setup.c b/lib/ipc_setup.c +index 43dc3e7..b3f3412 100644 +--- a/lib/ipc_setup.c ++++ b/lib/ipc_setup.c +@@ -843,12 +843,13 @@ qb_ipcs_uc_recv_and_auth(int32_t sock, struct qb_ipcs_service *s) + setsockopt(sock, SOL_SOCKET, SO_PASSCRED, &on, sizeof(on)); + #endif + +- res = s->poll_fns.dispatch_add(QB_LOOP_MED, +- data->sock, +- POLLIN | POLLPRI | POLLNVAL, +- data, process_auth); ++ res = s->poll_fns.dispatch_add(s->poll_priority, ++ data->sock, ++ POLLIN | POLLPRI | POLLNVAL, ++ data, process_auth); + if (res < 0) { +- qb_util_log(LOG_DEBUG, "Failed to process AUTH for fd (%d)", data->sock); ++ qb_util_log(LOG_DEBUG, "Failed to arrange for AUTH for fd (%d)", ++ data->sock); + close(sock); + destroy_ipc_auth_data(data); + } diff --git a/SPECS/libqb.spec b/SPECS/libqb.spec index a4d4b52..2c7b4ca 100644 --- a/SPECS/libqb.spec +++ b/SPECS/libqb.spec @@ -1,8 +1,9 @@ %bcond_without check +%bcond_without testsrpm Name: libqb Version: 1.0.3 -Release: 7%{?dist} +Release: 10%{?dist} Summary: An IPC library for high performance servers Group: System Environment/Libraries @@ -11,6 +12,9 @@ URL: https://github.com/ClusterLabs/libqb Source0: https://github.com/ClusterLabs/libqb/releases/download/v%{version}/%{name}-%{version}.tar.xz Patch0: bz1615945-remove-linker-callsites.patch +Patch1: bz1682119-install-tests.patch +Patch2: bz1714854-improve-shm-security.patch +Patch3: bz1718773-avoid-ipc-deadlock.patch BuildRequires: autoconf automake libtool doxygen procps check-devel # https://fedoraproject.org/wiki/Packaging:C_and_C%2B%2B#BuildRequires_and_Requires @@ -27,10 +31,17 @@ and polling. %setup #autosetup -p1 -S git_am # for when patches around %patch0 -p1 -b .bz1615945-remove-linker-callsites +%patch1 -p1 -b .bz1682119-install-tests +%patch2 -p1 -b .bz1714854-improve-shm-security.patch +%patch3 -p1 -b bz1718773-avoid-ipc-deadlock.patch %build ./autogen.sh -%configure --disable-static +%configure \ +%if %{with testsrpm} + --enable-install-tests \ +%endif + --disable-static make %{?_smp_mflags} V=1 %if 0%{?with_check} @@ -72,7 +83,34 @@ developing applications that use %{name}. %{_libdir}/pkgconfig/libqb.pc %{_mandir}/man3/qb*3* +%if %{with testsrpm} +%package tests +Summary: Test suite for %{name} +Group: Development/Libraries +Requires: %{name}%{?_isa} = %{version}-%{release} + +%files tests +%doc COPYING +%{_libdir}/libqb/tests/* + +%description tests +The %{name}-tests package contains the %{name} test suite. +%endif + + %changelog +* Mon Jun 10 2019 Christine Caulfield - 1.0.3-10 + Avoid deadlock in IPC connections + Resolves: rhbz#1718773 + +* Thu Jun 6 2019 Christine Caulfield - 1.0.3-9 + Improve security of SHM files used for IPCs + Resolves: rhbz#1714854 + +* Thu Mar 28 2019 Christine Caulfield - 1.0.3-8 +- Add RHEL-8.1 gating tests + Resolves: rhbz#1682119 + * Mon Sep 17 2018 Christine Caulfield - 1.0.3-7 - Remove linker magic in the logging code. Resolves: rhbz#1615945