]> 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:21:59 +0000 (13:21 +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 307f10cee3c0bfeca0f4b17c525c61ed6fdb552c..43c4023fb7b9bc656c36dabfb0696514773a25e9 100644 (file)
@@ -1987,10 +1987,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 87fc357cd880c54eea28e5e65312defa48ecf560..21ae217a384a396a78e7d61ccd9ad72632558a1e 100644 (file)
@@ -949,7 +949,7 @@ import_rdataset(dns_adbname_t *adbname, dns_rdataset_t *rdataset,
        INSIST(DNS_ADB_VALID(adb));
 
        rdtype = rdataset->type;
-       INSIST((rdtype == dns_rdatatype_a) || (rdtype == dns_rdatatype_aaaa));
+       REQUIRE(rdtype == dns_rdatatype_a || rdtype == dns_rdatatype_aaaa);
 
        addr_bucket = DNS_ADB_INVALIDBUCKET;
        new_addresses_added = false;
index 97e99019a40985672fcda631f8a01bc9d8a02ad6..4c538f5f9ff1a9e1a011dc2619651188b76b3e0e 100644 (file)
@@ -2337,6 +2337,10 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
                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, TCP_CLIENT(client), NULL,
@@ -2347,6 +2351,10 @@ ns__client_request(isc_nmhandle_t *handle, isc_result_t eresult,
                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, handle);
                break;
index 415836fd1313e2c2e97d14305fcb3790a6e8bd60..d002019fdf55298445f65746da86c3ba5a3d0f50 100644 (file)
@@ -999,7 +999,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;
@@ -1354,7 +1356,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
@@ -1497,8 +1502,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;
@@ -1514,7 +1518,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;
 }
 
 /*%
@@ -1616,7 +1620,6 @@ send_update_event(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;
@@ -1626,10 +1629,12 @@ send_update_event(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);
        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,
@@ -1680,13 +1685,13 @@ send_update_event(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
@@ -1776,7 +1781,6 @@ send_update_event(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))
                        {
@@ -2860,7 +2864,6 @@ update_action(isc_task_t *task, isc_event_t *event) {
        isc_mem_t *mctx = client->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;
@@ -2880,9 +2883,9 @@ update_action(isc_task_t *task, isc_event_t *event) {
 
        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);
        /*
         * Get old and new versions now that queryacl has been checked.
         */
@@ -2903,8 +2906,8 @@ update_action(isc_task_t *task, isc_event_t *event) {
                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,
@@ -2967,7 +2970,7 @@ update_action(isc_task_t *task, isc_event_t *event) {
                                                "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) {
@@ -3029,10 +3032,10 @@ update_action(isc_task_t *task, isc_event_t *event) {
 
                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.
                         */