Commit graph

15945 commits

Author SHA1 Message Date
Ondřej Surý
abe201bac3 Do not reuse shared TCP dispatches for zone transfers
Zone transfers (XFRIN) need a dedicated TCP connection because they
are long-lived and stream the entire zone.

(cherry picked from commit 6e78094ebd)
2026-05-06 15:05:48 +02:00
Ondřej Surý
4f54328eaf Use sequential per-dispatch message IDs for TCP
TCP dispentries no longer use the global QID hash table at all.
Responses are matched by scanning disp->active, and sequential
per-dispatch IDs (bounded by the pipelining limit) are unique
within a single dispatch by construction.  Since TCP delivers
only data we asked for on a specific connection, the per-peer
uniqueness that the global table enforced was never actually
needed for TCP.

DNS_DISPATCHOPT_FIXEDID is plumbed through dns_request_createraw
-> get_dispatch -> dns_dispatch_createtcp so FIXEDID TCP requests
always get a fresh isolated dispatch — the caller-supplied ID
then cannot collide with any other in-flight query either.

(cherry picked from commit 3e364aec2b)
2026-05-06 15:05:48 +02:00
Ondřej Surý
a3ba799eae Limit TCP pipelining per shared dispatch
Cap the number of in-flight queries on a single shared TCP dispatch.
When the limit is reached, the dispatch is removed from the hash
table so subsequent queries get a fresh connection.  The existing
dispatch continues serving its queries until they complete.

This bounds the blast radius of a connection drop: at most N queries
fail simultaneously instead of all queries to that server.

The default limit is 256.  It can be overridden for testing via
'named -T tcppipelining=N'.

(cherry picked from commit 385ceabe8f)
2026-05-06 15:05:48 +02:00
Ondřej Surý
d35bc843c5 Implement seamless TCP connection reuse in dns_dispatch
Previously, the user of dns_dispatch API had to first call
dns_dispatch_gettcp() and if that failed create a new TCP dispatch with
dns_dispatch_createtcp().  This has been changed and the TCP connection
reuse happens transparently inside dns_dispatch_createtcp().  There are
separate buckets for dns_resolver, dns_request and dns_xfrin units, so
these don't get mixed together.

(cherry picked from commit d5ee86b799)
2026-05-06 15:05:48 +02:00
Evan Hunt
3db5d47ed4 Hold a reference to the NTA table for the lifetime of each NTA
Each dns__nta_t now references its parent ntatable in nta_create() and
releases it in dns__nta_destroy().  This avoids a use-after-free in
fetch_done() and other callbacks that dereference nta->ntatable: the
ntatable could otherwise be released by view destruction while an
in-flight resolver fetch still holds a reference to the NTA.

(cherry picked from commit 26c895cc92)
2026-05-06 09:33:11 +02:00
Evan Hunt
d42b3e7b91 Clear dns64_aaaaok immediately after use
The DNS64 state information stored in client->query.dns64_aaaaok
could cause an assertion failure in query_respond() if the server
was configured in such a way as to trigger a new recursion before
the query had been reset - for example, by using the filter-aaaa
plugin, which may need to recurse to find out whether an A record
exists.

This has been addressed by clearing DNS64 state information
immediately after the call to query_filter64().

(cherry picked from commit 7213b038f0)
2026-05-06 04:47:07 +00:00
Evan Hunt
8e31dc5353 Fix a stack use-after-free in qpzone
In previous_closest_nsec(), a new qpreader was opened to search the NSEC
tree. It was possible for that to be used to update a QP iterator object
owned by the caller, and then be destroyed when the function returned.

This has been addressed by having the caller open the NSEC qpreader
instead.
2026-05-05 16:17:25 -07:00
Ondřej Surý
2bbbd60de3
Reject oversized RRsets at slab construction
dns_rdataslab_fromrdataset(), dns_rdataslab_merge() and
dns_rdataslab_subtract() summed per-record storage into an
unsigned int with no upper-bound check.  An RRset whose total
encoded size exceeds DNS_RDATA_MAXLENGTH cannot fit in a DNS
message and is unservable; building its in-memory representation
only burns memory on data that will fail at response time, and at
the upper bound the running sum could in theory wrap.

