]> git.ipfire.org Git - thirdparty/bind9.git/commitdiff
purge pending command events when shutting down
authorEvan Hunt <each@isc.org>
Fri, 3 Jul 2020 22:34:51 +0000 (15:34 -0700)
committerEvan Hunt <each@isc.org>
Mon, 13 Jul 2020 20:17:08 +0000 (13:17 -0700)
When we're shutting the system down via "rndc stop" or "rndc halt",
or reconfiguring the control channel, there are potential shutdown
races between the server task and network manager.  These are adressed by:

- purging any pending command tasks when shutting down the control channel
- adding an extra handle reference before the command handler to
  ensure the handle can't be deleted out from under us before calling
  command_respond()

bin/named/controlconf.c

index 924b8a74f66b737f65f553b2b10ef972ec478bc0..c69650ace56d7533d6ae8f710c409637d36fac91 100644 (file)
@@ -330,7 +330,6 @@ control_respond(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
        if (result != ISC_R_SUCCESS) {
                isc_nmhandle_unref(handle);
                conn->sending = false;
-               goto cleanup;
        }
 
 cleanup:
@@ -357,10 +356,17 @@ control_command(isc_task_t *task, isc_event_t *event) {
 
        UNUSED(task);
 
+       /*
+        * An extra ref and two unrefs are needed here to
+        * ensure the handle isn't cleaned up if we're running
+        * an "rndc stop" command.
+        */
+       isc_nmhandle_ref(conn->handle);
        conn->result = named_control_docommand(conn->request,
                                               listener->readonly, &conn->text);
        control_respond(conn->handle, conn->result, conn);
        isc_nmhandle_unref(conn->handle);
+       isc_nmhandle_unref(conn->handle);
        isc_event_free(&event);
 }
 
@@ -382,7 +388,14 @@ control_recvmessage(isc_nmhandle_t *handle, isc_result_t result, void *arg) {
        }
 
        if (result != ISC_R_SUCCESS) {
-               if (result != ISC_R_CANCELED && result != ISC_R_EOF) {
+               if (result == ISC_R_CANCELED) {
+                       /*
+                        * Don't bother with any more scheduled command events.
+                        */
+                       listener->controls->shuttingdown = true;
+                       isc_task_purge(named_g_server->task, NULL,
+                                      NAMED_EVENT_COMMAND, NULL);
+               } else if (result != ISC_R_EOF) {
                        log_invalid(&conn->ccmsg, result);
                }