]> git.ipfire.org Git - thirdparty/apache/httpd.git/commitdiff
Add in CAN-2004-0174 patch...
authorJim Jagielski <jim@apache.org>
Mon, 29 Mar 2004 17:33:52 +0000 (17:33 +0000)
committerJim Jagielski <jim@apache.org>
Mon, 29 Mar 2004 17:33:52 +0000 (17:33 +0000)
PR:
Obtained from:
Submitted by:
Reviewed by:

git-svn-id: https://svn.apache.org/repos/asf/httpd/httpd/branches/1.3.x@103189 13f79535-47bb-0310-9956-ffa450edef68

src/CHANGES
src/include/ap_config.h
src/main/http_main.c

index 204f273bfb29e6855b246cd26d2f0a8bf898f8f7..4c69677f349c59a6443748f560e0a61f532c6751 100644 (file)
@@ -1,5 +1,15 @@
 Changes with Apache 1.3.30
 
+  *) 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.
+     Enabled for some platforms known to have the issue (accept()
+     blocking after select() returns readable).  Define 
+     NONBLOCK_WHEN_MULTI_LISTEN if needed for your platform and not
+     already defined.  [Jeff Trawick, Brad Nicholes, Joe Orton]
+
   *) SECURITY: CAN-2003-0993 (cve.mitre.org) 
      Fix parsing of Allow/Deny rules using IP addresses without a
      netmask; issue is only known to affect big-endian 64-bit
index 635a2cbc384515de140f82e759e70e440ee2bac8..7fabc3be88edac57cabad36b38c4dd6dfc84a521 100644 (file)
@@ -151,6 +151,7 @@ int gethostname(char *name, int namelen);
 #define HAVE_SYSLOG 1
 #define SYS_SIGLIST _sys_siglist
 #define AP_ENABLE_EXCEPTION_HOOK
+#define NONBLOCK_WHEN_MULTI_LISTEN
 
 #elif defined(IRIX)
 #undef HAVE_GMTOFF
@@ -174,6 +175,7 @@ int gethostname(char *name, int namelen);
 #define NO_LONG_DOUBLE
 #define NO_LINGCLOSE
 #define HAVE_SYSLOG 1
+#define NONBLOCK_WHEN_MULTI_LISTEN
 
 #elif defined(HIUX)
 #undef HAVE_GMTOFF
@@ -259,6 +261,7 @@ typedef int rlim_t;
 #define NET_SIZE_T size_t
 #endif
 #define AP_ENABLE_EXCEPTION_HOOK
+#define NONBLOCK_WHEN_MULTI_LISTEN
 
 #elif defined(ULTRIX)
 /* we don't want to use sys/resource.h under
@@ -285,6 +288,7 @@ typedef int rlim_t;
 #define HAVE_SYSLOG 1
 #define HAVE_FLOCK_SERIALIZED_ACCEPT
 #define SINGLE_LISTEN_UNSERIALIZED_ACCEPT
+#define NONBLOCK_WHEN_MULTI_LISTEN
 
 #elif defined(PARAGON)
 #define HAVE_GMTOFF 1
@@ -977,6 +981,7 @@ typedef int rlim_t;
 #include <sys/socket.h>
 #define NET_SIZE_T size_t
 #define NEED_HASHBANG_EMUL
+#define NONBLOCK_WHEN_MULTI_LISTEN
 
 #elif defined(CYGWIN)               /* Cygwin 1.x POSIX layer for Win32 */
 #define SYSTEM_UID 18
@@ -996,6 +1001,8 @@ typedef int rlim_t;
 #define USE_PTHREAD_SERIALIZED_ACCEPT
 #endif
 
+#elif defined(NETWARE)
+#define NONBLOCK_WHEN_MULTI_LISTEN
 
 #else
 /* Unknown system - Edit these to match */
index 693da049831e53af2ef6ecb02c33a3091693902e..b56a52b63a998c30ced77779460b47b91eee52d6 100644 (file)
@@ -3920,6 +3920,76 @@ static void close_unused_listeners(void)
     old_listeners = NULL;
 }
 
