]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Gracefully handle uv_read_start() failures
authorOndřej Surý <ondrej@isc.org>
Tue, 14 Jun 2022 07:17:08 +0000 (09:17 +0200)
committerOndřej Surý <ondrej@isc.org>
Tue, 14 Jun 2022 09:55:03 +0000 (11:55 +0200)
Under specific rare timing circumstances the uv_read_start() could
fail with UV_EINVAL when the connection is reset between the connect (or
accept) and the uv_read_start() call on the nmworker loop.  Handle such
situation gracefully by propagating the errors from uv_read_start() into
upper layers, so the socket can be internally closed().

(cherry picked from commit b432d5d3bcccf199141564b6a87d2cdac296ed7e)

lib/isc/netmgr/netmgr-int.h
lib/isc/netmgr/netmgr.c
lib/isc/netmgr/tcp.c
lib/isc/netmgr/tcpdns.c
lib/isc/netmgr/udp.c

index 6cea89839cd63d41c8378c470da7c459d8fba337..218da8810dbc25863a4fa3dac0f44ad542ac3ddb 100644 (file)
@@ -1559,11 +1559,11 @@ isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
 void
 isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
 
-void
+isc_result_t
 isc__nm_start_reading(isc_nmsocket_t *sock);
 void
 isc__nm_stop_reading(isc_nmsocket_t *sock);
-void
+isc_result_t
 isc__nm_process_sock_buffer(isc_nmsocket_t *sock);
 void
 isc__nm_resume_processing(void *arg);
index aa9782c12a8bea9bf90a328930dcd806d58f4d66..4941e60c02546e0de068262eac04d80cbe0756bc 100644 (file)
@@ -2100,34 +2100,39 @@ isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
        worker->recvbuf_inuse = true;
 }
 
-void
+isc_result_t
 isc__nm_start_reading(isc_nmsocket_t *sock) {
+       isc_result_t result = ISC_R_SUCCESS;
        int r;
 
        if (sock->reading) {
-               return;
+               return (ISC_R_SUCCESS);
        }
 
        switch (sock->type) {
        case isc_nm_udpsocket:
                r = uv_udp_recv_start(&sock->uv_handle.udp, isc__nm_alloc_cb,
                                      isc__nm_udp_read_cb);
-               UV_RUNTIME_CHECK(uv_udp_recv_start, r);
                break;
        case isc_nm_tcpsocket:
                r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb,
                                  isc__nm_tcp_read_cb);
-               UV_RUNTIME_CHECK(uv_read_start, r);
                break;
        case isc_nm_tcpdnssocket:
                r = uv_read_start(&sock->uv_handle.stream, isc__nm_alloc_cb,
                                  isc__nm_tcpdns_read_cb);
-               UV_RUNTIME_CHECK(uv_read_start, r);
                break;
        default:
                UNREACHABLE();
        }
-       sock->reading = true;
+
+       if (r != 0) {
+               result = isc__nm_uverr2result(r);
+       } else {
+               sock->reading = true;
+       }
+
+       return (result);
 }
 
 void
