From 6e1eb1c3158937c539e7215294f12b1c9b9ab8c6ac899651bde9a4416eba2269 Mon Sep 17 00:00:00 2001 From: Marcus Meissner Date: Mon, 11 May 2015 11:43:59 +0000 Subject: [PATCH] Accepting request 306309 from home:pluskalm:branches:network:utilities - Fix CVE-2015-0847 * nbd_signaling_CVE-2015-0847.patch OBS-URL: https://build.opensuse.org/request/show/306309 OBS-URL: https://build.opensuse.org/package/show/network:utilities/nbd?expand=0&rev=31 --- nbd.changes | 6 + nbd.spec | 3 + nbd_signaling_CVE-2015-0847.patch | 181 ++++++++++++++++++++++++++++++ 3 files changed, 190 insertions(+) create mode 100644 nbd_signaling_CVE-2015-0847.patch diff --git a/nbd.changes b/nbd.changes index 15ec913..d0e8aeb 100644 --- a/nbd.changes +++ b/nbd.changes @@ -1,3 +1,9 @@ +------------------------------------------------------------------- +Mon May 11 08:13:48 UTC 2015 - mpluskal@suse.com + +- Fix CVE-2015-0847 + * nbd_signaling_CVE-2015-0847.patch + ------------------------------------------------------------------- Fri Apr 17 13:27:19 UTC 2015 - mpluskal@suse.com diff --git a/nbd.spec b/nbd.spec index fd6277b..bae7e70 100644 --- a/nbd.spec +++ b/nbd.spec @@ -32,6 +32,8 @@ Patch2: nbd-2.9.25-close.diff Patch3: nbd-2.9.25-doxyfile.diff # fix return value Patch4: no-return-nonvoid.patch +# fix for CVE-2015-0847 (incorrect signal handling DoD) +Patch5: nbd_signaling_CVE-2015-0847.patch BuildRequires: doxygen BuildRequires: glib2-devel >= 2.26.0 BuildRequires: xz @@ -89,6 +91,7 @@ the connection closes. %patch2 -p1 %patch3 -p1 %patch4 -p1 +%patch5 -p1 %build export CFLAGS="%{optflags} -fstack-protector -fno-strict-aliasing" diff --git a/nbd_signaling_CVE-2015-0847.patch b/nbd_signaling_CVE-2015-0847.patch new file mode 100644 index 0000000..70c7f42 --- /dev/null +++ b/nbd_signaling_CVE-2015-0847.patch @@ -0,0 +1,181 @@ +Index: nbd-3.10/nbd-server.c +=================================================================== +--- nbd-3.10.orig/nbd-server.c ++++ nbd-3.10/nbd-server.c +@@ -168,6 +168,16 @@ char default_authname[] = SYSCONFDIR "/n + + #include + ++static volatile sig_atomic_t is_sigchld_caught; /**< Flag set by ++ SIGCHLD handler ++ to mark a child ++ exit */ ++ ++static volatile sig_atomic_t is_sigterm_caught; /**< Flag set by ++ SIGTERM handler ++ to mark a exit ++ request */ ++ + static volatile sig_atomic_t is_sighup_caught; /**< Flag set by SIGHUP + handler to mark a + reconfiguration +@@ -930,27 +940,16 @@ GArray* parse_cfile(gchar* f, struct gen + } + + /** +- * Signal handler for SIGCHLD ++ * Handle SIGCHLD by setting atomically a flag which will be evaluated in the ++ * main loop of the root server process. This allows us to separate the signal ++ * catching from th actual task triggered by SIGCHLD and hence processing in the ++ * interrupt context is kept as minimial as possible. ++ * + * @param s the signal we're handling (must be SIGCHLD, or something + * is severely wrong) + **/ +-void sigchld_handler(int s) { +- int status; +- int* i; +- pid_t pid; +- +- while((pid=waitpid(-1, &status, WNOHANG)) > 0) { +- if(WIFEXITED(status)) { +- msg(LOG_INFO, "Child exited with %d", WEXITSTATUS(status)); +- } +- i=g_hash_table_lookup(children, &pid); +- if(!i) { +- msg(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid); +- } else { +- DEBUG("Removing %d from the list of children", pid); +- g_hash_table_remove(children, &pid); +- } +- } ++static void sigchld_handler(const int s G_GNUC_UNUSED) { ++ is_sigchld_caught = 1; + } + + /** +@@ -968,15 +967,16 @@ void killchild(gpointer key, gpointer va + } + + /** +- * Handle SIGTERM and dispatch it to our children ++ * Handle SIGTERM by setting atomically a flag which will be evaluated in the ++ * main loop of the root server process. This allows us to separate the signal ++ * catching from th actual task triggered by SIGTERM and hence processing in the ++ * interrupt context is kept as minimial as possible. ++ * + * @param s the signal we're handling (must be SIGTERM, or something + * is severely wrong). + **/ +-void sigterm_handler(int s) { +- g_hash_table_foreach(children, killchild, NULL); +- unlink(pidfname); +- +- exit(EXIT_SUCCESS); ++static void sigterm_handler(const int s G_GNUC_UNUSED) { ++ is_sigterm_caught = 1; + } + + /** +@@ -2066,9 +2066,12 @@ spawn_child() + goto out; + } + /* Child */ ++ ++ /* Child's signal disposition is reset to default. */ + signal(SIGCHLD, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); ++ sigemptyset(&oldset); + out: + sigprocmask(SIG_SETMASK, &oldset, NULL); + return pid; +@@ -2262,9 +2265,12 @@ handle_oldstyle_connection(GArray *const + goto handle_connection_out; + } + /* child */ ++ ++ /* Child's signal disposition is reset to default. */ + signal(SIGCHLD, SIG_DFL); + signal(SIGTERM, SIG_DFL); + signal(SIGHUP, SIG_DFL); ++ sigemptyset(&oldset); + sigprocmask(SIG_SETMASK, &oldset, NULL); + + g_hash_table_destroy(children); +@@ -2368,6 +2374,8 @@ void serveloop(GArray* servers) { + int max; + fd_set mset; + fd_set rset; ++ sigset_t blocking_mask; ++ sigset_t original_mask; + + /* + * Set up the master fd_set. The set of descriptors we need +@@ -2390,7 +2398,56 @@ void serveloop(GArray* servers) { + FD_SET(sock, &mset); + max=sock>max?sock:max; + } ++ ++ /* Construct a signal mask which is used to make signal testing and ++ * receiving an atomic operation to ensure no signal is received between ++ * tests and blocking pselect(). */ ++ if (sigemptyset(&blocking_mask) == -1) ++ err("failed to initialize blocking_mask: %m"); ++ ++ if (sigaddset(&blocking_mask, SIGCHLD) == -1) ++ err("failed to add SIGCHLD to blocking_mask: %m"); ++ ++ if (sigaddset(&blocking_mask, SIGHUP) == -1) ++ err("failed to add SIGHUP to blocking_mask: %m"); ++ ++ if (sigaddset(&blocking_mask, SIGTERM) == -1) ++ err("failed to add SIGTERM to blocking_mask: %m"); ++ ++ if (sigprocmask(SIG_BLOCK, &blocking_mask, &original_mask) == -1) ++ err("failed to block signals: %m"); ++ + for(;;) { ++ if (is_sigterm_caught) { ++ is_sigterm_caught = 0; ++ ++ g_hash_table_foreach(children, killchild, NULL); ++ unlink(pidfname); ++ ++ exit(EXIT_SUCCESS); ++ } ++ ++ if (is_sigchld_caught) { ++ int status; ++ int* i; ++ pid_t pid; ++ ++ is_sigchld_caught = 0; ++ ++ while ((pid=waitpid(-1, &status, WNOHANG)) > 0) { ++ if (WIFEXITED(status)) { ++ msg(LOG_INFO, "Child exited with %d", WEXITSTATUS(status)); ++ } ++ i = g_hash_table_lookup(children, &pid); ++ if (!i) { ++ msg(LOG_INFO, "SIGCHLD received for an unknown child with PID %ld", (long)pid); ++ } else { ++ DEBUG("Removing %d from the list of children", pid); ++ g_hash_table_remove(children, &pid); ++ } ++ } ++ } ++ + /* SIGHUP causes the root server process to reconfigure + * itself and add new export servers for each newly + * found export configuration group, i.e. spawn new +@@ -2425,8 +2482,7 @@ void serveloop(GArray* servers) { + } + + memcpy(&rset, &mset, sizeof(fd_set)); +- if(select(max+1, &rset, NULL, NULL, NULL)>0) { +- ++ if (pselect(max + 1, &rset, NULL, NULL, NULL, &original_mask) > 0) { + DEBUG("accept, "); + for(i=0; i < modernsocks->len; i++) { + int sock = g_array_index(modernsocks, int, i);