[9.21.16] fix: usr: Adding NSEC3 opt-out records could leave invalid records in chain

When creating an NSEC3 opt-out chain, a node in the chain could be removed too soon, causing the previous NSEC3 being unable to be found, resulting in invalid NSEC3 records to be left in the zone. This has been fixed.

Closes isc-projects/bind9#5671

Backport of isc-projects/bind9!11328

Merge branch '5671-fix-dbiterator-prev-9.21.16' into 'v9.21.16-release'

See merge request isc-private/bind9!891
This commit is contained in:
Andoni Duarte 2025-12-09 12:17:57 +00:00
commit 6d03b4f9c6

View file

@ -4300,6 +4300,9 @@ dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
isc_result_t result;
qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
qpznode_t *node = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = NULL;
REQUIRE(qpdbiter->node != NULL);
@ -4307,7 +4310,12 @@ dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
return qpdbiter->result;
}
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
/*
* Defer the release of the current node until we have the prev node
* from the QP tree.
*/
node = qpdbiter->node;
qpdbiter->node = NULL;
result = dns_qpiter_prev(&qpdbiter->iter, NULL,
(void **)&qpdbiter->node, NULL);
@ -4382,6 +4390,14 @@ dbiterator_prev(dns_dbiterator_t *iterator DNS__DB_FLARG) {
UNREACHABLE();
}
/*
* We have the prev node, we can release the previous current.
*/
nlock = qpzone_get_lock(node);
NODE_RDLOCK(nlock, &nlocktype);
qpznode_release(node, 0, &nlocktype DNS__DB_FLARG_PASS);
NODE_UNLOCK(nlock, &nlocktype);
if (result == ISC_R_SUCCESS) {
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
} else {
@ -4397,6 +4413,9 @@ dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG) {
isc_result_t result;
qpdb_dbiterator_t *qpdbiter = (qpdb_dbiterator_t *)iterator;
qpzonedb_t *qpdb = (qpzonedb_t *)iterator->db;
qpznode_t *node = NULL;
isc_rwlocktype_t nlocktype = isc_rwlocktype_none;
isc_rwlock_t *nlock = NULL;
REQUIRE(qpdbiter->node != NULL);
@ -4404,7 +4423,12 @@ dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG) {
return qpdbiter->result;
}
dereference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
/*
* Defer the release of the current node until we have the next node
* from the QP tree.
*/
node = qpdbiter->node;
qpdbiter->node = NULL;
result = dns_qpiter_next(&qpdbiter->iter, NULL,
(void **)&qpdbiter->node, NULL);
@ -4461,6 +4485,14 @@ dbiterator_next(dns_dbiterator_t *iterator DNS__DB_FLARG) {
UNREACHABLE();
}
/*
* We have the next node, we can release the previous current.
*/
nlock = qpzone_get_lock(node);
NODE_RDLOCK(nlock, &nlocktype);
qpznode_release(node, 0, &nlocktype DNS__DB_FLARG_PASS);
NODE_UNLOCK(nlock, &nlocktype);
if (result == ISC_R_SUCCESS) {
reference_iter_node(qpdbiter DNS__DB_FLARG_PASS);
} else {