Cap the running total at DNS_RDATA_MAXLENGTH and return ISC_R_NOSPACE
when exceeded.  Update the qpdb cache memory-purge test to use a
record size that fits within the new limit.

Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit f9d24b1b85)
2026-05-05 19:24:29 +02:00
Evan Hunt
0af1b07aad
Remove DNS_KEYFLAG_EXTENDED
The DNS_KEYFLAG_EXTENDED flag was only legitimate for type KEY
and was eliminated by RFC 3445. Dropping the extended-flags
handling in pub_compare() also fixes a possible crash when
signing a zone whose journal contains a crafted DNSKEY: a
6-byte record with the EXTENDED bit set produced a memmove()
length that underflowed and ran off a stack buffer.

(cherry picked from commit 9c06f0a41d)
2026-05-05 11:07:32 +02:00
Ondřej Surý
19f44a0aa3
Tidy up cleanup path in check_signer()
The cloned signature rdataset was not disassociated on the early
return taken when dns_dnssec_keyfromrdata() fails to parse the DNSKEY
public-key data.  In every current caller val->sigrdataset reaches
check_signer() rdatalist-backed, so dns_rdataset_clone() copies the
struct without taking any reference and dns_rdataset_disassociate()
is a no-op -- no memory is actually leaked today.  Hoist the key
parse out of the per-RRSIG loop and let the function fall through
to a single cleanup path, so the parse and the iteration cannot
diverge again.

Assisted-by: Claude:claude-opus-4-7
2026-05-05 07:43:15 +02:00
Ondřej Surý
0f821104e0
Use a keyed hash for the RRL bucket table
The previous hash_key() was a deterministic, unkeyed (<<1) + add over the
key words.  An off-path attacker could invert it offline and submit
queries whose source /24, qname hash, and qtype map to a single bucket;
under chaining this turns every lookup into an O(N) walk under
rrl->lock and starves legitimate query processing on the very feature
deployed to mitigate DoS.

Replace it with isc_hash32(), which is HalfSipHash-2-4 keyed by a
per-process random seed, so collision sets cannot be precomputed.

Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit a6b7ce29c4)
2026-05-04 16:15:58 +02:00
Ondřej Surý
2b18aa9d59 Reject RSA DNSKEYs with oversize public exponents at parse time
The wire-format RSA DNSKEY parser was the only key path with no upper
bound on the public exponent — opensslrsa_parse and opensslrsa_fromlabel
already cap at RSA_MAX_PUBEXP_BITS.  An attacker-controlled DNSKEY could
therefore force a validator to compute s^e mod n with e up to ~|n| bits,
amplifying every verify by ~120x for typical 2048-bit moduli (OpenSSL
itself only caps the exponent for moduli above 3072 bits).  Apply the
same bit-count cap to wire-format keys.

Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit ab8c1a77e0)
2026-04-30 13:16:30 +02:00
Ondřej Surý
9a15d2c973
Dispatch ratelimiter events under the lock
isc__ratelimiter_tick() and isc_ratelimiter_shutdown() each pulled
events out of rl->pending into a function-local list, dropped the
mutex, and then iterated.  ISC_LIST_APPEND leaves the link in the
LINKED state, so a concurrent isc_ratelimiter_dequeue() saw an
event as still queued, called ISC_LIST_UNLINK against rl->pending —
which patched the prev/next of the local list — and freed the
event before dispatch finished, producing either an INSIST in the
unlink macro or a use-after-free in the dispatch loop.

isc_async_run() is a non-blocking wfcq enqueue, so there is no
benefit to dropping the mutex around it.  Unlink each event and
hand it to isc_async_run() while still holding rl->lock; the
existing ISC_LINK_LINKED check in dequeue then correctly
distinguishes "still queued and cancellable" from "already taken".

Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit 4d465f4fa5)
2026-04-30 10:53:49 +02:00
Ondřej Surý
36897a0872 Fix swapped arguments in redirect2() single-label branch
For a query whose qname is the root, the labels==1 branch in
redirect2() called dns_name_copy(redirectname, view->redirectzone)
with arguments reversed, overwriting the view-global
nxdomain-redirect target with the empty redirectname rather than
copying the configured target into the per-query lookup name.  After
the corruption, view->redirectzone names the root, so
dns_name_issubdomain() makes redirect2() short-circuit for every
subsequent query and the nxdomain-redirect feature stops working
until named is restarted.

Triggering this needs the resolver to receive an NXDOMAIN for the
root from upstream, which does not happen in normal DNS operation.

