]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
netmgr: don't send to an inactive (closing) udp socket
authorWitold Kręcicki <wpk@isc.org>
Thu, 16 Jan 2020 10:52:58 +0000 (11:52 +0100)
committerWitold Kręcicki <wpk@isc.org>
Mon, 20 Jan 2020 21:28:36 +0000 (22:28 +0100)
We had a race in which n UDP socket could have been already closing
by libuv but we still sent data to it. Mark socket as not-active
when stopping listening and verify that socket is not active when
trying to send data to it.

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

index 177adec3c6330ad79424e23a8c15c50bff87dcf5..f309ab5131827473fae41b7dba758d30cabf9452 100644 (file)
@@ -603,6 +603,13 @@ isc__nmsocket_prep_destroy(isc_nmsocket_t *sock);
  * if there are no remaining references or active handles.
  */
 
+bool
+isc__nmsocket_active(isc_nmsocket_t *sock);
+/*%<
+ * Check is socket 'sock' is active - by checking either sock->active or
+ * sock->parent->active;
+ */
+
 void
 isc__nm_async_closecb(isc__networker_t *worker, isc__netievent_t *ev0);
 /*%<
index 6a66bd5fdbd8fe9ca340d468243dde489e182aaf..7943b1f5baf5f61783fe44f2fa8eabdb8cc02813 100644 (file)
@@ -681,7 +681,7 @@ isc__nm_enqueue_ievent(isc__networker_t *worker, isc__netievent_t *event) {
        uv_async_send(&worker->async);
 }
 
-static bool
+bool
 isc__nmsocket_active(isc_nmsocket_t *sock) {
        REQUIRE(VALID_NMSOCK(sock));
        if (sock->parent != NULL) {
index 6b79d8e0bcfc7d9d80d2736c32dd4817cec26901..0bad9ceaf5d6fbf374370622f7d2b8c925fa2e0c 100644 (file)
@@ -179,14 +179,18 @@ stop_udp_child(isc_nmsocket_t *sock) {
 
 static void
 stoplistening(isc_nmsocket_t *sock) {
+       INSIST(sock->type == isc_nm_udplistener);
        /*
         * Socket is already closing; there's nothing to do.
         */
-       if (uv_is_closing((uv_handle_t *) &sock->uv_handle.udp)) {
+       if (!isc__nmsocket_active(sock)) {
                return;
        }
-
-       INSIST(sock->type == isc_nm_udplistener);
+       /*
+        * Mark it inactive now so that all sends will be ignored
+        * and we won't try to stop listening again.
+        */
+       atomic_store(&sock->active, false);
 
        for (int i = 0; i < sock->nchildren; i++) {
                isc__netievent_udpstop_t *event = NULL;
@@ -375,6 +379,11 @@ isc__nm_udp_send(isc_nmhandle_t *handle, isc_region_t *region,
                return (ISC_R_UNEXPECTED);
        }
 
+       if (!isc__nmsocket_active(sock)) {
+               isc_nmhandle_unref(handle);
+               return (ISC_R_CANCELED);
+       }
+
        if (isc__nm_in_netthread()) {
                ntid = isc_nm_tid();
        } else {
@@ -425,7 +434,7 @@ isc__nm_async_udpsend(isc__networker_t *worker, isc__netievent_t *ev0) {
 
        REQUIRE(worker->id == ievent->sock->tid);
 
-       if (atomic_load(&ievent->sock->active)) {
+       if (isc__nmsocket_active(ievent->sock)) {
                udp_send_direct(ievent->sock, ievent->req, &ievent->peer);
        } else {
                ievent->req->cb.send(ievent->req->handle,