]> granicus.if.org Git - apache/commitdiff
*) SECURITY: CAN-2004-0174 (cve.mitre.org)
authorJeff Trawick <trawick@apache.org>
Fri, 19 Mar 2004 11:16:03 +0000 (11:16 +0000)
committerJeff Trawick <trawick@apache.org>
Fri, 19 Mar 2004 11:16:03 +0000 (11:16 +0000)
     Fix starvation issue on listening sockets where a short-lived
     connection on a rarely-accessed listening socket will cause a
     child to hold the accept mutex and block out new connections until
     another connection arrives on that rarely-accessed listening socket.
     With Apache 2.x there is no performance concern about enabling the
     logic for platforms which don't need it, so it is enabled everywhere
     except for Win32.  [Jeff Trawick]

(already in 2.0.49, propagating to mirrors now)

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/trunk@103029 13f79535-47bb-0310-9956-ffa450edef68

CHANGES
configure.in
include/ap_config.h
os/unix/unixd.c
server/listen.c
server/mpm/netware/mpm_netware.c

diff --git a/CHANGES b/CHANGES
index 197396dafa3dd9a2b6ff7082af329f574e5527f7..0e793cdf844d91de340f16b0264dbfda93771e48 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -283,6 +283,15 @@ Changes with Apache 2.1.0-dev
 
 Changes with Apache 2.0.49
 
+  *) SECURITY: CAN-2004-0174 (cve.mitre.org)
+     Fix starvation issue on listening sockets where a short-lived
+     connection on a rarely-accessed listening socket will cause a
+     child to hold the accept mutex and block out new connections until
+     another connection arrives on that rarely-accessed listening socket.
+     With Apache 2.x there is no performance concern about enabling the 
+     logic for platforms which don't need it, so it is enabled everywhere
+     except for Win32.  [Jeff Trawick]
+
   *) mod_cgid: Fix storage corruption caused by use of incorrect pool.
      [Jeff Trawick]
 
index 5f393e100437695b34bfde24322a9691de95c428..68bc23bb0e7bf5ebc2c6f0e620403a02304da876 100644 (file)
@@ -235,6 +235,8 @@ case $host in
       ;;
 esac
 
+APR_SETVAR(AP_NONBLOCK_WHEN_MULTI_LISTEN, [1])
+
 dnl
 dnl Process command line arguments. This is done early in the process so the
 dnl user can get feedback quickly in case of an error.
@@ -486,6 +488,11 @@ if test "$SINGLE_LISTEN_UNSERIALIZED_ACCEPT" = "1"; then
               [This platform doesn't suffer from the thundering herd problem])
 fi
 
+if test "$AP_NONBLOCK_WHEN_MULTI_LISTEN" = "1"; then
+    AC_DEFINE(AP_NONBLOCK_WHEN_MULTI_LISTEN, 1, 
+              [Listening sockets are non-blocking when there are more than 1])
+fi
+
 AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL, SIG$AP_SIG_GRACEFUL, [Signal used to gracefully restart])
 AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL_STRING, "SIG$AP_SIG_GRACEFUL", [Signal used to gracefully restart (as a quoted string)])
 AC_DEFINE_UNQUOTED(AP_SIG_GRACEFUL_SHORT, $AP_SIG_GRACEFUL, [Signal used to gracefully restart (without SIG prefix)])
index 04d01a4d0841f38b5409751b500873fccffafcb1..6c0fd50a4b40bdc5e2d6a01288c877abf5423b8c 100644 (file)
 #include "ap_config_auto.h"
 #include "ap_config_layout.h"
 #endif
+#if defined(NETWARE)
+#define AP_NONBLOCK_WHEN_MULTI_LISTEN 1
+#endif
 
 /* TODO - We need to put OS detection back to make all the following work */
 
index 082b3cf6a7d58eadad5cf98174a717599933dbe0..6d43fe70f5f3bdcdacb7c048a2cbb0c7db818dff 100644 (file)
@@ -530,6 +530,19 @@ AP_DECLARE(apr_status_t) unixd_accept(void **accepted, ap_listen_rec *lr,
 #endif
 #ifdef ENETUNREACH
         case ENETUNREACH:
+#endif
+        /* EAGAIN/EWOULDBLOCK can be returned on BSD-derived
+         * TCP stacks when the connection is aborted before
+         * we call connect, but only because our listener
+         * sockets are non-blocking (AP_NONBLOCK_WHEN_MULTI_LISTEN)
+         */
+#ifdef EAGAIN
+        case EAGAIN:
+#endif
+#ifdef EWOULDBLOCK
+#if !defined(EAGAIN) || EAGAIN != EWOULDBLOCK
+        case EWOULDBLOCK:
+#endif
 #endif
             break;
 #ifdef ENETDOWN
index 56a99751bc65c1da2dbdac17af5d2d3f09d0c4fe..e6873baec489752a64a2705afc74cf96a4e26362 100644 (file)
@@ -383,6 +383,26 @@ static int ap_listen_open(apr_pool_t *pool, apr_port_t port)
     }
     old_listeners = NULL;
 
+#if AP_NONBLOCK_WHEN_MULTI_LISTEN
+    /* if multiple listening sockets, make them non-blocking so that
+     * if select()/poll() reports readability for a reset connection that
+     * is already forgotten about by the time we call accept, we won't
+     * be hung until another connection arrives on that port
+     */
+    if (ap_listeners->next) {
+        for (lr = ap_listeners; lr; lr = lr->next) {
+            apr_status_t status;
+
+            status = apr_socket_opt_set(lr->sd, APR_SO_NONBLOCK, 1);
+            if (status != APR_SUCCESS) {
+                ap_log_perror(APLOG_MARK, APLOG_STARTUP|APLOG_ERR, status, pool,
+                              "ap_listen_open: unable to make socket non-blocking");
+                return -1;
+            }
+        }
+    }
+#endif /* AP_NONBLOCK_WHEN_MULTI_LISTEN */
+
     /* we come through here on both passes of the open logs phase
      * only register the cleanup once... otherwise we try to close
      * listening sockets twice when cleaning up prior to exec
index 34e8cbf56eb80c97d74f25d3285067be62eb792d..27f0e517205a394ef9491be21e006d1ddcf811f9 100644 (file)
@@ -828,9 +828,6 @@ static int setup_listeners(server_rec *s)
         if (sockdes > listenmaxfd) {
             listenmaxfd = sockdes;
         }
-        /* Use non-blocking listen sockets so that we
-           never get hung up. */
-        apr_socket_opt_set(lr->sd, APR_SO_NONBLOCK, 1);
     }
     return 0;
 }