From f6fdc77c4699db4e54165e1759e7bf3d639b30cb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= Date: Wed, 18 Mar 2026 03:55:51 +0100 Subject: [PATCH] Fix TOCTOU race in DNS UPDATE SSU table handling Pass the SSU table through the update event struct from send_update() to update_action() instead of reading it from the zone twice. If rndc reconfig changed the zone's update policy between the two reads (e.g., from allow-update to update-policy), send_update() would skip the maxbytype allocation but update_action() would see a non-NULL ssutable, triggering INSIST(ssutable == NULL || maxbytype != NULL) and crashing named. The ssutable reference is now taken once in send_update() and transferred to update_action() via the event struct, ensuring both functions see the same value. (cherry picked from commit c172416559e62a31de27061648db7ffe3b1b7f63) --- lib/ns/update.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/ns/update.c b/lib/ns/update.c index c3e4eb115d..c02535130f 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -203,6 +203,7 @@ struct update_event { dns_zone_t *zone; isc_result_t result; dns_message_t *answer; + dns_ssutable_t *ssutable; unsigned int *maxbytype; size_t maxbytypelen; }; @@ -1850,9 +1851,9 @@ send_update_event(ns_client_t *client, dns_zone_t *zone) { sizeof(*event)); event->zone = zone; event->result = ISC_R_SUCCESS; - event->maxbytype = maxbytype; + event->ssutable = MOVE_OWNERSHIP(ssutable); + event->maxbytype = MOVE_OWNERSHIP(maxbytype); event->maxbytypelen = maxbytypelen; - maxbytype = NULL; INSIST(client->nupdates == 0); client->nupdates++; @@ -2840,6 +2841,7 @@ update_action(isc_task_t *task, isc_event_t *event) { update_event_t *uev = (update_event_t *)event; dns_zone_t *zone = uev->zone; ns_client_t *client = (ns_client_t *)event->ev_arg; + dns_ssutable_t *ssutable = uev->ssutable; unsigned int *maxbytype = uev->maxbytype; size_t update = 0, maxbytypelen = uev->maxbytypelen; isc_result_t result; @@ -2854,7 +2856,6 @@ update_action(isc_task_t *task, isc_event_t *event) { dns_message_t *request = client->message; dns_rdataclass_t zoneclass; dns_name_t *zonename = NULL; - dns_ssutable_t *ssutable = NULL; dns_fixedname_t tmpnamefixed; dns_name_t *tmpname = NULL; dns_zoneopt_t options; @@ -2874,7 +2875,6 @@ 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); - dns_zone_getssutable(zone, &ssutable); options = dns_zone_getoptions(zone); /*