]> source.dussan.org Git - rspamd.git/commitdiff
[Fix] Check remain before processing TXT records
authorVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 17 Jun 2021 10:38:11 +0000 (11:38 +0100)
committerVsevolod Stakhov <vsevolod@highsecure.ru>
Thu, 17 Jun 2021 10:39:22 +0000 (11:39 +0100)
contrib/librdns/parse.c

index a1b25e2ff4a0bf20c7095212e502ba7a2f6b1876..fbf9d3e1407ccb8d3b659810c4e2e7b32d913439 100644 (file)
@@ -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;