From 02d000c74780dccff900769bd449cf3818ac2b90 Mon Sep 17 00:00:00 2001 From: Jonathan Hui Date: Wed, 6 May 2026 12:32:11 -0700 Subject: [PATCH] [dns-client] fix double-free of mSavedResponse on duplicate response (#13060) Fix a double-free of `mSavedResponse` in `Dns::Client` when processing duplicate DNS responses matching an active query. When an SRV/TXT query needs to resolve a host address (AAAA), the DNS client allocates a chained `newQuery` to handle it. If duplicate responses are processed before the query chain is finalized, they trigger multiple AAAA resolution allocations for the same parent query. Because the new query inherits `mSavedResponse` from the parent query's `QueryInfo`, multiple chained queries end up aliasing/sharing the same cloned `mSavedResponse` message. During finalization, `FreeQuery` walks the chain and frees `mSavedResponse` for each query, leading to a double-free of the shared `Message` and free-list/heap corruption. This commit resolves the issue by: 1. Rejecting duplicate responses early in `ParseResponse` if a response has already been received and saved for the query (`info.mSavedResponse != nullptr`), returning `kErrorDrop`. 2. Initializing the `mSavedResponse` field of the `QueryInfo` struct to `nullptr` before allocating the host resolution query (`newQuery`) to prevent it from inheriting a potentially non-null saved response from its parent. --- src/core/net/dns_client.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/core/net/dns_client.cpp b/src/core/net/dns_client.cpp index 9260ea0e5..4f7634ea7 100644 --- a/src/core/net/dns_client.cpp +++ b/src/core/net/dns_client.cpp @@ -1497,6 +1497,7 @@ Error Client::ParseResponse(const Message &aResponseMessage, Query *&aQuery, Err VerifyOrExit(aQuery != nullptr, error = kErrorNotFound); info.ReadFrom(*aQuery); + VerifyOrExit(info.mSavedResponse == nullptr, error = kErrorDrop); queryName.SetFromMessage(*aQuery, kNameOffsetInQuery); @@ -1872,6 +1873,7 @@ void Client::ResolveHostAddressIfNeeded(Query &aQuery, const Message &aResponseM info.mMessageId = 0; info.mTransmissionCount = 0; info.mMainQuery = &FindMainQuery(aQuery); + info.mSavedResponse = nullptr; SuccessOrExit(AllocateQuery(info, nullptr, hostName, newQuery)); IgnoreError(SendQuery(*newQuery, info, /* aUpdateTimer */ true));