You are viewing a plain text version of this content. The canonical link for it is here.
Posted to cvs@httpd.apache.org by jo...@apache.org on 2007/07/17 16:48:27 UTC

svn commit: r556936 - in /httpd/httpd/branches/2.2.x: CHANGES configure.in include/ap_mmn.h include/mpm_common.h server/mpm/experimental/event/event.c server/mpm/prefork/prefork.c server/mpm/worker/worker.c server/mpm_common.c

Author: jorton
Date: Tue Jul 17 07:48:25 2007
New Revision: 556936

URL: http://svn.apache.org/viewvc?view=rev&rev=556936
Log:
Merge r551843, r551889 from trunk:

Add alternative fixes for CVE-2007-3304:

* configure.in: Check for getpgid.

* include/mpm_common.h (ap_mpm_safe_kill): New prototype.

* server/mpm_common.c (reclaim_one_pid): Ensure pid validity before
calling apr_proc_wait().
(ap_mpm_safe_kill): New function.

* server/mpm/prefork/prefork.c, server/mpm/worker/worker.c,
server/mpm/experimental/event/event.c: Use ap_mpm_safe_kill() on pids
from the scoreboard, throughout.

* include/ap_mmn.h: Minor bump.

* server/mpm_common.c: getpgid() returns a pid_t

Submitted by: jorton, jim
Reviewed by: jorton, jim, rpluem

Modified:
    httpd/httpd/branches/2.2.x/CHANGES
    httpd/httpd/branches/2.2.x/configure.in
    httpd/httpd/branches/2.2.x/include/ap_mmn.h
    httpd/httpd/branches/2.2.x/include/mpm_common.h
    httpd/httpd/branches/2.2.x/server/mpm/experimental/event/event.c
    httpd/httpd/branches/2.2.x/server/mpm/prefork/prefork.c
    httpd/httpd/branches/2.2.x/server/mpm/worker/worker.c
    httpd/httpd/branches/2.2.x/server/mpm_common.c

Modified: httpd/httpd/branches/2.2.x/CHANGES
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/CHANGES?view=diff&rev=556936&r1=556935&r2=556936
==============================================================================
--- httpd/httpd/branches/2.2.x/CHANGES [utf-8] (original)
+++ httpd/httpd/branches/2.2.x/CHANGES [utf-8] Tue Jul 17 07:48:25 2007
@@ -6,6 +6,11 @@
      Cache-Control header without any value. 
      [Niklas Edmundsson <nikke acc.umu.se>]
 
+  *) SECURITY: CVE-2007-3304 (cve.mitre.org)
+     prefork, worker, event MPMs: Ensure that the parent process cannot
+     be forced to kill processes outside its process group. 
+     [Joe Orton, Jim Jagielski]
+
   *) mod_cache: Do not set Date or Expires when they are missing from
      the original response or are invalid.  [Justin Erenkrantz]
 

Modified: httpd/httpd/branches/2.2.x/configure.in
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/configure.in?view=diff&rev=556936&r1=556935&r2=556936
==============================================================================
--- httpd/httpd/branches/2.2.x/configure.in (original)
+++ httpd/httpd/branches/2.2.x/configure.in Tue Jul 17 07:48:25 2007
@@ -392,6 +392,7 @@
 bindprocessor \
 prctl \
 timegm \
+getpgid
 )
 
 dnl confirm that a void pointer is large enough to store a long integer

Modified: httpd/httpd/branches/2.2.x/include/ap_mmn.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/include/ap_mmn.h?view=diff&rev=556936&r1=556935&r2=556936
==============================================================================
--- httpd/httpd/branches/2.2.x/include/ap_mmn.h (original)
+++ httpd/httpd/branches/2.2.x/include/ap_mmn.h Tue Jul 17 07:48:25 2007
@@ -113,6 +113,8 @@
  * 20051115.3 (2.2.3)  Added server_scheme member to server_rec (minor)
  * 20051115.4 (2.2.4)  Added ap_get_server_banner() and
  *                         ap_get_server_description() (minor)
+ * 20051115.5 (2.2.5)  Added ap_mpm_safe_kill() (minor)
+ *
  */
 
 #define MODULE_MAGIC_COOKIE 0x41503232UL /* "AP22" */
