[9.16][CVE-2024-1737 (part 2)] Be smarter about refusing to add many RR types to the database

Add HTTPS, SVCB, SRV, PTR, NAPTR, DNSKEY and TXT records to the list of
the priority types that are put at the beginning of the slabheader list
for faster access and to avoid eviction when there are more types than
the max-types-per-name limit.

(cherry picked from commit b27c6bcce8)

---

Backport of MR https://gitlab.isc.org/isc-private/bind9/-/merge_requests/712

Related https://gitlab.isc.org/isc-projects/bind9/-/issues/3405

Merge branch '3405-limit-the-number-of-resource-records-in-rrset-nxdomain-9.16' into 'bind-9.16'

See merge request isc-projects/bind9!9172
This commit is contained in:
Nicki Křížek
2024-07-24 11:14:10 +00:00
2 changed files with 79 additions and 15 deletions
+4 -4
View File
@@ -596,18 +596,18 @@ n=$((n + 1))
echo_i "check prefetch qtype * (${n})"
ret=0
dig_with_opts @10.53.0.5 fetchall.tld any >dig.out.1.${n} || ret=1
ttl1=$(awk '/"A" "short" "ttl"/ { print $2 - 3 }' dig.out.1.${n})
ttl1=$(awk '/^fetchall.tld/ { print $2 - 3; exit }' dig.out.1.${n})
# sleep so we are in prefetch range
sleep "${ttl1:-0}"
# trigger prefetch
dig_with_opts @10.53.0.5 fetchall.tld any >dig.out.2.${n} || ret=1
ttl2=$(awk '/"A" "short" "ttl"/ { print $2 }' dig.out.2.${n})
ttl2=$(awk '/^fetchall.tld/ { print $2; exit }' dig.out.2.${n})
sleep 1
# check that prefetch occurred;
# note that only one record is prefetched, which is the AAAA record in this case,
# note that only the first record is prefetched,
# because of the order of the records in the cache
dig_with_opts @10.53.0.5 fetchall.tld any >dig.out.3.${n} || ret=1
ttl3=$(awk '/::1/ { print $2 }' dig.out.3.${n})
ttl3=$(awk '/^fetchall.tld/ { print $2; exit }' dig.out.3.${n})
test "${ttl3:-0}" -gt "${ttl2:-1}" || ret=1
if [ $ret != 0 ]; then echo_i "failed"; fi
status=$((status + ret))
+75 -11
View File
@@ -990,6 +990,8 @@ prio_type(rbtdb_rdatatype_t type) {
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_soa):
case dns_rdatatype_a:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_a):
case dns_rdatatype_mx:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_mx):
case dns_rdatatype_aaaa:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_aaaa):
case dns_rdatatype_nsec:
@@ -1002,6 +1004,22 @@ prio_type(rbtdb_rdatatype_t type) {
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ds):
case dns_rdatatype_cname:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_cname):
case dns_rdatatype_dname:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dname):
case dns_rdatatype_svcb:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_svcb):
case dns_rdatatype_https:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_https):
case dns_rdatatype_dnskey:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_dnskey):
case dns_rdatatype_srv:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_srv):
case dns_rdatatype_txt:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_txt):
case dns_rdatatype_ptr:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_ptr):
case dns_rdatatype_naptr:
case RBTDB_RDATATYPE_VALUE(dns_rdatatype_rrsig, dns_rdatatype_naptr):
return (true);
}
return (false);
@@ -6244,6 +6262,26 @@ update_recordsandxfrsize(bool add, rbtdb_version_t *rbtversion,
#define DNS_RBTDB_MAX_RTYPES 100
#endif /* DNS_RBTDB_MAX_RTYPES */
static bool
overmaxtype(dns_rbtdb_t *rbtdb, uint32_t ntypes) {
UNUSED(rbtdb);
if (DNS_RBTDB_MAX_RTYPES == 0) {
return (false);
}
return (ntypes >= DNS_RBTDB_MAX_RTYPES);
}
static bool
prio_header(rdatasetheader_t *header) {
if (NEGATIVE(header) && prio_type(RBTDB_RDATATYPE_EXT(header->type))) {
return (true);
}
return (prio_type(header->type));
}
/*
* write lock on rbtnode must be held.
*/
@@ -6255,7 +6293,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
rbtdb_changed_t *changed = NULL;
rdatasetheader_t *topheader = NULL, *topheader_prev = NULL;
rdatasetheader_t *header = NULL, *sigheader = NULL;
rdatasetheader_t *prioheader = NULL;
rdatasetheader_t *prioheader = NULL, *expireheader = NULL;
unsigned char *merged = NULL;
isc_result_t result;
bool header_nx;
@@ -6265,7 +6303,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
rbtdb_rdatatype_t negtype, sigtype;
dns_trust_t trust;
int idx;
uint32_t ntypes;
uint32_t ntypes = 0;
/*
* Add an rdatasetheader_t to a node.
@@ -6330,7 +6368,6 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
set_ttl(rbtdb, topheader, 0);
mark_header_ancient(rbtdb, topheader);
}
ntypes = 0;
goto find_header;
}
/*
@@ -6342,6 +6379,7 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
{
if (topheader->type == sigtype) {
sigheader = topheader;
break;
}
}
negtype = RBTDB_RDATATYPE_VALUE(covers, 0);
@@ -6354,11 +6392,9 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
* check for an extant non-ancient NODATA ncache
* entry which covers the same type as the RRSIG.
*/
ntypes = 0;
for (topheader = rbtnode->data; topheader != NULL;
topheader = topheader->next)
{
ntypes++;
if ((topheader->type ==
RBTDB_RDATATYPE_NCACHEANY) ||
(newheader->type == sigtype &&
@@ -6403,12 +6439,16 @@ add32(dns_rbtdb_t *rbtdb, dns_rbtnode_t *rbtnode, const dns_name_t *nodename,
}
}
ntypes = 0;
for (topheader = rbtnode->data; topheader != NULL;
topheader = topheader->next)
{
ntypes++;
if (prio_type(topheader->type)) {
if (IS_CACHE(rbtdb) && ACTIVE(topheader, now)) {
++ntypes;
expireheader = topheader;
} else if (!IS_CACHE(rbtdb)) {
++ntypes;
}
if (prio_header(topheader)) {
prioheader = topheader;
}
if (topheader->type == newheader->type ||
@@ -6765,8 +6805,7 @@ find_header:
/*
* No rdatasets of the given type exist at the node.
*/
if (ntypes > DNS_RBTDB_MAX_RTYPES) {
if (!IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) {
free_rdataset(rbtdb, rbtdb->common.mctx,
newheader);
return (ISC_R_QUOTA);
@@ -6774,7 +6813,7 @@ find_header:
newheader->down = NULL;
if (prio_type(newheader->type)) {
if (prio_header(newheader)) {
/* This is a priority type, prepend it */
newheader->next = rbtnode->data;
rbtnode->data = newheader;
@@ -6787,6 +6826,31 @@ find_header:
newheader->next = rbtnode->data;
rbtnode->data = newheader;
}
if (IS_CACHE(rbtdb) && overmaxtype(rbtdb, ntypes)) {
if (expireheader == NULL) {
expireheader = newheader;
}
if (NEGATIVE(newheader) &&
!prio_header(newheader))
{
/*
* Add the new non-priority negative
* header to the database only
* temporarily.
*/
expireheader = newheader;
}
set_ttl(rbtdb, expireheader, 0);
mark_header_ancient(rbtdb, expireheader);
/*
* FIXME: In theory, we should mark the RRSIG
* and the header at the same time, but there is
* no direct link between those two header, so
* we would have to check the whole list again.
*/
}
}
}