From 20435438945f0a4fb5f1203e697d145afc7072d6 Mon Sep 17 00:00:00 2001 From: Vsevolod Stakhov Date: Thu, 17 Jun 2021 11:38:11 +0100 Subject: [PATCH] [Fix] Check remain before processing TXT records --- contrib/librdns/parse.c | 94 ++++++++++++++++++++++++----------------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/contrib/librdns/parse.c b/contrib/librdns/parse.c index a1b25e2ff..fbf9d3e14 100644 --- a/contrib/librdns/parse.c +++ b/contrib/librdns/parse.c @@ -263,7 +263,8 @@ rdns_parse_rr (struct rdns_resolver *resolver, return -1; } if (*remain < (int)sizeof (uint16_t) * 6) { - rdns_info ("stripped dns reply: %d bytes remain", *remain); + rdns_info ("stripped dns reply: %d bytes remain; domain %s", *remain, + rep->requested_name); return -1; } GET16 (type); @@ -282,7 +283,7 @@ rdns_parse_rr (struct rdns_resolver *resolver, parsed = true; } else { - rdns_info ("corrupted A record"); + rdns_info ("corrupted A record; domain: %s", rep->requested_name); return -1; } break; @@ -294,14 +295,14 @@ rdns_parse_rr (struct rdns_resolver *resolver, parsed = true; } else { - rdns_info ("corrupted AAAA record"); + rdns_info ("corrupted AAAA record; domain %s", rep->requested_name); return -1; } break; case DNS_T_PTR: if (! rdns_parse_labels (resolver, in, &elt->content.ptr.name, &p, rep, remain, true)) { - rdns_info ("invalid labels in PTR record"); + rdns_info ("invalid labels in PTR record; domain %s", rep->requested_name); return -1; } parsed = true; @@ -309,7 +310,7 @@ rdns_parse_rr (struct rdns_resolver *resolver, case DNS_T_NS: if (! rdns_parse_labels (resolver, in, &elt->content.ns.name, &p, rep, remain, true)) { - rdns_info ("invalid labels in NS record"); + rdns_info ("invalid labels in NS record; domain %s", rep->requested_name); return -1; } parsed = true; @@ -317,60 +318,74 @@ rdns_parse_rr (struct rdns_resolver *resolver, case DNS_T_SOA: if (! rdns_parse_labels (resolver, in, &elt->content.soa.mname, &p, rep, remain, true)) { - rdns_info ("invalid labels in NS record"); + rdns_info ("invalid labels in SOA record; domain %s", rep->requested_name); return -1; } if (! rdns_parse_labels (resolver, in, &elt->content.soa.admin, &p, rep, remain, true)) { - rdns_info ("invalid labels in NS record"); + rdns_info ("invalid labels in SOA record; domain %s", rep->requested_name); + return -1; + } + if (*remain >= sizeof(int32_t) * 5) { + GET32 (elt->content.soa.serial); + GET32 (elt->content.soa.refresh); + GET32 (elt->content.soa.retry); + GET32 (elt->content.soa.expire); + GET32 (elt->content.soa.minimum); + } + else { + rdns_info ("invalid data in SOA record; domain %s", rep->requested_name); return -1; } - GET32 (elt->content.soa.serial); - GET32 (elt->content.soa.refresh); - GET32 (elt->content.soa.retry); - GET32 (elt->content.soa.expire); - GET32 (elt->content.soa.minimum); parsed = true; break; case DNS_T_MX: GET16 (elt->content.mx.priority); if (! rdns_parse_labels (resolver, in, &elt->content.mx.name, &p, rep, remain, true)) { - rdns_info ("invalid labels in MX record"); + rdns_info ("invalid labels in MX record; domain %s", rep->requested_name); return -1; } parsed = true; break; case DNS_T_TXT: case DNS_T_SPF: - elt->content.txt.data = malloc (datalen + 1); - if (elt->content.txt.data == NULL) { - rdns_err ("failed to allocate %d bytes for TXT record", (int)datalen + 1); - return -1; - } - /* Now we should compose data from parts */ - copied = 0; - parts = 0; - while (copied + parts < datalen) { - txtlen = *p; - if (txtlen + copied + parts <= datalen) { - parts ++; - memcpy (elt->content.txt.data + copied, p + 1, txtlen); - copied += txtlen; - p += txtlen + 1; - *remain -= txtlen + 1; + if (datalen <= *remain) { + elt->content.txt.data = malloc(datalen + 1); + if (elt->content.txt.data == NULL) { + rdns_err ("failed to allocate %d bytes for TXT record; domain %s", + (int) datalen + 1, rep->requested_name); + return -1; } - else { - break; + /* Now we should compose data from parts */ + copied = 0; + parts = 0; + while (copied + parts < datalen && *remain > 0) { + txtlen = *p; + if (txtlen + copied + parts <= datalen && *remain >= txtlen + 1) { + parts++; + memcpy (elt->content.txt.data + copied, p + 1, txtlen); + copied += txtlen; + p += txtlen + 1; + *remain -= txtlen + 1; + } + else { + break; + } } + *(elt->content.txt.data + copied) = '\0'; + parsed = true; + elt->type = RDNS_REQUEST_TXT; + } + else { + rdns_info ("stripped data in TXT record (%d bytes available, %d requested); " + "domain %s", (int)*remain, (int)datalen, rep->requested_name); + return -1; } - *(elt->content.txt.data + copied) = '\0'; - parsed = true; - elt->type = RDNS_REQUEST_TXT; break; case DNS_T_SRV: if (p - *pos > (int)(*remain - sizeof (uint16_t) * 3)) { - rdns_info ("stripped dns reply while reading SRV record"); + rdns_info ("stripped dns reply while reading SRV record; domain %s", rep->requested_name); return -1; } GET16 (elt->content.srv.priority); @@ -378,14 +393,14 @@ rdns_parse_rr (struct rdns_resolver *resolver, GET16 (elt->content.srv.port); if (! rdns_parse_labels (resolver, in, &elt->content.srv.target, &p, rep, remain, true)) { - rdns_info ("invalid labels in SRV record"); + rdns_info ("invalid labels in SRV record; domain %s", rep->requested_name); return -1; } parsed = true; break; case DNS_T_TLSA: if (p - *pos > (int)(*remain - sizeof (uint8_t) * 3) || datalen <= 3) { - rdns_info ("stripped dns reply while reading TLSA record"); + rdns_info ("stripped dns reply while reading TLSA record; domain %s", rep->requested_name); return -1; } GET8 (elt->content.tlsa.usage); @@ -394,7 +409,8 @@ rdns_parse_rr (struct rdns_resolver *resolver, datalen -= 3; elt->content.tlsa.data = malloc (datalen); if (elt->content.tlsa.data == NULL) { - rdns_err ("failed to allocate %d bytes for TLSA record", (int)datalen + 1); + rdns_err ("failed to allocate %d bytes for TLSA record; domain %s", + (int)datalen + 1, rep->requested_name); return -1; } elt->content.tlsa.datalen = datalen; @@ -409,7 +425,7 @@ rdns_parse_rr (struct rdns_resolver *resolver, *remain -= datalen; break; default: - rdns_debug ("unexpected RR type: %d", type); + rdns_debug ("unexpected RR type: %d; domain %s", type, rep->requested_name); p += datalen; *remain -= datalen; break; -- 2.39.5