mirror of
https://gitlab.isc.org/isc-projects/bind9
synced 2025-09-02 23:55: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:
@@ -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,
|
||||||
|
Reference in New Issue
Block a user