← ALL ADVISORIES

LOW BYTERAY-2026-0239Disclosed

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 bound AnswersNum or DataLength.
  • AnswersNum >= 1 check (line 1282): weak — enforces minimum only, no upper bound.
  • RemainingLength checks (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

  1. A firmware component calls the DnsDxe GeneralLookUp protocol function; the DNS response comes from a DNS server the attacker controls or spoofs.
  2. Set up a DNS server that answers the GeneralLookup query with one or more answer records.
  3. Make the RData AllocateZeroPool at DnsImpl.c:1453 (IPv4) or 1481 (IPv6) fail while the QName allocation before it succeeds, for example with fault injection in a test build.
  4. ParseDnsResponse jumps to ON_EXIT before RRCount++, and the cleanup loop does not free RRList[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.

References