From 1eb7fd50d7c045c1203f700cb08169308435ae72 Mon Sep 17 00:00:00 2001 From: Alexey Izbyshev Date: Sun, 29 Jan 2023 19:46:51 +0300 Subject: [PATCH 2/2] prevent CNAME/PTR parsing from reading data past the response end Mail-Followup-To: musl@lists.openwall.com 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. --- src/network/dns_parse.c | 4 ++-- src/network/getnameinfo.c | 4 ++-- src/network/lookup.h | 2 +- src/network/lookup_name.c | 4 ++-- 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 #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; -- 2.39.1