From: Witold Kręcicki Date: Thu, 16 Jan 2020 10:52:58 +0000 (+0100) Subject: netmgr: don't send to an inactive (closing) udp socket X-Git-Tag: v9.16.0~60^2~5 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=16908ec3d912f0ca7e01edf95685eb91a52b4f08;p=thirdparty%2Fbind9.git netmgr: don't send to an inactive (closing) udp socket 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. --- diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h index 177adec3c63..f309ab51318 100644 --- a/lib/isc/netmgr/netmgr-int.h +++ b/lib/isc/netmgr/netmgr-int.h @@ -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); /*%< diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 6a66bd5fdbd..7943b1f5baf 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -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) { diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c index 6b79d8e0bcf..0bad9ceaf5d 100644 --- a/lib/isc/netmgr/udp.c +++ b/lib/isc/netmgr/udp.c @@ -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,