Swap the arguments to match the dns_name_copy(source, dest)
signature.  Add a system test that issues a root query through the
nxdomain-redirect resolver and verifies the redirect feature still
works for a normal NXDOMAIN-producing query afterwards.

Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit c62f24f7ee)
2026-04-30 07:38:57 +02:00
Ondřej Surý
45ea92ea4b
Size HMAC key generation buffers to the maximum block size
hmac_generate() declared its on-stack nonce buffer as
unsigned char data[ISC_MAX_MD_SIZE], i.e. 64 bytes. That is the maximum
digest size, but the buffer is filled up to the algorithm's HMAC block
size, which is 128 bytes for SHA-384 and SHA-512. Asking rndc-confgen
for an HMAC-SHA-384 or HMAC-SHA-512 key with -b > 512 (the documented
range allows up to 1024) wrote past the end of the stack buffer; on
hardened builds this aborted with a stack-smash detector firing
instead of producing a key.

Use the existing ISC_MAX_BLOCK_SIZE (128) for the buffer so the full
1..1024 range advertised by -A hmac-sha{384,512} works as documented.
The matching key_rawsecret[64] in confgen's generate_key() is enlarged
the same way so the generated key fits when dumped to the buffer.

Add a system test that exercises rndc-confgen across the previously
overflowing keysizes; with -Db_sanitize=address it caught the abort
before the fix.

Assisted-by: Claude:claude-opus-4-7
(cherry picked from commit 46f6bb6364)
2026-04-30 06:00:07 +02:00
Ondřej Surý
1a93486cde Refuse SIG and NXT records in dynamic updates
SIG (24) and NXT (30) are obsolete DNSSEC record types, superseded by
RRSIG and NSEC in RFC 3755.  Allowing them through dynamic update
exposes two distinct bugs that the surrounding GL#5818 work already
fixes as defense-in-depth:

  - dns__db_findrdataset() used to REQUIRE that (covers == 0 ||
    type == RRSIG), which aborts named when a SIG update reaches the
    prescan foreach_rr() call.  Fixed to accept dns_rdatatype_issig().
  - diff.c rdata_covers() used to test only RRSIG, dropping the
    covered-type field for SIG rdatas; the zone DB then filed every
    SIG rdataset under typepair (SIG, 0) instead of
    (SIG, covered_type) and follow-up adds collided at that bucket.
    Fixed to use dns_rdatatype_issig().

Both underlying bugs are still reachable via inbound zone transfer
(diff.c rdata_covers() runs from both dns_diff_apply on the IXFR path
and dns_diff_load on the AXFR path), so the type-helper fixes above
remain necessary.  For the dynamic-update path, the simplest and
safest posture is to refuse SIG and NXT outright at the front door in
ns/update.c, alongside the existing NSEC/NSEC3/non-apex-RRSIG
refusals.  KEY remains permitted because it is still used to carry
public keys for SIG(0) transaction authentication.

The existing tcp-self SIG regression test is repointed to assert
REFUSED on the SIG add, a symmetric NXT test is added, and the
SIG-via-dyn-update covers-bucket test is removed because it is no
longer reachable through this entry point; AXFR-based coverage of
diff.c rdata_covers() follows in a separate commit.

(cherry picked from commit 3a44a13232)
2026-04-17 19:24:13 +02:00
Ondřej Surý
2c2533774c Fix dropped covers field for SIG records in dns_diff_apply
rdata_covers() in lib/dns/diff.c discriminated only on
dns_rdatatype_rrsig (46) and returned 0 for the legacy SIG (24), so
the covered-type field was silently discarded on the dynamic-update
and IXFR paths.  Every SIG rdataset was then filed in the zone DB
under typepair (SIG, 0) instead of (SIG, covered_type); a second SIG
add with a different covers but a different TTL collided at that
bucket, tripped DNS_DBADD_EXACTTTL in qpzone, returned
DNS_R_NOTEXACT, and came back to the client as SERVFAIL.

Use dns_rdatatype_issig() here so both SIG and RRSIG carry their
covers through the diff, matching the helper pattern already used in
lib/dns/master.c, lib/ns/xfrout.c, lib/dns/qpcache.c, and the
dns__db_findrdataset() REQUIRE that the surrounding merge request
just relaxed.

(cherry picked from commit 0a5ba57116)
2026-04-17 19:24:13 +02:00
Mark Andrews
62920a981f Fix assertion failure in dns_db_findrdataset() for SIG records
dns__db_findrdataset() had a REQUIRE() that only accepted
dns_rdatatype_rrsig when the covers parameter was set.  A dynamic
update containing a SIG record (type 24) would trigger this
assertion, crashing named.  Use dns_rdatatype_issig() to accept
both SIG and RRSIG.

