]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
Don't continue opening a new rndc connection if we are shutting down
authorOndřej Surý <ondrej@isc.org>
Tue, 23 Jun 2020 11:02:21 +0000 (13:02 +0200)
committerOndřej Surý <ondrej@isc.org>
Wed, 1 Jul 2020 06:44:56 +0000 (08:44 +0200)
Due to lack of synchronization, whenever named was being requested to
stop using rndc, controlconf.c module could be trying to access an already
released pointer through named_g_server->interfacemgr in a separate
thread.

The race could only be triggered if named was being shutdown and more
rndc connections were ocurring at the same time.

This fix correctly checks if the server is shutting down before opening
a new rndc connection.

bin/named/controlconf.c

index a3fda486d3df3654f7ce7b207a91b0546ffd7027..bab50ae8e07edd50c600140c93bbde1f2c52d3bb 100644 (file)
@@ -226,6 +226,7 @@ shutdown_listener(controllistener_t *listener) {
        if (listener->listening) {
                isc_socket_cancel(listener->sock, listener->task,
                                  ISC_SOCKCANCEL_ACCEPT);
+               return;
        }
 
        maybe_free_listener(listener);
@@ -636,6 +637,8 @@ control_newconn(isc_task_t *task, isc_event_t *event) {
 
        UNUSED(task);
 
+       REQUIRE(listener->listening);
+
        listener->listening = false;
 
        if (nevent->result != ISC_R_SUCCESS) {
@@ -647,6 +650,14 @@ control_newconn(isc_task_t *task, isc_event_t *event) {
        }
 
        sock = nevent->newsocket;
+
+       /* Is the server shutting down? */
+       if (listener->controls->shuttingdown) {
+               isc_socket_detach(&sock);
+               shutdown_listener(listener);
+               goto cleanup;
+       }
+
        isc_socket_setname(sock, "control", NULL);
        (void)isc_socket_getpeername(sock, &peeraddr);
        if (listener->type == isc_sockettype_tcp &&
@@ -1121,36 +1132,33 @@ add_listener(named_controls_t *cp, controllistener_t **listenerp,
 
        listener = isc_mem_get(mctx, sizeof(*listener));
 
-       if (result == ISC_R_SUCCESS) {
-               listener->mctx = NULL;
-               isc_mem_attach(mctx, &listener->mctx);
-               listener->controls = cp;
-               listener->task = cp->server->task;
-               listener->address = *addr;
-               listener->sock = NULL;
-               listener->listening = false;
-               listener->exiting = false;
-               listener->acl = NULL;
-               listener->type = type;
-               listener->perm = 0;
-               listener->owner = 0;
-               listener->group = 0;
-               listener->readonly = false;
-               ISC_LINK_INIT(listener, link);
-               ISC_LIST_INIT(listener->keys);
-               ISC_LIST_INIT(listener->connections);
+       listener->mctx = NULL;
+       isc_mem_attach(mctx, &listener->mctx);
+       listener->controls = cp;
+       listener->task = cp->server->task;
+       listener->address = *addr;
+       listener->sock = NULL;
+       listener->listening = false;
+       listener->exiting = false;
+       listener->acl = NULL;
+       listener->type = type;
+       listener->perm = 0;
+       listener->owner = 0;
+       listener->group = 0;
+       listener->readonly = false;
+       ISC_LINK_INIT(listener, link);
+       ISC_LIST_INIT(listener->keys);
+       ISC_LIST_INIT(listener->connections);
 
-               /*
-                * Make the acl.
-                */
-               if (control != NULL && type == isc_sockettype_tcp) {
-                       allow = cfg_tuple_get(control, "allow");
-                       result = cfg_acl_fromconfig(allow, config, named_g_lctx,
-                                                   aclconfctx, mctx, 0,
-                                                   &new_acl);
-               } else {
-                       result = dns_acl_any(mctx, &new_acl);
-               }
+       /*
+        * Make the acl.
+        */
+       if (control != NULL && type == isc_sockettype_tcp) {
+               allow = cfg_tuple_get(control, "allow");
+               result = cfg_acl_fromconfig(allow, config, named_g_lctx,
+                                           aclconfctx, mctx, 0, &new_acl);
+       } else {
+               result = dns_acl_any(mctx, &new_acl);
        }
 
        if ((result == ISC_R_SUCCESS) && (control != NULL)) {