]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix dig +nssearch race between recv_done() and send_done()
authorAram Sargsyan <aram@isc.org>
Tue, 12 Apr 2022 13:00:45 +0000 (13:00 +0000)
committerAram Sargsyan <aram@isc.org>
Fri, 29 Apr 2022 09:09:39 +0000 (09:09 +0000)
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.

bin/dig/dighost.c
bin/dig/include/dig/dig.h

index 27af3c80f1b28a855ea3901658138dc2d5d40734..e0ba9c2aae7345af410eced1461f80c3174a48f5 100644 (file)
@@ -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);
                }
index 79a868d1ef31615ebb27938d1cb1963c3f0a350e..9683e398925df5d6caed61363f244b98d4295e5c 100644 (file)
@@ -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;