]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
2504. [bug] Address race condition in the socket code. [RT #18899]
authorMark Andrews <marka@isc.org>
Wed, 3 Dec 2008 02:03:47 +0000 (02:03 +0000)
committerMark Andrews <marka@isc.org>
Wed, 3 Dec 2008 02:03:47 +0000 (02:03 +0000)
CHANGES
lib/isc/unix/socket.c

diff --git a/CHANGES b/CHANGES
index 7890b3f858f0ecac87c36c76163e19f7f05514bc..5135511a8e3e8496d65ce8488d9bb27a21d68cf8 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+2504.  [bug]           Address race condition in the socket code. [RT #18899]
+
 2503.  [port]          linux: improve compatibility with Linux Standard
                        Base. [RT #18793]
 
index de2f9ce11e224bcf6cff6edf64463d87ee0c3e0b..9475c7eeb4491ac6631906262738eabd64fc5704 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: socket.c,v 1.309 2008/12/01 00:15:37 marka Exp $ */
+/* $Id: socket.c,v 1.310 2008/12/03 02:03:47 marka Exp $ */
 
 /*! \file */
 
@@ -2360,18 +2360,15 @@ isc_socket_detach(isc_socket_t **socketp) {
 isc_result_t
 isc_socket_close(isc_socket_t *sock) {
        int fd;
+       isc_socketmgr_t *manager;
+       isc_sockettype_t type;
 
        REQUIRE(VALID_SOCKET(sock));
 
        LOCK(&sock->lock);
+
        REQUIRE(sock->references == 1);
        REQUIRE(sock->type != isc_sockettype_fdwatch);
-       UNLOCK(&sock->lock);
-       /*
-        * We don't need to retain the lock hereafter, since no one else has
-        * this socket.
-        */
-
        REQUIRE(sock->fd >= 0 && sock->fd < (int)sock->manager->maxsocks);
 
        INSIST(!sock->connecting);
@@ -2383,6 +2380,8 @@ isc_socket_close(isc_socket_t *sock) {
        INSIST(ISC_LIST_EMPTY(sock->accept_list));
        INSIST(sock->connect_ev == NULL);
 
+       manager = sock->manager;
+       type = sock->type;
        fd = sock->fd;
        sock->fd = -1;
        sock->listener = 0;
@@ -2390,8 +2389,9 @@ isc_socket_close(isc_socket_t *sock) {
        sock->connecting = 0;
        sock->bound = 0;
        isc_sockaddr_any(&sock->peer_address);
+       UNLOCK(&sock->lock);
 
-       closesocket(sock->manager, sock->type, fd);
+       closesocket(manager, type, fd);
 
        return (ISC_R_SUCCESS);
 }
@@ -3028,6 +3028,7 @@ process_fd(isc_socketmgr_t *manager, int fd, isc_boolean_t readable,
 {
        isc_socket_t *sock;
        isc_boolean_t unlock_sock;
+       isc_boolean_t unwatch_read = ISC_FALSE, unwatch_write = ISC_FALSE;
        int lockid = FDLOCK_ID(fd);
 
        /*
@@ -3043,28 +3044,27 @@ process_fd(isc_socketmgr_t *manager, int fd, isc_boolean_t readable,
        }
 
        sock = manager->fds[fd];
-       UNLOCK(&manager->fdlock[lockid]);
        unlock_sock = ISC_FALSE;
        if (readable) {
                if (sock == NULL) {
-                       (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+                       unwatch_read = ISC_TRUE;
                        goto check_write;
                }
                unlock_sock = ISC_TRUE;
-               LOCK(&sock->lock);
+               LOCK(&sock->lock);              /* XXXMPA */
                if (!SOCK_DEAD(sock)) {
                        if (sock->listener)
                                dispatch_accept(sock);
                        else
                                dispatch_recv(sock);
                }
-               (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+               unwatch_read = ISC_TRUE;
        }
 check_write:
        if (writeable) {
                if (sock == NULL) {
-                       (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
-                       return;
+                       unwatch_write = ISC_TRUE;
+                       goto unlock_fd;
                }
                if (!unlock_sock) {
                        unlock_sock = ISC_TRUE;
@@ -3076,10 +3076,18 @@ check_write:
                        else
                                dispatch_send(sock);
                }
-               (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+               unwatch_write = ISC_TRUE;
        }
        if (unlock_sock)
                UNLOCK(&sock->lock);
+
+ unlock_fd:
+       UNLOCK(&manager->fdlock[lockid]);
+       if (unwatch_read)
+               (void)unwatch_fd(manager, fd, SELECT_POKE_READ);
+       if (unwatch_write)
+               (void)unwatch_fd(manager, fd, SELECT_POKE_WRITE);
+
 }
 
 #ifdef USE_KQUEUE