]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
fix NULL dereference in dns_view_bestzonecut()
authorColin Vidal <colin@isc.org>
Thu, 2 Apr 2026 07:17:17 +0000 (09:17 +0200)
committerColin Vidal <colin@isc.org>
Thu, 2 Apr 2026 10:16:12 +0000 (12:16 +0200)
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.)

lib/dns/view.c

index 2e4853d928b533a662688b14c04d9707ca5e92a9..eca63fae9ea7e61727409fe05200330613bf8962 100644 (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;
 }