From e9714fa4dfd91242e9eddaa79ea93e5466f2c790 Mon Sep 17 00:00:00 2001 From: Vladimir Dubrovin <3proxy@3proxy.ru> Date: Fri, 30 Oct 2026 12:42:01 +0300 Subject: [PATCH] resolve: the PTR answer of dnsname walked inside its record data The label walk of a DNS PTR answer ran to the end of the whole message, not to the end of the record's data, and took a compression pointer for a label length, so it could write past the end of the answer buffer on the stack. An answer of 3841 bytes or more reached past the buffer itself. A record that ended exactly at the end of the message was also read one byte past it. The walk now stops at the end of the record's data, a name that does not end there, or one that is compressed or empty is not accepted, and the answer loop reads nothing past the message. --- src/resolve.c | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/resolve.c b/src/resolve.c index 5b9da88..c7991e6 100644 --- a/src/resolve.c +++ b/src/resolve.c @@ -167,6 +167,7 @@ uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_ k += 4; if(na > 255) na = 255; /* somebody is very evil */ for (j = 0; j < na; j++) { /* now there should be answers */ + if(k >= len) break; while(buf[k] < 192 && buf[k] !=0 && (k+buf[k]+14) < len) k+= (buf[k] + 1); if(!buf[k]) k--; if((k+(af == AF_INET6?28:16)) > len) { @@ -195,15 +196,17 @@ uint32_t udpresolve(int af, unsigned char * name, unsigned char * value, uint32_ k+= (12 + flen); continue; /* we need A PTR */ } - for (s2 = buf + k + 12; s2 < (buf + k + 12 + len) && *s2; ){ - s1 = s2 + ((unsigned)*s2) + 1; + s1 = buf + k + 12 + flen; /* the end of this record's data, inside the answer */ + for (s2 = buf + k + 12; s2 < s1 && *s2 && *s2 < 64; ){ + unsigned char *next = s2 + ((unsigned)*s2) + 1; *s2 = '.'; - s2 = s1; + s2 = next; } - *s2 = 0; + if(s2 >= s1 || *s2 || s2 == buf + k + 12) + break; /* the name runs past its data, is compressed or empty */ if(param->username)free(param->username); param->username = (unsigned char *)strdup ((char *)buf + k + 13); - + return udpresolve(af,param->username, value, NULL, NULL, 2); } }