From 1f2d2611ee23f0b9200dbea8a7b65fa9f3b86e3f Mon Sep 17 00:00:00 2001 From: Aram Sargsyan Date: Tue, 12 Apr 2022 13:00:45 +0000 Subject: [PATCH] Fix dig +nssearch race between recv_done() and send_done() The `send_done()` callback needs to access query's `link.next` pointer when running in `+nssearch` mode, even if the query is already canceled or serviced, which can happen when `recv_done()` happens to be called earlier than `send_done()`. Keep the next query's pointer before unlinking the query from the lookup's queries list in `clear_query()` so that `send_done()` can use it even if the query is cleared. Conflict: NA Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/1f2d2611ee23f0b9200dbea8a7b65fa9f3b86e3f --- bin/dig/dighost.c | 8 ++++++-- bin/dig/include/dig/dig.h | 1 + 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/bin/dig/dighost.c b/bin/dig/dighost.c index 27af3c80f1..e0ba9c2aae 100644 --- a/bin/dig/dighost.c +++ b/bin/dig/dighost.c @@ -1591,6 +1591,7 @@ clear_query(dig_query_t *query) { } if (ISC_LINK_LINKED(query, link)) { + query->saved_next = ISC_LIST_NEXT(query, link); ISC_LIST_UNLINK(lookup->q, query, link); } if (ISC_LINK_LINKED(query, clink)) { @@ -1609,6 +1610,7 @@ clear_query(dig_query_t *query) { isc_buffer_invalidate(&query->lengthbuf); if (query->waiting_senddone) { + debug("waiting senddone, delay freeing query"); query->pending_free = true; } else { query->magic = 0; @@ -2583,6 +2585,7 @@ setup_lookup(dig_lookup_t *lookup) { ISC_LINK_INIT(query, clink); ISC_LINK_INIT(query, link); + query->saved_next = NULL; query->magic = DIG_QUERY_MAGIC; @@ -2617,10 +2620,11 @@ send_done(isc_task_t *_task, isc_event_t *event) { query->waiting_senddone = false; l = query->lookup; - if (!query->pending_free && l->ns_search_only && !l->trace_root && + if (l == current_lookup && l->ns_search_only && !l->trace_root && !l->tcp_mode) { debug("sending next, since searching"); - next = ISC_LIST_NEXT(query, link); + next = query->pending_free ? query->saved_next + : ISC_LIST_NEXT(query, link); if (next != NULL) { send_udp(next); } diff --git a/bin/dig/include/dig/dig.h b/bin/dig/include/dig/dig.h index 79a868d1ef..9683e39892 100644 --- a/bin/dig/include/dig/dig.h +++ b/bin/dig/include/dig/dig.h @@ -183,6 +183,7 @@ struct dig_query { isc_socket_t *sock; ISC_LINK(dig_query_t) link; ISC_LINK(dig_query_t) clink; + dig_query_t *saved_next; isc_sockaddr_t sockaddr; isc_time_t time_sent; isc_time_t time_recv; -- 2.23.0