2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

clean up outerhandle when a tcpdns socket is disconnected

this prevents a crash when some non-netmgr thread, such as a
recursive lookup, times out after the TCP socket is already
disconnected.
This commit is contained in:
Evan Hunt
2020-06-20 15:03:05 -07:00
parent bcbc7e2b10
commit 3704c4fff2
4 changed files with 38 additions and 16 deletions

View File

@@ -98,14 +98,6 @@ struct isc_nmhandle {
isc_nmsocket_t *sock; isc_nmsocket_t *sock;
size_t ah_pos; /* Position in the socket's 'active handles' array */ size_t ah_pos; /* Position in the socket's 'active handles' array */
/*
* The handle is 'inflight' if netmgr is not currently processing
* it in any way - it might mean that e.g. a recursive resolution
* is happening. For an inflight handle we must wait for the
* calling code to finish before we can free it.
*/
atomic_bool inflight;
isc_sockaddr_t peer; isc_sockaddr_t peer;
isc_sockaddr_t local; isc_sockaddr_t local;
isc_nm_opaquecb_t doreset; /* reset extra callback, external */ isc_nm_opaquecb_t doreset; /* reset extra callback, external */
@@ -650,6 +642,12 @@ isc__nmsocket_active(isc_nmsocket_t *sock);
* or, for child sockets, 'sock->parent->active'. * or, for child sockets, 'sock->parent->active'.
*/ */
void
isc__nmsocket_clearcb(isc_nmsocket_t *sock);
/*%<
* Clear the recv and accept callbacks in 'sock'.
*/
void void
isc__nm_async_closecb(isc__networker_t *worker, isc__netievent_t *ev0); isc__nm_async_closecb(isc__networker_t *worker, isc__netievent_t *ev0);
/*%< /*%<

View File

@@ -987,6 +987,16 @@ isc__nmsocket_init(isc_nmsocket_t *sock, isc_nm_t *mgr, isc_nmsocket_type type,
sock->magic = NMSOCK_MAGIC; sock->magic = NMSOCK_MAGIC;
} }
void
isc__nmsocket_clearcb(isc_nmsocket_t *sock) {
REQUIRE(VALID_NMSOCK(sock));
sock->rcb.recv = NULL;
sock->rcbarg = NULL;
sock->accept_cb.accept = NULL;
sock->accept_cbarg = NULL;
}
void void
isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) { isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
isc_nmsocket_t *sock = uv_handle_get_data(handle); isc_nmsocket_t *sock = uv_handle_get_data(handle);

View File

@@ -584,6 +584,7 @@ readtimeout_cb(uv_timer_t *handle) {
if (sock->rcb.recv != NULL) { if (sock->rcb.recv != NULL) {
sock->rcb.recv(sock->tcphandle, ISC_R_TIMEDOUT, NULL, sock->rcb.recv(sock->tcphandle, ISC_R_TIMEDOUT, NULL,
sock->rcbarg); sock->rcbarg);
isc__nmsocket_clearcb(sock);
} }
} }
@@ -682,7 +683,9 @@ isc__nm_tcp_resumeread(isc_nmsocket_t *sock) {
isc__netievent_startread_t *ievent = NULL; isc__netievent_startread_t *ievent = NULL;
REQUIRE(VALID_NMSOCK(sock)); REQUIRE(VALID_NMSOCK(sock));
REQUIRE(sock->rcb.recv != NULL); if (sock->rcb.recv == NULL) {
return (ISC_R_CANCELED);
}
if (!atomic_load(&sock->readpaused)) { if (!atomic_load(&sock->readpaused)) {
return (ISC_R_SUCCESS); return (ISC_R_SUCCESS);
@@ -744,6 +747,7 @@ read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf) {
if (sock->rcb.recv != NULL) { if (sock->rcb.recv != NULL) {
isc__nm_incstats(sock->mgr, sock->statsindex[STATID_RECVFAIL]); isc__nm_incstats(sock->mgr, sock->statsindex[STATID_RECVFAIL]);
sock->rcb.recv(sock->tcphandle, ISC_R_EOF, NULL, sock->rcbarg); sock->rcb.recv(sock->tcphandle, ISC_R_EOF, NULL, sock->rcbarg);
isc__nmsocket_clearcb(sock);
} }
/* /*
@@ -1080,6 +1084,7 @@ isc__nm_tcp_shutdown(isc_nmsocket_t *sock) {
{ {
sock->rcb.recv(sock->tcphandle, ISC_R_CANCELED, NULL, sock->rcb.recv(sock->tcphandle, ISC_R_CANCELED, NULL,
sock->rcbarg); sock->rcbarg);
isc__nmsocket_clearcb(sock);
} }
} }
@@ -1092,5 +1097,6 @@ isc__nm_tcp_cancelread(isc_nmsocket_t *sock) {
{ {
sock->rcb.recv(sock->tcphandle, ISC_R_CANCELED, NULL, sock->rcb.recv(sock->tcphandle, ISC_R_CANCELED, NULL,
sock->rcbarg); sock->rcbarg);
isc__nmsocket_clearcb(sock);
} }
} }

View File

@@ -231,6 +231,11 @@ dnslisten_readcb(isc_nmhandle_t *handle, isc_result_t eresult,
if (dnssock->self != NULL) { if (dnssock->self != NULL) {
isc__nmsocket_detach(&dnssock->self); isc__nmsocket_detach(&dnssock->self);
} }
isc__nmsocket_clearcb(dnssock);
if (dnssock->outerhandle != NULL) {
isc_nmhandle_unref(dnssock->outerhandle);
dnssock->outerhandle = NULL;
}
return; return;
} }
@@ -340,8 +345,7 @@ isc__nm_tcpdns_stoplistening(isc_nmsocket_t *sock) {
atomic_store(&sock->listening, false); atomic_store(&sock->listening, false);
atomic_store(&sock->closed, true); atomic_store(&sock->closed, true);
sock->rcb.recv = NULL; isc__nmsocket_clearcb(sock);
sock->rcbarg = NULL;
if (sock->outer != NULL) { if (sock->outer != NULL) {
isc__nm_tcp_stoplistening(sock->outer); isc__nm_tcp_stoplistening(sock->outer);
@@ -431,7 +435,11 @@ resume_processing(void *arg) {
} }
isc_nmhandle_unref(handle); isc_nmhandle_unref(handle);
} else if (sock->outerhandle != NULL) { } else if (sock->outerhandle != NULL) {
isc_nm_resumeread(sock->outerhandle->sock); result = isc_nm_resumeread(sock->outerhandle->sock);
if (result != ISC_R_SUCCESS) {
isc_nmhandle_unref(sock->outerhandle);
sock->outerhandle = NULL;
}
} }
return; return;
@@ -524,7 +532,9 @@ tcpdns_close_direct(isc_nmsocket_t *sock) {
REQUIRE(sock->tid == isc_nm_tid()); REQUIRE(sock->tid == isc_nm_tid());
/* We don't need atomics here, it's all in single network thread */ /* We don't need atomics here, it's all in single network thread */
if (sock->timer_initialized) { if (sock->self != NULL) {
isc__nmsocket_detach(&sock->self);
} else if (sock->timer_initialized) {
/* /*
* We need to fire the timer callback to clean it up, * We need to fire the timer callback to clean it up,
* it will then call us again (via detach) so that we * it will then call us again (via detach) so that we
@@ -533,15 +543,13 @@ tcpdns_close_direct(isc_nmsocket_t *sock) {
sock->timer_initialized = false; sock->timer_initialized = false;
uv_timer_stop(&sock->timer); uv_timer_stop(&sock->timer);
uv_close((uv_handle_t *)&sock->timer, timer_close_cb); uv_close((uv_handle_t *)&sock->timer, timer_close_cb);
} else if (sock->self != NULL) {
isc__nmsocket_detach(&sock->self);
} else { } else {
/* /*
* At this point we're certain that there are no external * At this point we're certain that there are no external
* references, we can close everything. * references, we can close everything.
*/ */
if (sock->outerhandle != NULL) { if (sock->outerhandle != NULL) {
sock->outerhandle->sock->rcb.recv = NULL; isc__nmsocket_clearcb(sock->outerhandle->sock);
isc_nmhandle_unref(sock->outerhandle); isc_nmhandle_unref(sock->outerhandle);
sock->outerhandle = NULL; sock->outerhandle = NULL;
} }