+#ifdef NONBLOCK_WHEN_MULTI_LISTEN
+/* retrieved from APR */
+static int soblock(int sd)
+{
+#ifdef NETWARE
+    u_long one = 0;
+
+    if (ioctlsocket(sd, FIONBIO, &one) == SOCKET_ERROR) {
+        return -1;
+    }
+#else
+#ifndef BEOS
+    int fd_flags;
+    
+    fd_flags = fcntl(sd, F_GETFL, 0);
+#if defined(O_NONBLOCK)
+    fd_flags &= ~O_NONBLOCK;
+#elif defined(O_NDELAY)
+    fd_flags &= ~O_NDELAY;
+#elif defined(FNDELAY)
+    fd_flags &= ~FNDELAY;
+#else
+#error Teach soblock() how to make a socket blocking on your platform.
+#endif
+    if (fcntl(sd, F_SETFL, fd_flags) == -1) {
+        return errno;
+    }
+#else
+    int on = 0;
+    if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0)
+        return errno;
+#endif /* BEOS */
+#endif /* NETWARE */
+    return 0;
+}
+
+static int sononblock(int sd)
+{
+#ifdef NETWARE
+    u_long one = 1;
+
+    if (ioctlsocket(sd, FIONBIO, &one) == SOCKET_ERROR) {
+        return -1;
+    }
+#else
+#ifndef BEOS
+    int fd_flags;
+    
+    fd_flags = fcntl(sd, F_GETFL, 0);
+#if defined(O_NONBLOCK)
+    fd_flags |= O_NONBLOCK;
+#elif defined(O_NDELAY)
+    fd_flags |= O_NDELAY;
+#elif defined(FNDELAY)
+    fd_flags |= FNDELAY;
+#else
+#error Teach sononblock() how to make a socket non-blocking on your platform.
+#endif
+    if (fcntl(sd, F_SETFL, fd_flags) == -1) {
+        return errno;
+    }
+#else
+    int on = 1;
+    if (setsockopt(sd, SOL_SOCKET, SO_NONBLOCK, &on, sizeof(int)) < 0)
+        return errno;
+#endif /* BEOS */
+#endif /* NETWARE */
+    return 0;
+}
+#endif /* NONBLOCK_WHEN_MULTI_LISTEN */
 
 /* open sockets, and turn the listeners list into a singly linked ring */
 static void setup_listeners(pool *p)
@@ -3952,6 +4022,20 @@ static void setup_listeners(pool *p)
     head_listener = ap_listeners;
     close_unused_listeners();
 
+#ifdef NONBLOCK_WHEN_MULTI_LISTEN
+    if (ap_listeners->next != ap_listeners) {
+        lr = ap_listeners;
+        do {
+            if (sononblock(lr->fd) < 0) {
+                ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+                             "A listening socket could not be made non-blocking.");
+                exit(APEXIT_INIT);
+            }
+            lr = lr->next;
+        } while (lr != ap_listeners);
+    }
+#endif /* NONBLOCK_WHEN_MULTI_LISTEN */
+    
 #ifdef NO_SERIALIZED_ACCEPT
     /* warn them about the starvation problem if they're using multiple
      * sockets
@@ -4501,6 +4585,19 @@ static void child_main(int child_num_arg)
 #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 (NONBLOCK_WHEN_MULTI_LISTEN)
+                     */
+#ifdef EAGAIN
+                case EAGAIN:
+#endif
+#ifdef EWOULDBLOCK
+#if !defined(EAGAIN) || EAGAIN != EWOULDBLOCK
+                case EWOULDBLOCK:
+#endif
 #endif
                     break;
 #ifdef ENETDOWN
@@ -4591,6 +4688,21 @@ static void child_main(int child_num_arg)
         * socket options, file descriptors, and read/write buffers.
         */
 
+#ifdef NONBLOCK_WHEN_MULTI_LISTEN
+        /* This assumes that on this platform the non-blocking setting of
+         * a listening socket is inherited.  If that isn't the case,
+         * this is wasted effort.
+         */
+        if (ap_listeners != ap_listeners->next) {
+            if (soblock(csd) != 0) {
+                ap_log_error(APLOG_MARK, APLOG_CRIT, NULL,
+                             "couldn't make socket descriptor (%d) blocking again",
+                             csd);
+                continue;
+            }
+        }
+#endif /* NONBLOCK_WHEN_MULTI_LISTEN */
+
        clen = sizeof(sa_server);
        if (getsockname(csd, &sa_server, &clen) < 0) {
            ap_log_error(APLOG_MARK, APLOG_DEBUG, server_conf, 
@@ -6365,15 +6477,22 @@ void worker_main(void)
             if (csd == INVALID_SOCKET) {
                 csd = -1;
             }
-        } while (csd < 0 && h_errno == EINTR);
+        } while (csd < 0 && h_errno == WSAEINTR);
        
         if (csd == INVALID_SOCKET) {
-            if (h_errno != WSAECONNABORTED) {
+            if ((h_errno != WSAECONNABORTED) && (h_errno != WSAEWOULDBLOCK)) {
                 ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
                              "accept: (client socket) failed with errno = %d",h_errno);
             }
         }
         else {
+            u_long one = 0;
+
+            if (soblock(csd) != 0) {
+                ap_log_error(APLOG_MARK, APLOG_ERR, server_conf,
+                             "%d couldn't make socket descriptor (%d) blocking again.", h_errno, csd);
+                continue;
+            }
             add_job(csd);
         }
     }