From: Ondřej Surý Date: Wed, 18 Mar 2026 02:55:51 +0000 (+0100) Subject: Fix TOCTOU race in DNS UPDATE SSU table handling X-Git-Tag: v9.20.22~8^2~1 X-Git-Url: http://git.ipfire.org/gitweb.cgi?a=commitdiff_plain;h=c409b9a9393d5c8392664554d787da48c982cde5;p=thirdparty%2Fbind9.git 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) --- diff --git a/lib/ns/update.c b/lib/ns/update.c index bd5cac26231..1314889d7d8 100644 --- a/lib/ns/update.c +++ b/lib/ns/update.c @@ -201,6 +201,7 @@ struct update { ns_client_t *client; isc_result_t result; dns_message_t *answer; + dns_ssutable_t *ssutable; unsigned int *maxbytype; size_t maxbytypelen; }; @@ -1857,14 +1858,14 @@ send_update(ns_client_t *client, dns_zone_t *zone) { *uev = (update_t){ .zone = zone, .client = client, - .maxbytype = maxbytype, + .ssutable = TAKE_OWNERSHIP(ssutable), + .maxbytype = TAKE_OWNERSHIP(maxbytype), .maxbytypelen = maxbytypelen, .result = ISC_R_SUCCESS, }; isc_nmhandle_attach(client->handle, &client->updatehandle); isc_async_run(dns_zone_getloop(zone), update_action, uev); - maxbytype = NULL; cleanup: if (db != NULL) { @@ -2697,6 +2698,7 @@ update_action(void *arg) { update_t *uev = (update_t *)arg; dns_zone_t *zone = uev->zone; ns_client_t *client = uev->client; + dns_ssutable_t *ssutable = uev->ssutable; unsigned int *maxbytype = uev->maxbytype; size_t update = 0, maxbytypelen = uev->maxbytypelen; isc_result_t result; @@ -2711,7 +2713,6 @@ update_action(void *arg) { 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; @@ -2728,7 +2729,6 @@ update_action(void *arg) { 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); is_inline = (!dns_zone_israw(zone) && dns_zone_issecure(zone));