2
0
mirror of https://gitlab.isc.org/isc-projects/bind9 synced 2025-08-31 14:35:26 +00:00

Purge memory pool upon plugin destruction

The typical sequence of events for AAAA queries which trigger recursion
for an A RRset at the same name is as follows:

 1. Original query context is created.
 2. An AAAA RRset is found in cache.
 3. Client-specific data is allocated from the filter-aaaa memory pool.
 4. Recursion is triggered for an A RRset.
 5. Original query context is torn down.

 6. Recursion for an A RRset completes.
 7. A second query context is created.
 8. Client-specific data is retrieved from the filter-aaaa memory pool.
 9. The response to be sent is processed according to configuration.
10. The response is sent.
11. Client-specific data is returned to the filter-aaaa memory pool.
12. The second query context is torn down.

However, steps 6-12 are not executed if recursion for an A RRset is
canceled.  Thus, if named is in the process of recursing for A RRsets
when a shutdown is requested, the filter-aaaa memory pool will have
outstanding allocations which will never get released.  This in turn
leads to a crash since every memory pool must not have any outstanding
allocations by the time isc_mempool_destroy() is called.

Fix by creating a stub query context whenever fetch_callback() is called,
including cancellation events. When the qctx is destroyed, it will ensure
the client is detached and the plugin memory is freed.
This commit is contained in:
Evan Hunt
2019-05-22 10:58:41 +02:00
parent b2408003d4
commit 86eddebc83
2 changed files with 36 additions and 12 deletions

View File

@@ -365,7 +365,7 @@ static void
query_trace(query_ctx_t *qctx);
static void
qctx_init(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype,
qctx_init(ns_client_t *client, dns_fetchevent_t **eventp, dns_rdatatype_t qtype,
query_ctx_t *qctx);
static isc_result_t
@@ -5065,7 +5065,7 @@ nxrrset:
* when leaving the scope or freeing the qctx.
*/
static void
qctx_init(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype,
qctx_init(ns_client_t *client, dns_fetchevent_t **eventp, dns_rdatatype_t qtype,
query_ctx_t *qctx) {
REQUIRE(qctx != NULL);
REQUIRE(client != NULL);
@@ -5079,7 +5079,12 @@ qctx_init(ns_client_t *client, dns_fetchevent_t *event, dns_rdatatype_t qtype,
CCTRACE(ISC_LOG_DEBUG(3), "qctx_init");
qctx->event = event;
if (eventp != NULL) {
qctx->event = *eventp;
*eventp = NULL;
} else {
qctx->event = NULL;
}
qctx->qtype = qctx->type = qtype;
qctx->result = ISC_R_SUCCESS;
qctx->findcoveringnsec = qctx->view->synthfromdnssec;
@@ -5642,6 +5647,7 @@ fetch_callback(isc_task_t *task, isc_event_t *event) {
isc_result_t result;
isc_logcategory_t *logcategory = NS_LOGCATEGORY_QUERY_ERRORS;
int errorloglevel;
query_ctx_t qctx;
UNUSED(task);
@@ -5709,26 +5715,42 @@ fetch_callback(isc_task_t *task, isc_event_t *event) {
client->state = NS_CLIENTSTATE_WORKING;
/*
* If this client is shutting down, or this transaction
* has timed out, do not resume the find.
* Initialize a new qctx and use it to either resume from
* recursion or clean up after cancelation. Transfer
* ownership of devent to the new qctx in the process.
*/
qctx_init(client, &devent, 0, &qctx);
client_shuttingdown = ns_client_shuttingdown(client);
if (fetch_canceled || client_shuttingdown) {
free_devent(client, &event, &devent);
/*
* We've timed out or are shutting down. We can now
* free the event and other resources held by qctx, but
* don't call qctx_destroy() yet: it might destroy the
* client, which we still need for a moment.
*/
qctx_freedata(&qctx);
/*
* Return an error to the client, or just drop.
*/
if (fetch_canceled) {
CTRACE(ISC_LOG_ERROR, "fetch cancelled");
query_error(client, DNS_R_SERVFAIL, __LINE__);
} else {
query_next(client, ISC_R_CANCELED);
}
} else {
query_ctx_t qctx;
/*
* Initialize a new qctx and use it to resume
* from recursion.
* Free any persistent plugin data that was allocated to
* service the client, then detach the client object.
*/
qctx.detach_client = true;
qctx_destroy(&qctx);
} else {
/*
* Resume the find process.
*/
qctx_init(client, devent, 0, &qctx);
query_trace(&qctx);
result = query_resume(&qctx);