Hello community,

here is the log from the commit of package nbd for openSUSE:Factory checked in 
at 2015-05-15 07:43:06
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Comparing /work/SRC/openSUSE:Factory/nbd (Old)
 and      /work/SRC/openSUSE:Factory/.nbd.new (New)
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Package is "nbd"

Changes:
--------
--- /work/SRC/openSUSE:Factory/nbd/nbd.changes  2015-04-21 10:51:50.000000000 
+0200
+++ /work/SRC/openSUSE:Factory/.nbd.new/nbd.changes     2015-05-15 
07:43:19.000000000 +0200
@@ -1,0 +2,6 @@
+Mon May 11 08:13:48 UTC 2015 - [email protected]
+
+- Fix CVE-2015-0847
+  * nbd_signaling_CVE-2015-0847.patch
+
+-------------------------------------------------------------------

New:
----
  nbd_signaling_CVE-2015-0847.patch

++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

Other differences:
------------------
++++++ nbd.spec ++++++
--- /var/tmp/diff_new_pack.AAILhO/_old  2015-05-15 07:43:20.000000000 +0200
+++ /var/tmp/diff_new_pack.AAILhO/_new  2015-05-15 07:43:20.000000000 +0200
@@ -32,6 +32,8 @@
 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 @@
 %patch2 -p1
 %patch3 -p1
 %patch4 -p1
+%patch5 -p1
 
 %build
 export CFLAGS="%{optflags} -fstack-protector -fno-strict-aliasing"

++++++ nbd_signaling_CVE-2015-0847.patch ++++++
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 <nbdsrv.h>
 
+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);

Reply via email to