fix NULL dereference in dns_view_bestzonecut()

When `dns_view_bestzonecut()` is called with a NULL `delegsetp`, it
calls `bestzonecut_zone()` with a NULL `rdataset` pointer but there is a
non-guarded de-reference of the `rdataset` pointer in
`bestzonecut_zone()`.

In practice, the only current situation where `dns_view_bestzonecut()`
is called with NULL `delegsetp` is from a case of `seek_ds()` _and_ the
non-guarded dereference occurs only if there is a static-stub local
zone matching the zonecut `seek_ds()` is looking for. It's unclear if
such flow is actually possible.

The `rdataset` is now always valid inside `dns_view_bestzonecut()`. (It
was initially set only if `delegsetp` was set to avoid extra works in
the qpzone, which can be skipped when `rdataset` is NULL, but this
doesn't really make a difference, considering we are in a slow path
considering the result wasn't found in this case.)
This commit is contained in:
Colin Vidal 2026-04-02 09:17:17 +02:00
parent 43c58dafcc
commit fc03a876ae

View file

@ -1140,19 +1140,14 @@ dns_view_bestzonecut(dns_view_t *view, const dns_name_t *name,
unsigned int options, bool usehints, bool usecache,
dns_delegset_t **delegsetp) {
isc_result_t result;
dns_rdataset_t rdatasetdata = DNS_RDATASET_INIT;
dns_rdataset_t *rdataset = NULL;
dns_rdataset_t rdataset = DNS_RDATASET_INIT;
REQUIRE(DNS_VIEW_VALID(view));
REQUIRE(view->frozen);
if (delegsetp != NULL) {
REQUIRE(*delegsetp == NULL);
rdataset = &rdatasetdata;
}
REQUIRE(delegsetp == NULL || *delegsetp == NULL);
result = bestzonecut_zone(view, name, fname, dcname, now, options,
rdataset);
&rdataset);
if (result == DNS_R_NXDOMAIN && usecache) {
/*
@ -1167,14 +1162,14 @@ dns_view_bestzonecut(dns_view_t *view, const dns_name_t *name,
* cache can have a more precise delegation.
*/
bestzonecut_zoneorcache(view, name, fname, dcname, now, options,
rdataset, delegsetp);
&rdataset, delegsetp);
}
/*
* No local zone nor cache match. Last attempt with the hints.
*/
if (result == DNS_R_NXDOMAIN && usehints) {
result = bestzonecut_hints(view, fname, dcname, now, rdataset);
result = bestzonecut_hints(view, fname, dcname, now, &rdataset);
}
if (result != ISC_R_SUCCESS) {
@ -1190,10 +1185,10 @@ dns_view_bestzonecut(dns_view_t *view, const dns_name_t *name,
* the same, and this avoid adding extra code here to extract
* A/AAAA rdataset if any.
*/
dns_delegset_fromnsrdataset(rdataset, delegsetp);
dns_delegset_fromnsrdataset(&rdataset, delegsetp);
}
dns_rdataset_cleanup(rdataset);
dns_rdataset_cleanup(&rdataset);
return result;
}