From 70bc729f736639502d2cbfe836f8c60408b6edde Mon Sep 17 00:00:00 2001 From: Ilia Alshanetsky Date: Mon, 24 Aug 2026 16:10:30 -0400 Subject: [PATCH] ext/standard: Bound-check RR parsing in the dns_get_mx() answer loop The answer loop read type, class, ttl, rdlength and weight with raw GETSHORT() after an unvalidated dn_skipname() advance, so a reply whose last record name ends at the end of the received data read up to about 12 bytes past the 64K querybuf stack union, with the weight reaching userland through the $weights array. Guard the fixed-size header fields the way php_parserr() already does; rdata skips stay bounded by the cp < end loop condition. --- NEWS | 2 ++ ext/standard/dns.c | 8 ++++++++ 2 files changed, 10 insertions(+) diff --git a/NEWS b/NEWS index 982945e5ebfc..6fcc446e5ee0 100644 --- a/NEWS +++ b/NEWS @@ -60,6 +60,8 @@ PHP NEWS . Fixed three Windows-only proc_open() defects: an uninitialized PROCESS_INFORMATION, an indeterminate comspec pointer after a failed lookup, and an unchecked CreateFileA() failure. (Ilia Alshanetsky) + . Fixed out-of-bounds read when parsing a malformed MX answer in + dns_get_mx(). (Ilia Alshanetsky) - XSL: . Fixed bug GH-23730 (use-after-free when XSLTProcessor::importStylesheet() diff --git a/ext/standard/dns.c b/ext/standard/dns.c index 64301ed04161..61319565da7b 100644 --- a/ext/standard/dns.c +++ b/ext/standard/dns.c @@ -1120,6 +1120,10 @@ PHP_FUNCTION(dns_get_mx) RETURN_FALSE; } cp += i; + if (cp + 10 > end) { + php_dns_free_handle(handle); + RETURN_FALSE; + } GETSHORT(type, cp); cp += INT16SZ + INT32SZ; GETSHORT(i, cp); @@ -1127,6 +1131,10 @@ PHP_FUNCTION(dns_get_mx) cp += i; continue; } + if (cp + 2 > end) { + php_dns_free_handle(handle); + RETURN_FALSE; + } GETSHORT(weight, cp); if ((i = dn_expand(answer.qb2, end, cp, buf, sizeof(buf)-1)) < 0) { php_dns_free_handle(handle);