EDK II - Memory Leak in ParseDnsResponse
ParseDnsResponse processes attacker-controlled DNS answer records in a loop bounded by DnsHeader->AnswersNum from the wire.
- Advisory
- BYTERAY-2026-0239
- CWE
- CWE-401
- Vendor
- TianoCore
- Product
- EDK II
- Reported
- 2026-06-25
- Disclosure
- 2026-10-29
- Affected
- EDK II at commit 70741a15d9a714323a5598eac47727e60507e22f (master, 2026-06-21); affected code in NetworkPkg/DnsDxe/DnsImpl.c.
- Credit
- Argus-Systems
Executive Summary
ParseDnsResponse processes attacker-controlled DNS answer records in a loop bounded by DnsHeader->AnswersNum from the wire. For each record it allocates QName (line 1442 IPv4 / 1470 IPv6) then RData (line 1453 / 1481). The per-iteration counter RRCount is only incremented after both allocations succeed (line 1461 / 1489). When the RData allocation fails, control jumps to ON_EXIT, whose cleanup loop (lines 1704–1713 IPv4, 1736–1745 IPv6) iterates only indices 0..RRCount-1. Because RRCount was not incremented before the failure, the QName buffer stored at RRList[RRCount] is never freed, and the cleanup then frees RRList itself, losing the pointer. The response is parsed from the network via DnsOnPacketReceived on the GeneralLookup path, but the leak only happens when the RData pool allocation fails, which the sender of the response cannot force.
This advisory is one of a set reported to VulnCheck on 2026-06-25 for coordinated disclosure to the EDK II maintainers. After several follow-ups over the following months no response was received. 126 days after the initial report, ByteRay is publishing the findings in good faith so that affected integrators can assess and remediate them. All findings were identified against EDK II commit 70741a15d9a714323a5598eac47727e60507e22f (master, 2026-06-21).
Affected Products and Versions
- Vendor: TianoCore
- Product: EDK II (
NetworkPkg) - Affected commit:
70741a15d9a714323a5598eac47727e60507e22f(master, 2026-06-21). The code is present on that commit and later revisions that have not changed it. - Location:
NetworkPkg/DnsDxe/DnsImpl.c:1453 - Function:
ParseDnsResponse - Category:
Memory Leak (CWE-401)
Technical Details
Controllability: EXTERNAL_UNTRUSTED — confidence: high
Data Flow
A UDP DNS response packet is received by DnsOnPacketReceived (line 1804–1838), which extracts the raw bytes via NetbufGetByte and passes them to ParseDnsResponse. The function reads DnsHeader->AnswersNum directly from the wire (line 1392, loop bound) and AnswerSection->DataLength via NTOHS (line 1419, allocation size). The only validation is IsValidDnsResponse (partial — matches the response to a pending query but does not bound AnswersNum) and a RemainingLength check (partial — ensures DataLength fits within the packet but allows large values). For each answer record, QName is allocated (line 1442) and stored in Dns4RR[RRCount].QName before RRCount is incremented. When the subsequent RData allocation (line 1453) fails, control jumps to ON_EXIT (line 1456) without incrementing RRCount. The cleanup loop (lines 1704–1713) iterates only 0..RRCount-1, orphaning RRList[RRCount].QName. DataLength is a UINT16 and line 1424 rejects it when it exceeds the remaining packet length, so the RData request is at most the size of one received datagram; it fails only when the pool is already exhausted.
Affected Callers
DnsOnPacketReceived
Sanitization / Security Controls
IsValidDnsResponse(line 1246): validates the response matches an outstanding query (Identification/Type/Class) — partial; does not boundAnswersNumorDataLength.AnswersNum >= 1check (line 1282): weak — enforces minimum only, no upper bound.RemainingLengthchecks (lines 1396, 1424): partial — bounds packet parsing but allows large allocations up to packet size.
Reachability and Preconditions
Attacker position and trust level for this issue are stated in the Controllability line and Data Flow above, and the concrete trigger is in Reproduction below.
Exploitability: Low
Realism: Low
Reproduction
- A firmware component calls the DnsDxe
GeneralLookUpprotocol function; the DNS response comes from a DNS server the attacker controls or spoofs. - Set up a DNS server that answers the GeneralLookup query with one or more answer records.
- Make the
RDataAllocateZeroPoolatDnsImpl.c:1453(IPv4) or1481(IPv6) fail while theQNameallocation before it succeeds, for example with fault injection in a test build. ParseDnsResponsejumps toON_EXITbeforeRRCount++, and the cleanup loop does not freeRRList[RRCount].QName.
Impact
Each failed RData allocation leaks one QName buffer of AsciiStrLen (QueryName) + 1 bytes. This only happens while the UEFI pool is already out of memory, so the leak adds a few bytes to an existing out-of-memory condition and does not by itself cause a denial of service.
Remediation and Mitigation
As of commit 70741a15d9a714323a5598eac47727e60507e22f this issue is unfixed upstream and no CVE has been assigned. Validate the attacker-controlled value described above before it is used; the specific missing control is identified under Technical Details. The specific control that is absent or ineffective is identified in the Sanitization / Security Controls list under Technical Details.
Timeline
- 2026-06-25 - Reported to VulnCheck for coordinated disclosure to the TianoCore / EDK II security team.
- 2026-07 to 2026-10 - Several follow-ups sent; no response received.
- 2026-10-29 - Public disclosure in good faith, 126 days after the initial report.
Credits
Discovered and reported by Argus-Systems.