@@ -120,7 +122,7 @@
 #ifndef MODULE_MAGIC_NUMBER_MAJOR
 #define MODULE_MAGIC_NUMBER_MAJOR 20051115
 #endif
-#define MODULE_MAGIC_NUMBER_MINOR 4                     /* 0...n */
+#define MODULE_MAGIC_NUMBER_MINOR 5                     /* 0...n */
 
 /**
  * Determine if the server's current MODULE_MAGIC_NUMBER is at least a

Modified: httpd/httpd/branches/2.2.x/include/mpm_common.h
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/include/mpm_common.h?view=diff&rev=556936&r1=556935&r2=556936
==============================================================================
--- httpd/httpd/branches/2.2.x/include/mpm_common.h (original)
+++ httpd/httpd/branches/2.2.x/include/mpm_common.h Tue Jul 17 07:48:25 2007
@@ -145,6 +145,19 @@
 #endif
 
 /**
+ * Safely signal an MPM child process, if the process is in the
+ * current process group.  Otherwise fail.
+ * @param pid the process id of a child process to signal
+ * @param sig the signal number to send
+ * @return APR_SUCCESS if signal is sent, otherwise an error as per kill(3);
+ * APR_EINVAL is returned if passed either an invalid (< 1) pid, or if
+ * the pid is not in the current process group
+ */
+#ifdef AP_MPM_WANT_RECLAIM_CHILD_PROCESSES
+apr_status_t ap_mpm_safe_kill(pid_t pid, int sig);
+#endif
+
+/**
  * Determine if any child process has died.  If no child process died, then
  * this process sleeps for the amount of time specified by the MPM defined
  * macro SCOREBOARD_MAINTENANCE_INTERVAL.

Modified: httpd/httpd/branches/2.2.x/server/mpm/experimental/event/event.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/server/mpm/experimental/event/event.c?view=diff&rev=556936&r1=556935&r2=556936
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm/experimental/event/event.c (original)
+++ httpd/httpd/branches/2.2.x/server/mpm/experimental/event/event.c Tue Jul 17 07:48:25 2007
@@ -1998,12 +1998,10 @@
 
             active_children = 0;
             for (index = 0; index < ap_daemons_limit; ++index) {
-                if (MPM_CHILD_PID(index) != 0) {
-                    if (kill(MPM_CHILD_PID(index), 0) == 0) {
-                            active_children = 1;
-                            /* Having just one child is enough to stay around */
-                            break;
-                    }
+                if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) {
+                    active_children = 1;
+                    /* Having just one child is enough to stay around */
+                    break;
                 }
             }
         } while (!shutdown_pending && active_children &&

Modified: httpd/httpd/branches/2.2.x/server/mpm/prefork/prefork.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/server/mpm/prefork/prefork.c?view=diff&rev=556936&r1=556935&r2=556936
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm/prefork/prefork.c (original)
+++ httpd/httpd/branches/2.2.x/server/mpm/prefork/prefork.c Tue Jul 17 07:48:25 2007
@@ -1127,7 +1127,7 @@
         for (index = 0; index < ap_daemons_limit; ++index) {
             if (ap_scoreboard_image->servers[index][0].status != SERVER_DEAD) {
                 /* Ask each child to close its listeners. */
-                kill(MPM_CHILD_PID(index), AP_SIG_GRACEFUL);
+                ap_mpm_safe_kill(MPM_CHILD_PID(index), AP_SIG_GRACEFUL);
                 active_children++;
             }
         }
@@ -1165,12 +1165,10 @@
 
             active_children = 0;
             for (index = 0; index < ap_daemons_limit; ++index) {
-                if (MPM_CHILD_PID(index) != 0) {
-                    if (kill(MPM_CHILD_PID(index), 0) == 0) {
-                            active_children = 1;
-                            /* Having just one child is enough to stay around */
-                            break;
-                    }
+                if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) {
+                    active_children = 1;
+                    /* Having just one child is enough to stay around */
+                    break;
                 }
             }
         } while (!shutdown_pending && active_children &&
@@ -1222,7 +1220,7 @@
                  * piped loggers, etc. They almost certainly won't handle
                  * it gracefully.
                  */
-                kill(ap_scoreboard_image->parent[index].pid, AP_SIG_GRACEFUL);
+                ap_mpm_safe_kill(ap_scoreboard_image->parent[index].pid, AP_SIG_GRACEFUL);
             }
         }
     }

