]> git.ipfire.org Git - thirdparty/unbound.git/commitdiff
- Fix for missing bounds check for decompressing dnames
authorW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 21 Apr 2026 08:32:37 +0000 (10:32 +0200)
committerW.C.A. Wijngaards <wouter@nlnetlabs.nl>
Tue, 21 Apr 2026 08:32:37 +0000 (10:32 +0200)
  for downloaded authority zones. This fixes that the server
  could end up with malformed zone content after receiving
  truncated packet contents from an AXFR. In addition, the
  domain names in the SOA rdata are checked before the
  authority code picks up the zone serial.
  Thanks to Halil Oktay for the report.

doc/Changelog
services/authzone.c

index a96f08a119362485ebdf865481083709a514ca23..fcbb4ca6fbdafce62939cd3a09bd73f3fb211a84 100644 (file)
          a DNAME record. This stops bad answers, and checks that
          the authoritative server gives correct replies.
          Thanks to Qifan Zhang, Palo Alto Networks for the report.
+       - Fix for missing bounds check for decompressing dnames
+         for downloaded authority zones. This fixes that the server
+         could end up with malformed zone content after receiving
+         truncated packet contents from an AXFR. In addition, the
+         domain names in the SOA rdata are checked before the
+         authority code picks up the zone serial.
+         Thanks to Halil Oktay for the report.
 
 20 April 2026: Wouter
        - Fix compile warnings for thread setname routine, and test compile.
index 9778cf1b79a23f130c62f79485714f5637419a54..ebcdc7e43643564f1b44a8c4ccae741505f8e541 100644 (file)
@@ -1369,6 +1369,10 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
                                uncompressed_len = pkt_dname_len(&pktbuf);
                                if(!uncompressed_len)
                                        return 0; /* parse error in dname */
+                               compressed_len = sldns_buffer_position(
+                                       &pktbuf) - oldpos;
+                               if(compressed_len > rdlen)
+                                       return 0; /* dname exceeds rdata */
                                if(!sldns_buffer_available(buf,
                                        uncompressed_len))
                                        /* dname too long for buffer */
@@ -1376,8 +1380,6 @@ decompress_rr_into_buffer(struct sldns_buffer* buf, uint8_t* pkt,
                                dname_pkt_copy(&pktbuf, 
                                        sldns_buffer_current(buf), rd);
                                sldns_buffer_skip(buf, (ssize_t)uncompressed_len);
-                               compressed_len = sldns_buffer_position(
-                                       &pktbuf) - oldpos;
                                rd += compressed_len;
                                rdlen -= compressed_len;
                                count--;
@@ -2003,12 +2005,21 @@ auth_zone_get_serial(struct auth_zone* z, uint32_t* serial)
        struct auth_data* apex;
        struct auth_rrset* soa;
        struct packed_rrset_data* d;
+       size_t primlen, mboxlen;
        apex = az_find_name(z, z->name, z->namelen);
        if(!apex) return 0;
        soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
        if(!soa || soa->data->count==0)
                return 0; /* no RRset or no RRs in rrset */
        if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */
+       if((primlen = dname_valid(soa->data->rr_data[0]+2,
+               soa->data->rr_len[0]-2)) == 0)
+               return 0; /* primary dname malformed */
+       if((mboxlen = dname_valid(soa->data->rr_data[0]+2+primlen,
+               soa->data->rr_len[0]-2-primlen)) == 0)
+               return 0; /* mailbox dname malformed */
+       if(2+primlen+mboxlen+4*5 != soa->data->rr_len[0])
+               return 0; /* rdata malformed */
        d = soa->data;
        *serial = sldns_read_uint32(d->rr_data[0]+(d->rr_len[0]-20));
        return 1;
@@ -2021,12 +2032,21 @@ xfr_find_soa(struct auth_zone* z, struct auth_xfer* xfr)
        struct auth_data* apex;
        struct auth_rrset* soa;
        struct packed_rrset_data* d;
+       size_t primlen, mboxlen;
        apex = az_find_name(z, z->name, z->namelen);
        if(!apex) return 0;
        soa = az_domain_rrset(apex, LDNS_RR_TYPE_SOA);
        if(!soa || soa->data->count==0)
                return 0; /* no RRset or no RRs in rrset */
        if(soa->data->rr_len[0] < 2+4*5) return 0; /* SOA too short */
+       if((primlen = dname_valid(soa->data->rr_data[0]+2,
+               soa->data->rr_len[0]-2)) == 0)
+               return 0; /* primary dname malformed */
+       if((mboxlen = dname_valid(soa->data->rr_data[0]+2+primlen,
+               soa->data->rr_len[0]-2-primlen)) == 0)
+               return 0; /* mailbox dname malformed */
+       if(2+primlen+mboxlen+4*5 != soa->data->rr_len[0])
+               return 0; /* rdata malformed */
        /* SOA record ends with serial, refresh, retry, expiry, minimum,
         * as 4 byte fields */
        d = soa->data;