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:
@@ -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,
|
||||
|
Reference in New Issue
Block a user