]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Disable UPDATE and NOTIFY for non-IN classes
authorEvan Hunt <each@isc.org>
Wed, 4 Mar 2026 21:24:52 +0000 (13:24 -0800)
committerMichał Kępień <michal@isc.org>
Thu, 7 May 2026 11:09:18 +0000 (13:09 +0200)
Return NOTIMP for UPDATE and NOTIFY requests received for views with a
class other than IN.  Only QUERY is now supported for non-IN views such
as CHAOS.

When running dns dns_rdata_tostruct() with types that are only defined
for class IN, ensure that the class is correct before proceeding.

Add an assertion that any zone being updated is of class IN. (Note
that previously, a DLZ zone could have its class value set incorrectly
to NONE; this has been fixed.)

This addresses YWH-PGM40640-70 and YWH-PGM40640-73 (as well as any
similar problems that might have occurred in the future) by minimizing
the code paths that can be reached by rdata classes other than IN, so it
is safe for the implementation to assume that rdatatypes that are only
defined for class IN, such as SVCB or WKS, have been parsed and
validated, and not accepted as unknown/opaque data.

Fixes: isc-projects/bind9#5777
Fixes: isc-projects/bind9#5779
(cherry picked from commit a6d8e330ed6cf0021bff3f00aa1dc7a296f5aec0)

bin/named/server.c
lib/dns/adb.c
lib/ns/client.c
lib/ns/update.c

