[9.18] fix: usr: Reject record sets too large to serve in DNS

When BIND was asked to store a record set whose total size exceeds
what fits in a DNS message, it would allocate memory and build the
structure, then fail later at response time. Such oversized record
sets are now rejected at the time of storage with an error, avoiding
wasted work on data that can never be served.

Backport of MR !11963

Merge branch 'backport-ondrej/harden-buflen-overflow-9.18' into 'bind-9.18'

See merge request isc-projects/bind9!11965
This commit is contained in:
Ondřej Surý 2026-05-05 20:22:33 +02:00
commit ab3d96b3e3
2 changed files with 22 additions and 5 deletions

View file

@ -126,7 +126,7 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
#if DNS_RDATASET_FIXED
unsigned char *offsetbase;
#endif /* if DNS_RDATASET_FIXED */
unsigned int buflen;
uint32_t buflen;
isc_result_t result;
unsigned int nitems;
unsigned int nalloc;
@ -240,6 +240,10 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
if (rdataset->type == dns_rdatatype_rrsig) {
buflen++;
}
if (buflen - reservelen - 2 > DNS_RDATA_MAXLENGTH) {
result = ISC_R_NOSPACE;
goto free_rdatas;
}
}
}
@ -257,6 +261,10 @@ dns_rdataslab_fromrdataset(dns_rdataset_t *rdataset, isc_mem_t *mctx,
if (rdataset->type == dns_rdatatype_rrsig) {
buflen++;
}
if (buflen - reservelen - 2 > DNS_RDATA_MAXLENGTH) {
result = ISC_R_NOSPACE;
goto free_rdatas;
}
/*
* Ensure that singleton types are actually singletons.
@ -492,7 +500,8 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
unsigned int flags, uint32_t maxrrperset,
unsigned char **tslabp) {
unsigned char *ocurrent, *ostart, *ncurrent, *tstart, *tcurrent, *data;
unsigned int ocount, ncount, count, olength, tlength, tcount, length;
unsigned int ocount, ncount, count, olength, tcount, length;
uint32_t tlength;
dns_rdata_t ordata = DNS_RDATA_INIT;
dns_rdata_t nrdata = DNS_RDATA_INIT;
bool added_something = false;
@ -583,6 +592,9 @@ dns_rdataslab_merge(unsigned char *oslab, unsigned char *nslab,
if (type == dns_rdatatype_rrsig) {
tlength++;
}
if (tlength - reservelen - 2 > DNS_RDATA_MAXLENGTH) {
return ISC_R_NOSPACE;
}
tcount++;
nncount++;
added_something = true;
@ -761,7 +773,8 @@ dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab,
dns_rdataclass_t rdclass, dns_rdatatype_t type,
unsigned int flags, unsigned char **tslabp) {
unsigned char *mcurrent, *sstart, *scurrent, *tstart, *tcurrent;
unsigned int mcount, scount, rcount, count, tlength, tcount, i;
unsigned int mcount, scount, rcount, count, tcount, i;
uint32_t tlength;
dns_rdata_t srdata = DNS_RDATA_INIT;
dns_rdata_t mrdata = DNS_RDATA_INIT;
#if DNS_RDATASET_FIXED
@ -818,7 +831,10 @@ dns_rdataslab_subtract(unsigned char *mslab, unsigned char *sslab,
* This rdata isn't in the sslab, and thus isn't
* being subtracted.
*/
tlength += (unsigned int)(mcurrent - mrdatabegin);
tlength += (uint32_t)(mcurrent - mrdatabegin);
if (tlength - reservelen - 2 > DNS_RDATA_MAXLENGTH) {
return ISC_R_NOSPACE;
}
tcount++;
} else {
rcount++;

View file

@ -316,7 +316,8 @@ ISC_RUN_TEST_IMPL(overmempurge_bigrdata) {
* cache size doesn't reach the "max".
*/
while (i-- > 0) {
overmempurge_addrdataset(db, now, i, 50054, 65535, false);
overmempurge_addrdataset(db, now, i, 50054,
DNS_RDATA_MAXLENGTH - 8, false);
assert_true(isc_mem_inuse(mctx2) < maxcache);
}