2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-09-03 16:15:27 +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; dns_slabheader_t *newheader = NULL;
isc_result_t result; isc_result_t result;
bool delegating = false; bool delegating = false;
bool newnsec; bool newnsec = false;
isc_rwlocktype_t tlocktype = isc_rwlocktype_none; isc_rwlocktype_t tlocktype = isc_rwlocktype_none;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none; isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = NULL; 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 * 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 * 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. * Add to the auxiliary NSEC tree if we're adding an NSEC record.
*/ */
newnsec = (qpnode->nsec != DNS_DB_NSEC_HAS_NSEC && if (rdataset->type == dns_rdatatype_nsec) {
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 * 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); TREE_WRLOCK(&qpdb->tree_lock, &tlocktype);
} }
nlock = &qpdb->buckets[qpnode->locknum].lock;
NODE_WRLOCK(nlock, &nlocktype); NODE_WRLOCK(nlock, &nlocktype);
if (qpdb->rrsetstats != NULL) { 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, expire_ttl_headers(qpdb, qpnode->locknum, &nlocktype, &tlocktype,
now DNS__DB_FLARG_PASS); now DNS__DB_FLARG_PASS);
if (newnsec) { if (newnsec && qpnode->nsec != DNS_DB_NSEC_HAS_NSEC) {
qpcnode_t *nsecnode = NULL; qpcnode_t *nsecnode = NULL;
result = dns_qp_getname(qpdb->nsec, name, (void **)&nsecnode, result = dns_qp_getname(qpdb->nsec, name, (void **)&nsecnode,