[glibc/release/2.43/master] resolv: Fix buffer overreads in ns_sprintrrf (CVE-2026-6238)

Aurelien Jarno via Glibc-cvs <[email protected]> Wed, 1 Jul 2026 21:37:51 +0000 (GMT)
Newsgroups gmane.comp.lib.glibc.cvs
Message-ID <[email protected]>
https://sourceware.org/git/gitweb.cgi?p=glibc.git;h=3a418da6a3938756763980541e440dbdd46900fb

commit 3a418da6a3938756763980541e440dbdd46900fb
Author: Florian Weimer <[email protected]>
Date:   Fri Jun 19 18:22:20 2026 +0200

    resolv: Fix buffer overreads in ns_sprintrrf (CVE-2026-6238)
    
    Check that the RDATA payload does not require more than RDATALEN
    bytes while processing it.  The fixes cover A6, LOC records.
    (CERT, TKEY, TSIG were fixed before, by switching to the generic
    formatter.)
    
    The vulnerable LOC record handling was first introduced before
    glibc 2.0, in commit ee188d555b8c32ad9704a7440cab400af967292f.
    
    CERT, TSIG, TKEY handling came with commit
    b43b13ac2544b11f35be301d1589b51a8473e32b, released with glibc 2.2.
    
    A6 record handling was introduced in commit
    91633816430e7ec5a19fe3ff510a7c4822a9557e ("* resolv/ns_print.c
    (ns_sprintrrf): Handle ns_t_a6 and ns_t_opt."), which went into glibc
    2.7.
    
    This fixes bug 34069.
    
    Reviewed-by: Carlos O'Donell <[email protected]>
    Reviewed-by: Adhemerval Zanella <[email protected]>
    (cherry picked from commit a7b60d23bbb56eaef59f4962e4140062e552600a)

Diff:
---
 resolv/ns_print.c | 10 ++++++----
 1 file changed, 6 insertions(+), 4 deletions(-)

diff --git a/resolv/ns_print.c b/resolv/ns_print.c
index ab68bf2cb7..f9dd086804 100644
--- a/resolv/ns_print.c
+++ b/resolv/ns_print.c
@@ -345,7 +345,8 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
 	case ns_t_loc: {
 		char t[255];
 
-		/* XXX protocol format checking? */
+		if (rdlen != 16)
+		  goto formerr;
 		(void) loc_ntoa(rdata, t);
 		T(addstr(t, strlen(t), &buf, &buflen));
 		break;
@@ -479,13 +480,14 @@ ns_sprintrrf(const u_char *msg, size_t msglen,
 
 		/* address suffix: provided only when prefix len != 128 */
 		if (pbit < 128) {
-			if (rdata + pbyte >= edata) goto formerr;
+			unsigned int bytelen = sizeof(a) - pbyte;
+			if (edata - rdata < bytelen) goto formerr;
 			memset(&a, 0, sizeof(a));
-			memcpy(&a.s6_addr[pbyte], rdata, sizeof(a) - pbyte);
+			memcpy(&a.s6_addr[pbyte], rdata, bytelen);
 			if (inet_ntop (AF_INET6, &a, buf, buflen) == NULL)
 			  return -1;
 			addlen(strlen(buf), &buf, &buflen);
-			rdata += sizeof(a) - pbyte;
+			rdata += bytelen;
 		}
 
 		/* prefix name: provided only when prefix len > 0 */