]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix possible race in socket destruction.
authorWitold Kręcicki <wpk@isc.org>
Fri, 17 Jan 2020 13:42:57 +0000 (14:42 +0100)
committerWitold Kręcicki <wpk@isc.org>
Mon, 20 Jan 2020 21:28:36 +0000 (22:28 +0100)
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

lib/isc/netmgr/netmgr.c

index 7943b1f5baf5f61783fe44f2fa8eabdb8cc02813..d7cf3a36af239d7aafc9f8a71d63e18342068c9e 100644 (file)
@@ -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 *