mirror of
https://github.com/isc-projects/bind9.git
synced 2026-07-15 06:50:52 -04:00
[9.20] fix: usr: Fix a crash when querying an empty non-terminal in a wildcard zone in RBTDB
A query for an empty non-terminal in a wildcard zone served from the RBT zone database could abort named with an assertion failure. It now returns the correct NODATA answer. Closes #6170 Merge branch '6170-fix-non-terminal-wildcard-in-rbtdb-9.20' into 'bind-9.20' See merge request isc-projects/bind9!12299
This commit is contained in:
commit
b8e5801ec5
7 changed files with 142 additions and 1 deletions
26
bin/tests/system/wildcard/ns1/entwild.db.in
Normal file
26
bin/tests/system/wildcard/ns1/entwild.db.in
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
; Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
;
|
||||
; SPDX-License-Identifier: MPL-2.0
|
||||
;
|
||||
; This Source Code Form is subject to the terms of the Mozilla Public
|
||||
; License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
; file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
;
|
||||
; See the COPYRIGHT file distributed with this work for additional
|
||||
; information regarding copyright ownership.
|
||||
|
||||
; GL #6170 regression zone.
|
||||
;
|
||||
; An apex wildcard combined with a deeper name (en.jun2026.2048._domainkey)
|
||||
; that forms empty non-terminals. Querying one of those empty non-terminals
|
||||
; (e.g. 2048._domainkey) with DNSSEC requested, while the zone is served from
|
||||
; the RBT zone database, used to abort named in wildcard_blocked() because the
|
||||
; DNS_R_NEWORIGIN result of dns_rbtnodechain_next() was not handled.
|
||||
|
||||
$TTL 3600
|
||||
@ IN SOA ns hostmaster ( 1 3600 1200 604800 3600 )
|
||||
IN NS ns
|
||||
ns IN A 10.53.0.1
|
||||
* IN A 192.0.2.1
|
||||
en.jun2026.2048._domainkey IN TXT "v=DKIM1; k=rsa; p=PUBLICKEYDATA"
|
||||
crm._domainkey IN CNAME .
|
||||
|
|
@ -40,6 +40,16 @@ zone "nestedwild.test" {
|
|||
check-names ignore;
|
||||
};
|
||||
|
||||
/*
|
||||
* GL #6170: querying an empty non-terminal in this NSEC3-signed zone, which
|
||||
* also has a wildcard, used to abort named when served from RBTDB.
|
||||
*/
|
||||
zone "entwild.test" {
|
||||
type primary;
|
||||
file "entwild.db.signed";
|
||||
check-names ignore;
|
||||
};
|
||||
|
||||
/*
|
||||
* The contents of nsec3 and private.nsec3 are specially chosen to
|
||||
* have separate NSEC3 records for the "no qname proof" and the
|
||||
|
|
|
|||
|
|
@ -20,6 +20,20 @@ cp allwild.db.in allwild.db
|
|||
cp example.db.in example.db
|
||||
cp nestedwild.db.in nestedwild.db
|
||||
|
||||
# GL #6170: NSEC3-signed zone with a wildcard above empty non-terminals.
|
||||
zone=entwild.test
|
||||
infile=entwild.db.in
|
||||
zonefile=entwild.db
|
||||
outfile=entwild.db.signed
|
||||
|
||||
keyname1=$($KEYGEN -a ${DEFAULT_ALGORITHM} -n zone $zone 2>/dev/null)
|
||||
keyname2=$($KEYGEN -f KSK -a ${DEFAULT_ALGORITHM} -n zone $zone 2>/dev/null)
|
||||
|
||||
cat $infile $keyname1.key $keyname2.key >$zonefile
|
||||
|
||||
$SIGNER -3 - -H 10 -o $zone -f $outfile $zonefile >/dev/null 2>signer.err || cat signer.err
|
||||
echo_i "signed $zone"
|
||||
|
||||
zone=nsec
|
||||
infile=nsec.db.in
|
||||
zonefile=nsec.db
|
||||
|
|
|
|||
89
bin/tests/system/wildcard/tests_nonterminal_wildcard.py
Normal file
89
bin/tests/system/wildcard/tests_nonterminal_wildcard.py
Normal file
|
|
@ -0,0 +1,89 @@
|
|||
# Copyright (C) Internet Systems Consortium, Inc. ("ISC")
|
||||
#
|
||||
# SPDX-License-Identifier: MPL-2.0
|
||||
#
|
||||
# This Source Code Form is subject to the terms of the Mozilla Public
|
||||
# License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
# file, you can obtain one at https://mozilla.org/MPL/2.0/.
|
||||
#
|
||||
# See the COPYRIGHT file distributed with this work for additional
|
||||
# information regarding copyright ownership.
|
||||
|
||||
"""
|
||||
Regression test for GL #6170.
|
||||
|
||||
The NSEC3-signed zone entwild.test has an apex wildcard together with a deeper
|
||||
name (en.jun2026.2048._domainkey) that forms empty non-terminals. Querying
|
||||
one of those empty non-terminals (2048._domainkey) with DNSSEC requested, while
|
||||
the zone is served from the RBT zone database, used to abort named with:
|
||||
|
||||
lib/dns/include/dns/name.h:1013: REQUIRE(suffixlabels <= name->labels) failed
|
||||
|
||||
wildcard_blocked() in lib/dns/rbt-zonedb.c did not treat the DNS_R_NEWORIGIN
|
||||
result of dns_rbtnodechain_next() as a successful step when looking for the
|
||||
successor of the queried name, so the empty non-terminal that blocks the
|
||||
wildcard expansion was missed. The empty non-terminal must instead be answered
|
||||
with NODATA and an NSEC3 proof.
|
||||
|
||||
The bug only affected RBTDB; QPzone is unaffected.
|
||||
"""
|
||||
|
||||
import dns.rdatatype
|
||||
import pytest
|
||||
|
||||
import isctest
|
||||
|
||||
pytestmark = pytest.mark.extra_artifacts(
|
||||
[
|
||||
"ns1/K*",
|
||||
"ns1/dsset-*",
|
||||
"ns1/*.signed",
|
||||
"ns1/allwild.db",
|
||||
"ns1/entwild.db",
|
||||
"ns1/example.db",
|
||||
"ns1/nestedwild.db",
|
||||
"ns1/nsec.db",
|
||||
"ns1/nsec3.db",
|
||||
"ns1/private.nsec.conf",
|
||||
"ns1/private.nsec.db",
|
||||
"ns1/private.nsec3.conf",
|
||||
"ns1/private.nsec3.db",
|
||||
"ns1/root.db",
|
||||
"ns1/signer.err",
|
||||
"ns1/trusted.conf",
|
||||
]
|
||||
)
|
||||
|
||||
IP_ADDR = "10.53.0.1"
|
||||
|
||||
# 2048._domainkey.entwild.test. and _domainkey.entwild.test. are empty
|
||||
# non-terminals: they exist only because en.jun2026.2048._domainkey.entwild.test.
|
||||
# and crm._domainkey.entwild.test. do. They sit between the apex wildcard and
|
||||
# the existing names.
|
||||
ENT_NAME = "2048._domainkey.entwild.test."
|
||||
|
||||
|
||||
def test_empty_nonterminal_under_wildcard_is_nodata(named_port):
|
||||
"""Querying the empty non-terminal must yield NODATA, not crash named."""
|
||||
query = isctest.query.create(ENT_NAME, "A")
|
||||
response = isctest.query.tcp(query, IP_ADDR, named_port)
|
||||
|
||||
isctest.check.is_response_to(response, query)
|
||||
# The empty non-terminal exists, so the wildcard must not expand: NODATA.
|
||||
isctest.check.noerror(response)
|
||||
isctest.check.empty_answer(response)
|
||||
# The NSEC3 empty-non-terminal proof is the code path that used to crash.
|
||||
assert any(
|
||||
rrset.rdtype == dns.rdatatype.NSEC3 for rrset in response.authority
|
||||
), str(response)
|
||||
|
||||
|
||||
def test_wildcard_still_expands_without_blocking_ent(named_port):
|
||||
"""A name with no blocking empty non-terminal is still synthesized."""
|
||||
query = isctest.query.create("nonexistent.entwild.test.", "A")
|
||||
response = isctest.query.tcp(query, IP_ADDR, named_port)
|
||||
|
||||
isctest.check.is_response_to(response, query)
|
||||
isctest.check.noerror(response)
|
||||
assert response.answer, str(response)
|
||||
assert response.answer[0][0].to_text() == "192.0.2.1", str(response)
|
||||
|
|
@ -18,6 +18,7 @@ pytestmark = pytest.mark.extra_artifacts(
|
|||
"ns1/dsset-*",
|
||||
"ns1/*.signed",
|
||||
"ns1/allwild.db",
|
||||
"ns1/entwild.db",
|
||||
"ns1/example.db",
|
||||
"ns1/nestedwild.db",
|
||||
"ns1/nsec.db",
|
||||
|
|
|
|||
|
|
@ -51,6 +51,7 @@ pytestmark = pytest.mark.extra_artifacts(
|
|||
"ns1/dsset-*",
|
||||
"ns1/*.signed",
|
||||
"ns1/allwild.db",
|
||||
"ns1/entwild.db",
|
||||
"ns1/example.db",
|
||||
"ns1/nestedwild.db",
|
||||
"ns1/nsec.db",
|
||||
|
|
|
|||
|
|
@ -429,7 +429,7 @@ wildcard_blocked(rbtdb_search_t *search, const dns_name_t *qname,
|
|||
/* Now reset the chain and look for a successor with data. */
|
||||
chain = search->chain;
|
||||
result = dns_rbtnodechain_next(&chain, NULL, NULL);
|
||||
if (result == ISC_R_SUCCESS) {
|
||||
if (result == ISC_R_SUCCESS || result == DNS_R_NEWORIGIN) {
|
||||
check_next = step(search, &chain, FORWARD, next);
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue