Fix use-after-free in resolver SIG(0) async verification path

When a SIG(0)-signed response triggers async ECDSA verification via
dns_message_checksig_async(), the respctx_t holds a raw pointer to
the resquery_t. If the fetch context is shut down while verification
is in flight (e.g. due to recursive-clients quota exhaustion), the
query is destroyed and the callback dereferences a dangling pointer.

Take a reference on the resquery_t when initializing the respctx_t,
and release it in both cleanup paths. The query's own reference to
the fetch context keeps the fctx alive transitively.
This commit is contained in:
Ondřej Surý 2026-03-17 04:45:16 +01:00 committed by Michał Kępień
parent e249148d75
commit a6f53d47b2
No known key found for this signature in database

View file

@ -7543,6 +7543,7 @@ resquery_response(isc_result_t eresult, isc_region_t *region, void *arg) {
return;
cleanup:
resquery_detach(&rctx->query);
isc_mem_putanddetach(&rctx->mctx, rctx, sizeof(*rctx));
}
@ -7903,6 +7904,7 @@ resquery_response_continue(void *arg, isc_result_t result) {
rctx_done(rctx, result);
cleanup:
resquery_detach(&rctx->query);
isc_mem_putanddetach(&rctx->mctx, rctx, sizeof(*rctx));
}
@ -7916,7 +7918,7 @@ static void
rctx_respinit(resquery_t *query, fetchctx_t *fctx, isc_result_t result,
isc_region_t *region, respctx_t *rctx) {
*rctx = (respctx_t){ .result = result,
.query = query,
.query = resquery_ref(query),
.fctx = fctx,
.broken_type = badns_response,
.retryopts = query->options };