(cherry picked from commit 03edeccaa1)
2026-04-17 19:24:13 +02:00
Mark Andrews
35a5e29800 Remove unnecessary dns_name_free call
When processing a catalog zone member's primaries definition and
there is a TXT record containing an invalid name TSIG key name,
dns_name_free was incorrectly called triggering an assertion.
This has been fixed.

(cherry picked from commit 9f411c93c4)
2026-04-15 12:30:22 +10:00
Mark Andrews
6d38c398c8 Use the correct maximal compressed bit map buffer size
There are up to 256 windows in a NSEC/NSEC3 compressed bit
map of 32 + 2 octets each.

(cherry picked from commit e43e4bd20a)
2026-04-10 06:23:53 +00:00
Matthijs Mekking
f58554d05a Rename isdelegation() to is_insecure_referral()
The name 'isdelegation()' was confusing. This function is not checking
whether this message is a delegation, but whether the denial of
existence proofs in this message is a proof of a referral to an
unsigned zone.

The name 'is_unsecure_referral()' is more appropriate.

(cherry picked from commit e0f09bb374)
2026-04-07 09:44:30 +02:00
Matthijs Mekking
bd852b1f97 Revert isdelegation() to return boolean value again
The isdelegation() was changed to return an isc_result_t because the
idea was to have a separate return value DNS_R_NSEC3ITERRANGE to signal
to the caller we could not verify the proof because of too many
iterations in the NSEC3 record, or perhaps ISC_R_UNEXPECTED for a more
generic cause that verification was not done.

But this would make error handling more fragile and all we care about
is whether we can reliably say the NS bit was not set.

If we can not reliably say so, we have to treat it as an insecure
referrral.

Since the answer is either yes or no, we can revert back to returning
a boolean value.

(cherry picked from commit 3ac1bb1c39)
2026-04-07 09:44:19 +02:00
Aram Sargsyan
913f290e75 Fix a race condition in xfrin_recv_done() when calling xfrin_reset()
When the xfrin_recv_done() function decides to retry the transfer
using AXFR because of a previous error, it calls the xfrin_reset()
function which calls dns_db_closeversion() on 'xfr->ver'. The problem
is that the ixfr processing of a previous message could be still
in process in a worker thread, which then can use freed 'xfr->ver'.

If there is an ongoing worker thread delay the AXFR retry until after
the worker thread has finished its work.

(cherry picked from commit 141ff7bfa7)
2026-04-03 12:05:44 +00:00
Ondřej Surý
98f5caea05 Fix INSIST copy-paste error checking RADIX_V4 instead of RADIX_V6
The INSIST in isc_radix_insert() checks node->data[RADIX_V4] and
node->node_num[RADIX_V4] twice due to a copy-paste error, never
verifying the RADIX_V6 fields.

Fix the second pair to check RADIX_V6.

(cherry picked from commit 3f15f2d9e5)
2026-03-30 19:01:29 +02:00
Ondřej Surý
bd3c7d8014
Count temporal problems with DNSSEC validation as attempts
After KeyTrap, the temporal DNSSEC were originally hard errors that
caused validation failures even if the records had another valid
signature.  This has been changed and the RRSIGs outside of the
inception and expiration time are not counted as hard errors.  However,
these errors are not even counted as validation attempts, so excessive
number of expired RRSIGs would cause some non-cryptograhic extra work
for the validator.  This has been fixed and the temporal errors are
correctly counted as validation attempts.

(cherry picked from commit 6ba57a1f0f)
2026-03-30 13:07:15 +02:00
Mark Andrews
8a3408c3b1 Allow the dns_rdata_in_apl structure to be walked twice
The offset value should be set prior to calculating the length.

(cherry picked from commit f2fd54f4b2)
2026-03-27 12:38:01 +00:00
Aram Sargsyan
dbd86cb6d2 Allow empty APL records
Allow empty APL records because RFC 3123 (Section 4) says "zero or
more items". This fixes processing of a catalog zone ACL (which is
based on APL records) when the zone contains an empty APL record or
when a zone update arrives which creates an empty APL record.

(cherry picked from commit 35b8af229e)
2026-03-27 12:38:00 +00:00
Ondřej Surý
feb5dc7f98 Add regression test for TOCTOU race in DNS UPDATE SSU handling
Race rndc reconfig (toggling between allow-update and update-policy)
against a stream of DNS UPDATEs for 5 seconds and verify that named
does not crash.

