]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
resolved: fix potential use-after-free when freeing DNS extra stub listeners
authorLuca Boccassi <luca.boccassi@gmail.com>
Wed, 24 Jun 2026 12:43:14 +0000 (13:43 +0100)
committerLuca Boccassi <luca.boccassi@gmail.com>
Wed, 24 Jun 2026 17:02:12 +0000 (18:02 +0100)
dns_stub_listener_extra_free() frees the listener while DnsQuery and
DnsStream objects still keep pointers to it. On a reload the extra
listeners are freed before dns_stream_disconnect_all() and
dns_query_free() run, and dns_query_free() then dereferences those
pointers.

src/resolve/resolved-dns-stub.c

index 91ea30e0e2f4c81d1f42f6f97592c67f000e8674..4a4c3f001579bc0982b5f08d508da8e0f61c057a 100644 (file)
@@ -102,6 +102,19 @@ DnsStubListenerExtra *dns_stub_listener_extra_free(DnsStubListenerExtra *p) {
         p->udp_event_source = sd_event_source_disable_unref(p->udp_event_source);
         p->tcp_event_source = sd_event_source_disable_unref(p->tcp_event_source);
 
+        assert(p->manager);
+
+        /* Detach the raw back-pointers that DnsStream and DnsQuery objects keep to this listener before we
+         * free it. Otherwise a later dns_stream_complete()/dns_query_free() during the same reload would
+         * dereference the freed slab: dns_query_free() reads q->stub_listener_extra->queries_by_packet. */
+        LIST_FOREACH(streams, s, p->manager->dns_streams)
+                if (s->stub_listener_extra == p)
+                        s->stub_listener_extra = NULL;
+
+        LIST_FOREACH(queries, q, p->manager->dns_queries)
+                if (q->stub_listener_extra == p)
+                        q->stub_listener_extra = NULL;
+
         hashmap_free(p->queries_by_packet);
 
         return mfree(p);