about summary refs log tree commit diff
diff options
context:
space:
mode:
authorAlexey Izbyshev <izbyshev@ispras.ru>2023-01-29 19:46:51 +0300
committerRich Felker <dalias@aerifal.cx>2023-02-27 10:03:06 -0500
commit9b132e556774c744f9052581d2d8d0fab417e97c (patch)
treecbb516502c92f69bb6b01c82dbb7c30fed845c56
parent12590c8bbd04ea484cee86812e2258fbdfca0e59 (diff)
downloadmusl-9b132e556774c744f9052581d2d8d0fab417e97c.tar.gz
musl-9b132e556774c744f9052581d2d8d0fab417e97c.tar.xz
musl-9b132e556774c744f9052581d2d8d0fab417e97c.zip
prevent CNAME/PTR parsing from reading data past the response end
DNS parsing callbacks pass the response buffer end instead of the actual
response end to dn_expand, so a malformed DNS response can use message
compression to make dn_expand jump past the response end and attempt to
parse uninitialized parts of that buffer, which might succeed and return
garbage.
-rw-r--r--src/network/dns_parse.c4
-rw-r--r--src/network/getnameinfo.c4
-rw-r--r--src/network/lookup.h2
-rw-r--r--src/network/lookup_name.c4
4 files changed, 7 insertions, 7 deletions
diff --git a/src/network/dns_parse.c b/src/network/dns_parse.c
index 320df60d..7f83e791 100644
--- a/src/network/dns_parse.c
+++ b/src/network/dns_parse.c
@@ -1,7 +1,7 @@
 #include <string.h>
 #include "lookup.h"
 
-int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *), void *ctx)
+int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, const void *, int, const void *, int), void *ctx)
 {
 	int qdcount, ancount;
 	const unsigned char *p;
@@ -26,7 +26,7 @@ int __dns_parse(const unsigned char *r, int rlen, int (*callback)(void *, int, c
 		p += 1 + !!*p;
 		len = p[8]*256 + p[9];
 		if (len+10 > r+rlen-p) return -1;
-		if (callback(ctx, p[1], p+10, len, r) < 0) return -1;
+		if (callback(ctx, p[1], p+10, len, r, rlen) < 0) return -1;
 		p += 10 + len;
 	}
 	return 0;
diff --git a/src/network/getnameinfo.c b/src/network/getnameinfo.c
index 949e1811..080d3c06 100644
--- a/src/network/getnameinfo.c
+++ b/src/network/getnameinfo.c
@@ -108,10 +108,10 @@ static void reverse_services(char *buf, int port, int dgram)
 	__fclose_ca(f);
 }
 
-static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
 {
 	if (rr != RR_PTR) return 0;
-	if (__dn_expand(packet, (const unsigned char *)packet + 512,
+	if (__dn_expand(packet, (const unsigned char *)packet + plen,
 	    data, c, 256) <= 0)
 		*(char *)c = 0;
 	return 0;
diff --git a/src/network/lookup.h b/src/network/lookup.h
index ef662725..54b2f8b5 100644
--- a/src/network/lookup.h
+++ b/src/network/lookup.h
@@ -50,6 +50,6 @@ hidden int __lookup_ipliteral(struct address buf[static 1], const char *name, in
 hidden int __get_resolv_conf(struct resolvconf *, char *, size_t);
 hidden int __res_msend_rc(int, const unsigned char *const *, const int *, unsigned char *const *, int *, int, const struct resolvconf *);
 
-hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *), void *);
+hidden int __dns_parse(const unsigned char *, int, int (*)(void *, int, const void *, int, const void *, int), void *);
 
 #endif
diff --git a/src/network/lookup_name.c b/src/network/lookup_name.c
index 5f6867cb..f268bcda 100644
--- a/src/network/lookup_name.c
+++ b/src/network/lookup_name.c
@@ -111,13 +111,13 @@ struct dpc_ctx {
 
 #define ABUF_SIZE 768
 
-static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet)
+static int dns_parse_callback(void *c, int rr, const void *data, int len, const void *packet, int plen)
 {
 	char tmp[256];
 	int family;
 	struct dpc_ctx *ctx = c;
 	if (rr == RR_CNAME) {
-		if (__dn_expand(packet, (const unsigned char *)packet + ABUF_SIZE,
+		if (__dn_expand(packet, (const unsigned char *)packet + plen,
 		    data, tmp, sizeof tmp) > 0 && is_valid_hostname(tmp))
 			strcpy(ctx->canon, tmp);
 		return 0;