index 5d0bbfaa308213d3e57aabeb0bddc5f10eb4b9d0..63bb311d3a9906d9c7d627ef67fb5fcba657d28a 100644 (file)
@@ -1917,10 +1917,12 @@ dlzconfigure_callback(dns_view_t *view, dns_dlzdb_t *dlzdb, dns_zone_t *zone) {
        dns_rdataclass_t zclass = view->rdclass;
        isc_result_t result;
 
+       dns_zone_setclass(zone, zclass);
        result = dns_zonemgr_managezone(named_g_server->zonemgr, zone);
        if (result != ISC_R_SUCCESS) {
                return result;
        }
+
        dns_zone_setstats(zone, named_g_server->zonestats);
 
        return named_zone_configure_writeable_dlz(dlzdb, zone, zclass, origin);
index 1514fb46b9b1b398b62efdc5af9aedbf64d4fda4..7bfafff6d4650eb4e543bff828e6443419b3e3df 100644 (file)
@@ -567,6 +567,9 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
 
        rdtype = rdataset->type;
 
+       REQUIRE(rdataset->rdclass == dns_rdataclass_in);
+       REQUIRE(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
+
        switch (rdataset->trust) {
        case dns_trust_glue:
        case dns_trust_additional:
@@ -579,8 +582,6 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
                rdataset->ttl = ttlclamp(rdataset->ttl);
        }
 
-       REQUIRE(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
-
        for (result = dns_rdataset_first(rdataset); result == ISC_R_SUCCESS;
             result = dns_rdataset_next(rdataset))
        {
index 9bae43b3804ac03dff5d0be09174632ea8af7ed0..32f0240180dd1350fdc77fa0f6d36cf9f55961ed 100644 (file)
@@ -2413,6 +2413,10 @@ ns_client_request_continue(void *arg) {
                break;
        case dns_opcode_update:
                CTRACE("update");
+               if (client->view->rdclass != dns_rdataclass_in) {
+                       ns_client_error(client, DNS_R_NOTIMP);
+                       break;
+               }
 #ifdef HAVE_DNSTAP
                dns_dt_send(client->view, DNS_DTTYPE_UQ, &client->peeraddr,
                            &client->destsockaddr, transport_type, NULL,
@@ -2423,6 +2427,10 @@ ns_client_request_continue(void *arg) {
                break;
        case dns_opcode_notify:
                CTRACE("notify");
+               if (client->view->rdclass != dns_rdataclass_in) {
+                       ns_client_error(client, DNS_R_NOTIMP);
+                       break;
+               }
                ns_client_settimeout(client, 60);
                ns_notify_start(client, client->handle);
                break;
index 031efef0a1049faf51c9669ed923847a3ce49f8b..dbd53203674317595130477ac90fc744b1bfa769 100644 (file)
@@ -997,7 +997,9 @@ ssu_checkrr(void *data, rr_t *rr) {
                RUNTIME_CHECK(result == ISC_R_SUCCESS);
                target = &ptr.ptr;
        }
-       if (rr->rdata.type == dns_rdatatype_srv) {
+       if (rr->rdata.rdclass == dns_rdataclass_in &&
+           rr->rdata.type == dns_rdatatype_srv)
+       {
                result = dns_rdata_tostruct(&rr->rdata, &srv, NULL);
                RUNTIME_CHECK(result == ISC_R_SUCCESS);
                target = &srv.target;
@@ -1352,7 +1354,10 @@ replaces_p(dns_rdata_t *update_rr, dns_rdata_t *db_rr) {
                        return true;
                }
        }
-       if (db_rr->type == dns_rdatatype_wks) {
+
+       if (db_rr->rdclass == dns_rdataclass_in &&
+           db_rr->type == dns_rdatatype_wks)
+       {
                /*
                 * Compare the address and protocol fields only.  These
                 * form the first five bytes of the RR data.  Do a
@@ -1495,8 +1500,7 @@ cleanup:
  * 'rdata', and 'ttl', respectively.
  */
 static void
-get_current_rr(dns_message_t *msg, dns_section_t section,
-              dns_rdataclass_t zoneclass, dns_name_t **name,
+get_current_rr(dns_message_t *msg, dns_section_t section, dns_name_t **name,
               dns_rdata_t *rdata, dns_rdatatype_t *covers, dns_ttl_t *ttl,
               dns_rdataclass_t *update_class) {
        dns_rdataset_t *rdataset;
@@ -1512,7 +1516,7 @@ get_current_rr(dns_message_t *msg, dns_section_t section,
        dns_rdataset_current(rdataset, rdata);
        INSIST(dns_rdataset_next(rdataset) == ISC_R_NOMORE);
        *update_class = rdata->rdclass;
-       rdata->rdclass = zoneclass;
+       rdata->rdclass = dns_rdataclass_in;
 }
 
 /*%
@@ -1612,7 +1616,6 @@ send_update(ns_client_t *client, dns_zone_t *zone) {
        dns_message_t *request = client->message;
        isc_mem_t *mctx = client->manager->mctx;
        dns_aclenv_t *env = client->manager->aclenv;
-       dns_rdataclass_t zoneclass;
        dns_rdatatype_t covers;
        dns_name_t *zonename = NULL;
        unsigned int *maxbytype = NULL;
@@ -1624,11 +1627,13 @@ send_update(ns_client_t *client, dns_zone_t *zone) {
 
        CHECK(dns_zone_getdb(zone, &db));
        zonename = dns_db_origin(db);
-       zoneclass = dns_db_class(db);
        dns_zone_getssutable(zone, &ssutable);
        options = dns_zone_getoptions(zone);
        dns_db_currentversion(db, &ver);
 
+       /* Updates are only supported for class IN. */
+       INSIST(dns_zone_getclass(zone) == dns_rdataclass_in);
+
        /*
         * Update message processing can leak record existence information
         * so check that we are allowed to query this zone.  Additionally,
@@ -1678,13 +1683,13 @@ send_update(ns_client_t *client, dns_zone_t *zone) {
 
                INSIST(ssutable == NULL || update < maxbytypelen);
 
-               get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name,
-                              &rdata, &covers, &ttl, &update_class);
+               get_current_rr(request, DNS_SECTION_UPDATE, &name, &rdata,
+                              &covers, &ttl, &update_class);
 
                if (!dns_name_issubdomain(name, zonename)) {
                        FAILC(DNS_R_NOTZONE, "update RR is outside zone");
                }
-               if (update_class == zoneclass) {
+               if (update_class == dns_rdataclass_in) {
                        /*
                         * Check for meta-RRs.  The RFC2136 pseudocode says
                         * check for ANY|AXFR|MAILA|MAILB, but the text adds
@@ -1698,6 +1703,7 @@ send_update(ns_client_t *client, dns_zone_t *zone) {
                                CHECK(DNS_R_REFUSED);
                        }
                        if ((options & DNS_ZONEOPT_CHECKSVCB) != 0 &&
+                           rdata.rdclass == dns_rdataclass_in &&
                            rdata.type == dns_rdatatype_svcb)
                        {
                                result = dns_rdata_checksvcb(name, &rdata);
@@ -1785,7 +1791,6 @@ send_update(ns_client_t *client, dns_zone_t *zone) {
                        }
 
                        if (update_class == dns_rdataclass_any &&
-                           zoneclass == dns_rdataclass_in &&
                            (rdata.type == dns_rdatatype_ptr ||
                             rdata.type == dns_rdatatype_srv))
                        {
@@ -2717,7 +2722,6 @@ update_action(void *arg) {
        isc_mem_t *mctx = client->manager->mctx;
        dns_rdatatype_t covers;
        dns_message_t *request = client->message;
-       dns_rdataclass_t zoneclass;
        dns_name_t *zonename = NULL;
        dns_fixedname_t tmpnamefixed;
        dns_name_t *tmpname = NULL;
@@ -2734,9 +2738,10 @@ update_action(void *arg) {
 
        CHECK(dns_zone_getdb(zone, &db));
        zonename = dns_db_origin(db);
-       zoneclass = dns_db_class(db);
        options = dns_zone_getoptions(zone);
 
+       INSIST(dns_zone_getclass(zone) == dns_rdataclass_in);
+
        is_inline = (!dns_zone_israw(zone) && dns_zone_issecure(zone));
        is_maintain = ((dns_zone_getkeyopts(zone) & DNS_ZONEKEY_MAINTAIN) != 0);
        is_signing = is_inline || (!is_inline && is_maintain);
@@ -2761,8 +2766,8 @@ update_action(void *arg) {
                dns_rdataclass_t update_class;
                bool flag;
 
-               get_current_rr(request, DNS_SECTION_PREREQUISITE, zoneclass,
-                              &name, &rdata, &covers, &ttl, &update_class);
+               get_current_rr(request, DNS_SECTION_PREREQUISITE, &name, &rdata,
+                              &covers, &ttl, &update_class);
 
                if (ttl != 0) {
                        PREREQFAILC(DNS_R_FORMERR,
@@ -2825,7 +2830,7 @@ update_action(void *arg) {
                                                "prerequisite not satisfied");
                                }
                        }
-               } else if (update_class == zoneclass) {
+               } else if (update_class == dns_rdataclass_in) {
                        /* "temp<rr.name, rr.type> += rr;" */
                        result = temp_append(&temp, name, &rdata);
                        if (result != ISC_R_SUCCESS) {
@@ -2887,10 +2892,10 @@ update_action(void *arg) {
 
                INSIST(ssutable == NULL || update < maxbytypelen);
 
-               get_current_rr(request, DNS_SECTION_UPDATE, zoneclass, &name,
-                              &rdata, &covers, &ttl, &update_class);
+               get_current_rr(request, DNS_SECTION_UPDATE, &name, &rdata,
+                              &covers, &ttl, &update_class);
 
-               if (update_class == zoneclass) {
+               if (update_class == dns_rdataclass_in) {
                        /*
                         * RFC1123 doesn't allow MF and MD in master files.
                         */