From 5725c4191fa01175b0ca5b582ecf6860eed1ca5f Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Wed, 8 Apr 2026 14:43:16 +1000 Subject: [PATCH 1/3] Test oversized private record is properly ignored --- bin/tests/system/inline/tests.sh | 39 ++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/bin/tests/system/inline/tests.sh b/bin/tests/system/inline/tests.sh index 128cb49ef6..805824b8e8 100755 --- a/bin/tests/system/inline/tests.sh +++ b/bin/tests/system/inline/tests.sh @@ -1383,5 +1383,44 @@ test ${ttl2:-0} -eq 400 || ret=1 test "$ret" -eq 0 || echo_i "failed" status=$((status + ret)) +n=$((n + 1)) +echo_i "Test oversized private record is properly ignored ($n)" +ret=0 +zone=oversized-private-record +cat >ns3/oversized-private-record.db <dig.out.ns7.test$n.soa || ret=1 +grep "status: NOERROR" dig.out.ns7.test$n.soa >/dev/null || ret=1 +grep "TYPE65534.\\\\# 262" dig.out.ns7.test$n.soa >/dev/null || ret=1 +test "$ret" -eq 0 || echo_i "failed" +status=$((status + ret)) + echo_i "exit status: $status" [ $status -eq 0 ] || exit 1 From 7182a03b8277ccc09fe065703535c90ca1a8a59e Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Wed, 8 Apr 2026 14:43:23 +1000 Subject: [PATCH 2/3] Properly detect private records before copying We were triggering an assertion when trying to copy a private record to a buffer for modifying. Extend the private type detection and copy the contents after we have rejected invalid private records. --- lib/dns/nsec3.c | 25 ++++++++++++++++++------- 1 file changed, 18 insertions(+), 7 deletions(-) diff --git a/lib/dns/nsec3.c b/lib/dns/nsec3.c index 64e49ad3f0..e889b877c2 100644 --- a/lib/dns/nsec3.c +++ b/lib/dns/nsec3.c @@ -1123,20 +1123,31 @@ try_private: DNS_RDATASET_FOREACH(&rdataset) { dns_rdata_t rdata = DNS_RDATA_INIT; dns_rdataset_current(&rdataset, &rdata); - INSIST(rdata.length <= sizeof(buf)); - memmove(buf, rdata.data, rdata.length); /* - * Private NSEC3 record length >= 6. - * <0(1), hash(1), flags(1), iterations(2), saltlen(1)> + * Filter out non-private records. Delete private records that + * were being used to creating NSEC3 chains and add private + * records to remove that chains that were in the process of + * being constructed. If nonsec is set and there is a record + * saying to go insecure preserve it. + * + * Private records have 6 <= length <= 261 (6 + saltlen) and + * the following structure: + * + * <0(1), hash(1), flags(1), iterations(2), saltlen(1), + * salt(0..255)> */ - if (rdata.length < 6 || buf[0] != 0 || - (buf[2] & DNS_NSEC3FLAG_REMOVE) != 0 || - (nonsec && (buf[2] & DNS_NSEC3FLAG_NONSEC) != 0)) + if (rdata.length < 6 || rdata.data[0] != 0 || + rdata.data[5] + 6 != rdata.length || + (rdata.data[2] & DNS_NSEC3FLAG_REMOVE) != 0 || + (nonsec && (rdata.data[2] & DNS_NSEC3FLAG_NONSEC) != 0)) { continue; } + INSIST(rdata.length <= sizeof(buf)); + memmove(buf, rdata.data, rdata.length); + dns_difftuple_create(diff->mctx, DNS_DIFFOP_DEL, origin, 0, &rdata, &tuple); CHECK(do_one_tuple(&tuple, db, ver, diff)); From 5d7387b185726cd60181d18df12ef733588c9fc1 Mon Sep 17 00:00:00 2001 From: Mark Andrews Date: Fri, 15 May 2026 11:06:38 +1000 Subject: [PATCH 3/3] Add DNS_PRIVATE_BUFFERSIZE and use it The size of a private records is 1 byte more than the corresponding NSEC3PARAM record. --- lib/dns/include/dns/private.h | 7 +++++++ lib/dns/nsec3.c | 3 ++- lib/ns/update.c | 2 +- tests/dns/private_test.c | 8 ++++---- 4 files changed, 14 insertions(+), 6 deletions(-) diff --git a/lib/dns/include/dns/private.h b/lib/dns/include/dns/private.h index 8f3d5a32ad..883ddc746a 100644 --- a/lib/dns/include/dns/private.h +++ b/lib/dns/include/dns/private.h @@ -16,8 +16,15 @@ #include #include +#include #include +/* + * The private record has one extra byte, containing a 0, in front of + * an NSEC3PARAM record. + */ +#define DNS_PRIVATE_BUFFERSIZE (DNS_NSEC3PARAM_BUFFERSIZE + 1) + #pragma once isc_result_t diff --git a/lib/dns/nsec3.c b/lib/dns/nsec3.c index e889b877c2..6b8d3b8f52 100644 --- a/lib/dns/nsec3.c +++ b/lib/dns/nsec3.c @@ -32,6 +32,7 @@ #include #include #include +#include #include #include #include @@ -1064,7 +1065,7 @@ dns_nsec3param_deletechains(dns_db_t *db, dns_dbversion_t *ver, dns_rdataset_t rdataset; bool flag; isc_result_t result = ISC_R_SUCCESS; - unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1]; + unsigned char buf[DNS_PRIVATE_BUFFERSIZE]; dns_name_t *origin = dns_zone_getorigin(zone); dns_rdatatype_t privatetype = dns_zone_getprivatetype(zone); diff --git a/lib/ns/update.c b/lib/ns/update.c index 12bcf5a2c1..7cfc75dbe1 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -2323,7 +2323,7 @@ add_nsec3param_records(ns_client_t *client, dns_zone_t *zone, dns_db_t *db, isc_result_t result = ISC_R_SUCCESS; dns_difftuple_t *newtuple = NULL; dns_rdata_t rdata = DNS_RDATA_INIT; - unsigned char buf[DNS_NSEC3PARAM_BUFFERSIZE + 1]; + unsigned char buf[DNS_PRIVATE_BUFFERSIZE]; dns_diff_t temp_diff; dns_diffop_t op; bool flag; diff --git a/tests/dns/private_test.c b/tests/dns/private_test.c index ff851996a3..c4669ced4e 100644 --- a/tests/dns/private_test.c +++ b/tests/dns/private_test.c @@ -74,7 +74,7 @@ make_signing(signing_testcase_t *testcase, dns_rdata_t *private, static void make_nsec3(nsec3_testcase_t *testcase, dns_rdata_t *private, - unsigned char *pbuf) { + unsigned char *pbuf, size_t pbufsize) { isc_result_t result; dns_rdata_nsec3param_t params; dns_rdata_t nsec3param = DNS_RDATA_INIT; @@ -119,7 +119,7 @@ make_nsec3(nsec3_testcase_t *testcase, dns_rdata_t *private, dns_rdata_init(private); dns_nsec3param_toprivate(&nsec3param, private, privatetype, pbuf, - DNS_NSEC3PARAM_BUFFERSIZE + 1); + pbufsize); } /* convert private signing records to text */ @@ -179,13 +179,13 @@ ISC_RUN_TEST_IMPL(private_nsec3_totext) { UNUSED(state); for (i = 0; i < ncases; i++) { - unsigned char data[DNS_NSEC3PARAM_BUFFERSIZE + 1]; + unsigned char data[DNS_PRIVATE_BUFFERSIZE]; char output[BUFSIZ]; isc_buffer_t buf; isc_buffer_init(&buf, output, sizeof(output)); - make_nsec3(&testcases[i], &private, data); + make_nsec3(&testcases[i], &private, data, sizeof(data)); dns_private_totext(&private, &buf); assert_string_equal(output, results[i]); }