From: Witold Kręcicki Date: Fri, 17 Jan 2020 13:42:57 +0000 (+0100) Subject: Fix possible race in socket destruction. X-Git-Tag: v9.16.0~60^2 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=fd8788eb94f516d2c6d15ee023c867e938402abf;p=thirdparty%2Fbind9.git Fix possible race in socket destruction. When two threads unreferenced handles coming from one socket while the socket was being destructed we could get a use-after-free: Having handle H1 coming from socket S1, H2 coming from socket S2, S0 being a parent socket to S1 and S2: Thread A Thread B Unref handle H1 Unref handle H2 Remove H1 from S1 active handles Remove H2 from S2 active handles nmsocket_maybe_destroy(S1) nmsocket_maybe_destroy(S2) nmsocket_maybe_destroy(S0) nmsocket_maybe_destroy(S0) LOCK(S0->lock) Go through all children, figure out that we have no more active handles: sum of S0->children[i]->ah == 0 UNLOCK(S0->lock) destroy(S0) LOCK(S0->lock) - but S0 is already gone --- diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c index 7943b1f5baf..d7cf3a36af2 100644 --- a/lib/isc/netmgr/netmgr.c +++ b/lib/isc/netmgr/netmgr.c @@ -1158,7 +1158,7 @@ nmhandle_deactivate(isc_nmsocket_t *sock, isc_nmhandle_t *handle) { void isc_nmhandle_unref(isc_nmhandle_t *handle) { - isc_nmsocket_t *sock = NULL; + isc_nmsocket_t *sock = NULL, *tmp = NULL; REQUIRE(VALID_NMHANDLE(handle)); @@ -1199,8 +1199,14 @@ isc_nmhandle_unref(isc_nmhandle_t *handle) { } } + /* + * Temporarily reference the socket to ensure that it can't + * be deleted by another thread while we're deactivating the + * handle. + */ + isc_nmsocket_attach(sock, &tmp); nmhandle_deactivate(sock, handle); - nmsocket_maybe_destroy(sock); + isc_nmsocket_detach(&tmp); } void *