Modified: httpd/httpd/branches/2.2.x/server/mpm/worker/worker.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/server/mpm/worker/worker.c?view=diff&rev=556936&r1=556935&r2=556936
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm/worker/worker.c (original)
+++ httpd/httpd/branches/2.2.x/server/mpm/worker/worker.c Tue Jul 17 07:48:25 2007
@@ -1813,12 +1813,10 @@
 
             active_children = 0;
             for (index = 0; index < ap_daemons_limit; ++index) {
-                if (MPM_CHILD_PID(index) != 0) {
-                    if (kill(MPM_CHILD_PID(index), 0) == 0) {
-                            active_children = 1;
-                            /* Having just one child is enough to stay around */
-                            break;
-                    }
+                if (ap_mpm_safe_kill(MPM_CHILD_PID(index), 0) == APR_SUCCESS) {
+                    active_children = 1;
+                    /* Having just one child is enough to stay around */
+                    break;
                 }
             }
         } while (!shutdown_pending && active_children &&

Modified: httpd/httpd/branches/2.2.x/server/mpm_common.c
URL: http://svn.apache.org/viewvc/httpd/httpd/branches/2.2.x/server/mpm_common.c?view=diff&rev=556936&r1=556935&r2=556936
==============================================================================
--- httpd/httpd/branches/2.2.x/server/mpm_common.c (original)
+++ httpd/httpd/branches/2.2.x/server/mpm_common.c Tue Jul 17 07:48:25 2007
@@ -126,6 +126,11 @@
     apr_proc_t proc;
     apr_status_t waitret;
 
+    /* Ensure pid sanity. */
+    if (pid < 1) {
+        return 1;
+    }        
+
     proc.pid = pid;
     waitret = apr_proc_wait(&proc, NULL, NULL, APR_NOWAIT);
     if (waitret != APR_CHILD_NOTDONE) {
@@ -304,6 +309,66 @@
         }
         cur_extra = next;
     }
+}
+
+/* Before sending the signal to the pid this function verifies that
+ * the pid is a member of the current process group; either using
+ * apr_proc_wait(), where waitpid() guarantees to fail for non-child
+ * processes; or by using getpgid() directly, if available. */
+apr_status_t ap_mpm_safe_kill(pid_t pid, int sig)
+{
+#ifndef HAVE_GETPGID
+    apr_proc_t proc;
+    apr_status_t rv;
+    apr_exit_why_e why;
+    int status;
+
+    /* Ensure pid sanity */
+    if (pid < 1) {
+        return APR_EINVAL;
+    }
+
+    proc.pid = pid;
+    rv = apr_proc_wait(&proc, &status, &why, APR_NOWAIT);
+    if (rv == APR_CHILD_DONE) {
+#ifdef AP_MPM_WANT_PROCESS_CHILD_STATUS
+        /* The child already died - log the termination status if
+         * necessary: */
+        ap_process_child_status(&proc, why, status);
+#endif
+        return APR_EINVAL;
+    }
+    else if (rv != APR_CHILD_NOTDONE) {
+        /* The child is already dead and reaped, or was a bogus pid -
+         * log this either way. */
+        ap_log_error(APLOG_MARK, APLOG_NOTICE, rv, ap_server_conf,
+                     "cannot send signal %d to pid %ld (non-child or "
+                     "already dead)", sig, (long)pid);
+        return APR_EINVAL;
+    }
+#else
+    pid_t pg;
+
+    /* Ensure pid sanity. */
+    if (pid < 1) {
+        return APR_EINVAL;
+    }
+
+    pg = getpgid(pid);    
+    if (pg == -1) {
+        /* Process already dead... */
+        return errno;
+    }
+
+    if (pg != getpgrp()) {
+        ap_log_error(APLOG_MARK, APLOG_ALERT, 0, ap_server_conf,
+                     "refusing to send signal %d to pid %ld outside "
+                     "process group", sig, (long)pid);
+        return APR_EINVAL;
+    }
+#endif        
+
+    return kill(pid, sig) ? errno : APR_SUCCESS;
 }
 #endif /* AP_MPM_WANT_RECLAIM_CHILD_PROCESSES */