2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 06:25:31 +00:00

Fix a date race in qpcache_addrdataset()

The 'qpnode->nsec' structure member isn't protected by a lock and
there's a data race between the reading and writing parts in the
qpcache_addrdataset() function. Use a node read lock for accessing
'qpnode->nsec' in qpcache_addrdataset(). Add an additional
'qpnode->nsec != DNS_DB_NSEC_HAS_NSEC' check under a write lock
to be sure that no other competing thread changed it in the time
when the read lock is unlocked and a write lock is not acquired
yet.
This commit is contained in:
Aram Sargsyan
2025-04-16 09:10:47 +00:00
parent 58a0e6cc61
commit e1a415b412

View File

@@ -2916,7 +2916,7 @@ qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
dns_slabheader_t *newheader = NULL;
isc_result_t result;
bool delegating = false;
bool newnsec;
bool newnsec = false;
isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = NULL;
@@ -2986,6 +2986,8 @@ qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
}
}
nlock = &qpdb->buckets[qpnode->locknum].lock;
/*
* If we're adding a delegation type (which would be an NS or DNAME
* for a zone, but only DNAME counts for a cache), we need to set
@@ -2998,8 +3000,13 @@ qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
/*
* Add to the auxiliary NSEC tree if we're adding an NSEC record.
*/
newnsec = (qpnode->nsec != DNS_DB_NSEC_HAS_NSEC &&
rdataset->type == dns_rdatatype_nsec);
if (rdataset->type == dns_rdatatype_nsec) {
NODE_RDLOCK(nlock, &nlocktype);
if (qpnode->nsec != DNS_DB_NSEC_HAS_NSEC) {
newnsec = true;
}
NODE_UNLOCK(nlock, &nlocktype);
}
/*
* If we're adding a delegation type or adding to the auxiliary
@@ -3009,8 +3016,6 @@ qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
TREE_WRLOCK(&qpdb->tree_lock, &tlocktype);
}
nlock = &qpdb->buckets[qpnode->locknum].lock;
NODE_WRLOCK(nlock, &nlocktype);
if (qpdb->rrsetstats != NULL) {
@@ -3023,7 +3028,7 @@ qpcache_addrdataset(dns_db_t *db, dns_dbnode_t *node, dns_dbversion_t *version,
expire_ttl_headers(qpdb, qpnode->locknum, &nlocktype, &tlocktype,
now DNS__DB_FLARG_PASS);
if (newnsec) {
if (newnsec && qpnode->nsec != DNS_DB_NSEC_HAS_NSEC) {
qpcnode_t *nsecnode = NULL;
result = dns_qp_getname(qpdb->nsec, name, (void **)&nsecnode,