Before the fix, the race between send_update() and update_action()
reading the SSU table independently could trigger an assertion
failure (INSIST) when the zone's update policy changed between the
two reads.

(cherry picked from commit c503b6eee8)
2026-03-25 16:16:22 +01:00
Ondřej Surý
c409b9a939 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 c172416559)
2026-03-25 16:16:22 +01:00
Michał Kępień
b040b566fe Merge tag 'v9.20.21' into bind-9.20 2026-03-25 14:24:13 +00:00
Ondřej Surý
8feefb9874 Add MOVE_OWNERSHIP() macro for transferring pointer ownership
A helper macro that returns the current value of a pointer and sets
it to NULL in one expression, useful for transferring ownership in
designated initializers.

(cherry picked from commit 0f3be0beb8)
2026-03-23 12:05:30 +01:00
Ondřej Surý
d3965a91b6 Replace existing NTA instead of reusing it in dns_ntatable_add()
When an NTA already exists for a name, the old code retrieved
and reused the existing NTA object, then reset its timer via
settimer().  This is incorrect because isc_timer_start() and
isc_timer_stop() require the timer to be manipulated from its
owning loop (enforced by REQUIRE(timer->loop == isc_loop()) in
lib/isc/timer.c), and the caller may be running on a different
loop than the one that created the original NTA.

Instead, delete the old NTA (shutting down its timer on the
correct loop) and insert a fresh one that is owned by the
current loop.
2026-03-23 08:31:32 +00:00
Ondřej Surý
33d219bfe1 SKIP cache flush ordering on NTA expiry
dns_view_flushnode() was called in the delete_expired() async
callback, which runs after the query that detected the NTA expiry.
This created a race: the query would proceed with stale cached data
from the NTA period before the flush had a chance to run, resulting
in transient SERVFAIL with EDE 22 (No Reachable Authority).

Skip dns_view_flushnode() in the older branches as the solutions for
older branches are too complicated and this was not a critical bug.

(cherry picked from commit da8e1c956a)
2026-03-23 08:31:32 +00:00
Aram Sargsyan
567c170b0c Flush the node when NTA expires
When NTA expires the name's node should be flushed from the view's
cache as it's done when the NTA is manually removed using a rndc
command.

(cherry picked from commit 1899a3318c)
2026-03-20 03:24:56 +01:00
Ondřej Surý
993002cebf Fix data race on fctx->vresult in validated()
Move the write to fctx->vresult after LOCK(&fctx->lock).  The field was
being set before acquiring the lock, but dns_resolver_logfetch() reads
it under the same lock from another thread.

(cherry picked from commit a2bd833909)
2026-03-20 03:22:53 +01:00
Ondřej Surý
fb8a9e73cc Fix non-atomic read-modify-write on entry->srtt in adjustsrtt()
The SRTT update loaded the old value, computed a new one, and stored it
back as separate operations.  Two concurrent callers could each read the
same old value and one update would be silently lost.

Use a CAS loop for the read-modify-write on entry->srtt.  For the aging
path, also CAS on entry->lastage to prevent multiple threads from aging
the same entry in the same second.

(cherry picked from commit 4d15494b94)
2026-03-20 01:06:56 +00:00
Aram Sargsyan
99b583592e Take 'env' reference before async calling perform_reopen()
The 'env' pointer is passed to an async function without taking
a reference first, which can potentially cause a use-after-free
error. Take a reference, then detach in the async function.

(cherry picked from commit 48d7401f0d)
2026-03-18 17:04:56 +00:00
Aram Sargsyan
77d60acb86 Convert dns_dtenv_t reference counting to standard macors
Use standard reference counting macros for dns_dtenv_t instead of
custom attach/detach functions.

(cherry picked from commit 4ac3a6520e)
2026-03-18 17:04:56 +00:00
Ondřej Surý
d685d448e2 Fix isc_buffer_init capacity mismatch in DoH data chunk callback
isc_buffer_init() is given MAX_DNS_MESSAGE_SIZE (65535) as capacity but
only h2->content_length bytes are allocated.  This makes the buffer
believe it has more space than actually allocated.  A secondary bounds
check (new_bufsize <= h2->content_length) prevents actual overflow, but
the buffer invariant is violated.

Pass h2->content_length as the capacity to match the allocation.

