From 2451b1a9c47153d019e433d490b296521035375b Mon Sep 17 00:00:00 2001 From: Armaan Sandhu Date: Tue, 1 Sep 2026 15:00:08 -0400 Subject: [PATCH] resolve: fix use-after-free of the service browser in mDNS maintenance mdns_maintenance_query_complete() takes a reference on query->dnsservice_request and never drops it, so every successful mDNS maintenance query leaks one reference to the discovered service. The leak alone would be benign, but the service owns the one-shot event source that drives its maintenance schedule, and it only borrows a plain pointer to its service browser. Once the extra reference is outstanding, dns_service_browser_free() -> dns_remove_service() only drops the list's reference, so dns_service_free() never runs, the maintenance timer is never disabled, and the service outlives the browser it points at. The next time the timer fires, mdns_maintenance_query() dereferences the freed DnsServiceBrowser to reach the manager's event loop and to issue the query. Reaching it only takes a browse subscription whose record lives long enough for one maintenance query to be answered, followed by the subscription going away. Make the reference a _cleanup_ one, the way the sibling mdns_browse_service_query_complete() below already handles the reference it takes on the service browser. --- src/resolve/resolved-dns-browse-services.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/resolve/resolved-dns-browse-services.c b/src/resolve/resolved-dns-browse-services.c index c25180d99b..ca9b54075f 100644 --- a/src/resolve/resolved-dns-browse-services.c +++ b/src/resolve/resolved-dns-browse-services.c @@ -79,9 +79,9 @@ static usec_t mdns_maintenance_jitter(uint32_t ttl) { } static void mdns_maintenance_query_complete(DnsQuery *q) { + _cleanup_(dnssd_discovered_service_unrefp) DnssdDiscoveredService *service = NULL; _cleanup_(dns_service_browser_unrefp) DnsServiceBrowser *sb = NULL; _cleanup_(dns_query_freep) DnsQuery *query = q; - DnssdDiscoveredService *service = NULL; int r; assert(query);