fix: dev: Unpack struct vecheader

The bitset packing of the resign_lsb and heap_index in struct vecheader was causing a race condition, since both bindrdataset and heap operations tried to access the same byte (even though they are accessing different fields).
    
While heap operations are protected by the node lock of the header being inserted, they aren't protected by the node locks of the headers being displaced, leading to the race condition.
    
This MR fixes the issue by reverting the struct packing optimization.

Closes #5688

Merge branch '5688-no-heap-index-bitset' into 'main'

See merge request isc-projects/bind9!11378
This commit is contained in:
Alessio Podda 2025-12-16 17:06:12 +00:00
commit 7cbf5f652a
2 changed files with 12 additions and 6 deletions

View file

@ -81,18 +81,24 @@ struct dns_vecheader {
_Atomic(uint16_t) attributes;
_Atomic(dns_trust_t) trust;
/*%
* Locked by the heap lock. Can't be packed together with other fields
* since it is protected by a different lock.
*/
unsigned int heap_index;
/*%
* Locked by the owning node's lock.
*/
uint16_t resign_lsb : 1;
unsigned int heap_index : 31;
uint32_t serial;
dns_ttl_t ttl;
dns_typepair_t typepair;
/* resigning (zone). The lsb is not adjacent for struct packing reasons
/*
* resigning (zone).
*/
isc_stdtime_t resign;
uint16_t resign_lsb : 1;
/*%
* Link to the other versions of this rdataset.

View file

@ -1840,14 +1840,14 @@ add(qpzonedb_t *qpdb, qpznode_t *node, const dns_name_t *nodename,
result = ISC_R_SUCCESS;
if ((options & DNS_DBADD_EXACT) != 0) {
flags |= DNS_RDATASLAB_EXACT;
flags |= DNS_RDATAVEC_EXACT;
}
if ((options & DNS_DBADD_EXACTTTL) != 0 &&
newheader->ttl != header->ttl)
{
result = DNS_R_NOTEXACT;
} else if (newheader->ttl != header->ttl) {
flags |= DNS_RDATASLAB_FORCE;
flags |= DNS_RDATAVEC_FORCE;
}
if (result == ISC_R_SUCCESS) {
result = dns_rdatavec_merge(
@ -4943,7 +4943,7 @@ qpzone_subtractrdataset(dns_db_t *db, dns_dbnode_t *dbnode,
subresult = NULL;
result = ISC_R_SUCCESS;
if ((options & DNS_DBSUB_EXACT) != 0) {
flags |= DNS_RDATASLAB_EXACT;
flags |= DNS_RDATAVEC_EXACT;
if (newheader->ttl != header->ttl) {
result = DNS_R_NOTEXACT;
}