From: W.C.A. Wijngaards Date: Tue, 21 Apr 2026 08:32:37 +0000 (+0200) Subject: - Fix for missing bounds check for decompressing dnames X-Git-Tag: release-1.25.0rc1~6 X-Git-Url: http://git.ipfire.org/gitweb/?a=commitdiff_plain;h=84c645e7b39e13a1a8d9e3fd8a96c694387e04f6;p=thirdparty%2Funbound.git - 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. --- diff --git a/doc/Changelog b/doc/Changelog index a96f08a11..fcbb4ca6f 100644 --- a/doc/Changelog +++ b/doc/Changelog @@ -19,6 +19,13 @@ 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. diff --git a/services/authzone.c b/services/authzone.c index 9778cf1b7..ebcdc7e43 100644 --- a/services/authzone.c +++ b/services/authzone.c @@ -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;