]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Fix the statistic counter underflow in ns_client_t
authorOndřej Surý <ondrej@sury.org>
Thu, 26 Mar 2020 09:57:38 +0000 (10:57 +0100)
committerOndřej Surý <ondrej@isc.org>
Fri, 3 Apr 2020 17:41:46 +0000 (19:41 +0200)
In case of normal fetch, the .recursionquota is attached and
ns_statscounter_recursclients is incremented when the fetch is created.  Then
the .recursionquota is detached and the counter decremented in the
fetch_callback().

In case of prefetch or rpzfetch, the quota is attached, but the counter is not
incremented.  When we reach the soft-quota, the function returns early but don't
detach from the quota, and it gets destroyed during the ns_client_endrequest(),
so no memory was leaked.

But because the ns_statscounter_recursclients is only incremented during the
normal fetch the counter would be incorrectly decremented on two occassions:

1) When we reached the softquota, because the quota was not properly detached
2) When the prefetch or rpzfetch was cancelled mid-flight and the callback
   function was never called.

lib/ns/client.c
lib/ns/query.c

index 9900866c35600783228ea986046e0ff9308bff86..04a8da7d3e9cbe505336bd52cbe206e8e4574b53 100644 (file)
@@ -235,8 +235,10 @@ ns_client_endrequest(ns_client_t *client) {
         */
        if (client->recursionquota != NULL) {
                isc_quota_detach(&client->recursionquota);
-               ns_stats_decrement(client->sctx->nsstats,
-                                  ns_statscounter_recursclients);
+               if (client->query.prefetch == NULL) {
+                       ns_stats_decrement(client->sctx->nsstats,
+                                          ns_statscounter_recursclients);
+               }
        }
 
        /*
index a503109db0f9c8159eb188f03e3a296a6d887982..46f1b59c892fe480c44b07a3b4d3b42e7df18dc9 100644 (file)
@@ -2463,6 +2463,13 @@ prefetch_done(isc_task_t *task, isc_event_t *event) {
        }
        UNLOCK(&client->query.fetchlock);
 
+       /*
+        * We're done prefetching, detach from quota.
+        */
+       if (client->recursionquota != NULL) {
+               isc_quota_detach(&client->recursionquota);
+       }
+
        free_devent(client, &event, &devent);
        isc_nmhandle_unref(client->handle);
 }
@@ -2488,6 +2495,9 @@ query_prefetch(ns_client_t *client, dns_name_t *qname,
        if (client->recursionquota == NULL) {
                result = isc_quota_attach(&client->sctx->recursionquota,
                                          &client->recursionquota);
+               if (result == ISC_R_SOFTQUOTA) {
+                       isc_quota_detach(&client->recursionquota);
+               }
                if (result != ISC_R_SUCCESS) {
                        return;
                }
@@ -2698,6 +2708,9 @@ query_rpzfetch(ns_client_t *client, dns_name_t *qname, dns_rdatatype_t type) {
        if (client->recursionquota == NULL) {
                result = isc_quota_attach(&client->sctx->recursionquota,
                                          &client->recursionquota);
+               if (result == ISC_R_SOFTQUOTA) {
+                       isc_quota_detach(&client->recursionquota);
+               }
                if (result != ISC_R_SUCCESS) {
                        return;
                }