@@ -2188,7 +2193,7 @@ processbuffer(isc_nmsocket_t *sock) {
  * limit. In this case we'll be called again by resume_processing()
  * later.
  */
-void
+isc_result_t
 isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
        for (;;) {
                int_fast32_t ah = atomic_load(&sock->ah);
@@ -2199,7 +2204,10 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
                         * Don't reset the timer until we have a
                         * full DNS message.
                         */
-                       isc__nm_start_reading(sock);
+                       result = isc__nm_start_reading(sock);
+                       if (result != ISC_R_SUCCESS) {
+                               return (result);
+                       }
                        /*
                         * Start the timer only if there are no externally used
                         * active handles, there's always one active handle
@@ -2209,11 +2217,11 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
                        if (ah == 1) {
                                isc__nmsocket_timer_start(sock);
                        }
-                       return;
+                       goto done;
                case ISC_R_CANCELED:
                        isc__nmsocket_timer_stop(sock);
                        isc__nm_stop_reading(sock);
-                       return;
+                       goto done;
                case ISC_R_SUCCESS:
                        /*
                         * Stop the timer on the successful message read, this
@@ -2227,13 +2235,15 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
                            ah >= STREAM_CLIENTS_PER_CONN)
                        {
                                isc__nm_stop_reading(sock);
-                               return;
+                               goto done;
                        }
                        break;
                default:
                        UNREACHABLE();
                }
        }
+done:
+       return (ISC_R_SUCCESS);
 }
 
 void
index eaad8da7c657c3a6fb786ab7dd1283c2b52b4699..db97faf1746fd2d816f2464f3389a3306a252e1c 100644 (file)
@@ -768,18 +768,24 @@ isc__nm_async_tcpstartread(isc__networker_t *worker, isc__netievent_t *ev0) {
        isc__netievent_tcpstartread_t *ievent =
                (isc__netievent_tcpstartread_t *)ev0;
        isc_nmsocket_t *sock = ievent->sock;
+       isc_result_t result;
 
        REQUIRE(VALID_NMSOCK(sock));
        REQUIRE(sock->tid == isc_nm_tid());
        UNUSED(worker);
 
        if (isc__nmsocket_closing(sock)) {
+               result = ISC_R_CANCELED;
+       } else {
+               result = isc__nm_start_reading(sock);
+       }
+
+       if (result != ISC_R_SUCCESS) {
                sock->reading = true;
-               isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED);
+               isc__nm_tcp_failed_read_cb(sock, result);
                return;
        }
 
-       isc__nm_start_reading(sock);
        isc__nmsocket_timer_start(sock);
 }
 
index 6f513b49ceba2eb6810c2072a63a3eb0ccd59d68..40e01be6b72c9377258bf3553491e10747e90931 100644 (file)
@@ -735,6 +735,7 @@ isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) {
        isc__netievent_tcpdnsread_t *ievent =
                (isc__netievent_tcpdnsread_t *)ev0;
        isc_nmsocket_t *sock = ievent->sock;
+       isc_result_t result;
 
        UNUSED(worker);
 
@@ -742,12 +743,15 @@ isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) {
        REQUIRE(sock->tid == isc_nm_tid());
 
        if (isc__nmsocket_closing(sock)) {
-               sock->reading = true;
-               isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
-               return;
+               result = ISC_R_CANCELED;
+       } else {
+               result = isc__nm_process_sock_buffer(sock);
        }
 
-       isc__nm_process_sock_buffer(sock);
+       if (result != ISC_R_SUCCESS) {
+               sock->reading = true;
+               isc__nm_failed_read_cb(sock, result, false);
+       }
 }
 
 /*
@@ -839,6 +843,7 @@ isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread,
        isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)stream);
        uint8_t *base = NULL;
        size_t len;
+       isc_result_t result;
 
        REQUIRE(VALID_NMSOCK(sock));
        REQUIRE(sock->tid == isc_nm_tid());
@@ -882,7 +887,10 @@ isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread,
                sock->read_timeout = atomic_load(&sock->mgr->idle);
        }
 
-       isc__nm_process_sock_buffer(sock);
+       result = isc__nm_process_sock_buffer(sock);
+       if (result != ISC_R_SUCCESS) {
+               isc__nm_failed_read_cb(sock, result, true);
+       }
 free:
        if (nread < 0) {
                /*
@@ -1034,7 +1042,12 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
         * prep_destroy()->tcpdns_close_direct().
         */
        isc_nmhandle_attach(handle, &csock->recv_handle);
-       isc__nm_process_sock_buffer(csock);
+       result = isc__nm_process_sock_buffer(csock);
+       if (result != ISC_R_SUCCESS) {
+               isc_nmhandle_detach(&csock->recv_handle);
+               isc_nmhandle_detach(&handle);
+               goto failure;
+       }
 
        /*
         * The initial timer has been set, update the read timeout for the next
index 45e84d49bb290535f31931a13ce5137645024598..6a9acf543ee0746ed270e9e4b1378d51131b6ef6 100644 (file)
@@ -930,6 +930,7 @@ void
 isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) {
        isc__netievent_udpread_t *ievent = (isc__netievent_udpread_t *)ev0;
        isc_nmsocket_t *sock = ievent->sock;
+       isc_result_t result;
 
        UNUSED(worker);
 
@@ -937,12 +938,17 @@ isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) {
        REQUIRE(sock->tid == isc_nm_tid());
 
        if (isc__nmsocket_closing(sock)) {
+               result = ISC_R_CANCELED;
+       } else {
+               result = isc__nm_start_reading(sock);
+       }
+
+       if (result != ISC_R_SUCCESS) {
                sock->reading = true;
-               isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
+               isc__nm_failed_read_cb(sock, result, false);
                return;
        }
 
-       isc__nm_start_reading(sock);
        isc__nmsocket_timer_start(sock);
 }