(cherry picked from commit 8e240bbb5f)
2026-03-18 10:39:38 +00:00
Ondřej Surý
b0e8f5ec65
Fix missing mutex destroy and ede invalidate on fctx_create() error paths
The error cleanup in fctx_create() was missing isc_mutex_destroy() and
dns_ede_invalidate() calls. When error paths (cleanup_nameservers,
cleanup_fcount, cleanup_qmessage, cleanup_adb) were taken after the
mutex and edectx were initialized, the fctx memory was freed without
properly destroying these resources first.

(cherry picked from commit 5b1750f15f)
2026-03-17 23:26:28 +01:00
Ondřej Surý
0b9f45c0ff
Fix rwlock type mismatch in delete_ds() error path
The lock is acquired for reading but the error path from
dns_rdata_fromstruct() incorrectly unlocks it as a write lock.

(cherry picked from commit 96a22451d7)
2026-03-17 23:25:21 +01:00
Matthijs Mekking
e65298edb2 Fast fail a validator deadlock
We return DNS_R_NOVALIDSIG if we detected a deadlock. Then in
'validate_async_done()', this result value is used to check if we
need to fall back to insecure. As part of that we create a new fetch
but that fails because of the detected deadlock. This results in a loop
of deadlock detected, fallback to insecure, deadlock detected, ...

Add a new result value, ISC_R_DEADLOCK, and return this instead when
we have detected a deadlock. This will be treated as a generic error,
as there is no special handling for this result value.

(cherry picked from commit bc1d177cc2)
2026-03-17 14:39:48 +00:00
Mark Andrews
0fb1e5c865 Clear errno before calling strtol
The previous code was incorrectly clearing errno after calling
strtol but before testing the result rather than clearing it and
then calling strtol so that changes to errno can be correctly
determined.

(cherry picked from commit d3ffa1f007)
2026-03-17 00:28:07 +00:00
Ondřej Surý
07e1042108 Fix use-after-free in xfrin_recv_done
Move the LIBDNS_XFRIN_RECV_DONE probe execution before dns_xfrin_detach
in xfrin_recv_done.

Previously, dns_xfrin_detach was called before the trace probe, which
could free the xfr object.  Because the accessed member xfr->info is an
embedded array, the expression evaluates via pointer arithmetic rather
than a direct memory dereference.  Although this prevents a reliable
crash in practice, it technically remains a use-after-free issue.
Reorder the statements to ensure the transfer context is fully valid
when the probe executes.

(cherry picked from commit e57245ee81)
2026-03-16 12:00:04 +01:00
Aram Sargsyan
9a7ae56032 OpenSSL 4 compatibility fix
Starting from OpenSSL 4 the the X509_get_subject_name() function
returns a 'const' pointer to a name instead of a regular pointer.
Duplicate the name before operating on it, then free it.

(cherry picked from commit 336c523b79)
2026-03-16 10:56:17 +00:00
Ondřej Surý
338961bf7e
Fix KASP key leaks on keystore lookup failure
In both cfg_kasp_fromconfig() and cfg_kasp_builtinconfig(), the
newly allocated KASP key was not destroyed when the keystore
lookup failed.

(cherry picked from commit df1993611b)
2026-03-16 11:05:03 +01:00
Ondřej Surý
769dff3e6f
Fix missing server socket detach in TLS accept error path
When TLS creation fails in tlslisten_acceptcb(), tlssock->server
was not detached before detaching tlssock itself.

(cherry picked from commit 2ab3d7c075)
2026-03-16 11:05:03 +01:00
Ondřej Surý
f907b229d3
Simplify checkds_create() to return void
Since memory allocation never fails in BIND 9, checkds_create() cannot
fail.  Change it to return void and use designated initializers,
removing error handling at all call sites.

(cherry picked from commit 63d3c1f58a)
2026-03-16 11:04:58 +01:00
Ondřej Surý
dc419568d1
Fix cb_args memory leak in ns_query() error path
Initialize cb_args to NULL and free it in the cleanup path so it
is not leaked when the function fails after allocation.

(cherry picked from commit d7e1013741)
2026-03-16 10:50:22 +01:00
Ondřej Surý
109d100495
Fix TSIG key and transport leaks in zone_notify() error paths
Two 'goto next' paths in zone_notify() skipped detaching the TSIG
key and transport, leaking them on TLS configuration failure and
when the destination address is disabled.

(cherry picked from commit 1505cb1c24)
2026-03-16 10:50:22 +01:00