]> 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:33:23 +0000 (02:33 +0000)
committerMark Andrews <marka@isc.org>
Wed, 3 Dec 2008 02:33:23 +0000 (02:33 +0000)
CHANGES
lib/isc/unix/socket.c

diff --git a/CHANGES b/CHANGES
index f5e4266afa742c680f4e94a0f1ffd22e8ce7f9d0..391dba0d624a1e28c74764f5835ee277cfc4f02e 100644 (file)
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,4 @@
+2504.  [bug]           Address race condition in the socket code. [RT #18899]
 
        --- 9.5.1rc1 released ---
 
index e00fa7cb5178f4282e11ba81b9e39f9bdb97aee5..d76bb798bb6e468094ee6b513433d649c356e40e 100644 (file)
@@ -15,7 +15,7 @@
  * PERFORMANCE OF THIS SOFTWARE.
  */
 
-/* $Id: socket.c,v 1.275.10.32 2008/11/20 00:06:01 jinmei Exp $ */
+/* $Id: socket.c,v 1.275.10.32.2.1 2008/12/03 02:33:23 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,11 +3044,10 @@ 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;
@@ -3058,13 +3058,13 @@ process_fd(isc_socketmgr_t *manager, int fd, isc_boolean_t readable,
                        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