From 7247df0fcf1445e82b56a80d0e419aff701defde Mon Sep 17 00:00:00 2001
From: Mark Andrews <marka@isc.org>
Date: Tue, 8 Sep 2020 12:11:06 +1000
Subject: [PATCH] Lock access to control->symtab to prevent data race

    WARNING: ThreadSanitizer: data race
    Read of size 8 at 0x000000000001 by thread T1:
    #0 isccc_symtab_foreach lib/isccc/symtab.c:277:14
    #1 isccc_cc_cleansymtab lib/isccc/cc.c:954:2
    #2 control_recvmessage bin/named/controlconf.c:477:2
    #3 recv_data lib/isccc/ccmsg.c:110:2
    #4 read_cb lib/isc/netmgr/tcp.c:769:4
    #5 <null> <null>

    Previous write of size 8 at 0x000000000001 by thread T2:
    #0 isccc_symtab_define lib/isccc/symtab.c:242:2
    #1 isccc_cc_checkdup lib/isccc/cc.c:1026:11
    #2 control_recvmessage bin/named/controlconf.c:478:11
    #3 recv_data lib/isccc/ccmsg.c:110:2
    #4 read_cb lib/isc/netmgr/tcp.c:769:4
    #5 <null> <null>

    Location is heap block of size 190352 at 0x000000000011 allocated by main thread:
    #0 malloc <null>
    #1 isccc_symtab_create lib/isccc/symtab.c:76:18
    #2 isccc_cc_createsymtab lib/isccc/cc.c:948:10
    #3 named_controls_create bin/named/controlconf.c:1483:11
    #4 named_server_create bin/named/server.c:10057:2
    #5 setup bin/named/main.c:1256:2
    #6 main bin/named/main.c:1523:2

    Thread T1 (running) created by main thread at:
    #0 pthread_create <null>
    #1 isc_thread_create lib/isc/pthreads/thread.c:73:8
    #2 isc_nm_start lib/isc/netmgr/netmgr.c:215:3
    #3 create_managers bin/named/main.c:909:15
    #4 setup bin/named/main.c:1223:11
    #5 main bin/named/main.c:1523:2

    Thread T2 (running) created by main thread at:
    #0 pthread_create <null>
    #1 isc_thread_create lib/isc/pthreads/thread.c:73:8
    #2 isc_nm_start lib/isc/netmgr/netmgr.c:215:3
    #3 create_managers bin/named/main.c:909:15
    #4 setup bin/named/main.c:1223:11
    #5 main bin/named/main.c:1523:2

    SUMMARY: ThreadSanitizer: data race lib/isccc/symtab.c:277:14 in isccc_symtab_foreach

(cherry picked from commit 0450acc1b65442a0e904c895cf2875eacf409598)
Conflict: NA
Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/7247df0fcf1445e82b56a80d0e419aff701defde
---
 bin/named/controlconf.c | 41 +++++++++++++++++++++++++++++++----------
 1 file changed, 31 insertions(+), 10 deletions(-)

diff --git a/bin/named/controlconf.c b/bin/named/controlconf.c
index 1d31f7a311..9fdf49bb7a 100644
--- a/bin/named/controlconf.c
+++ b/bin/named/controlconf.c
@@ -21,6 +21,7 @@
 #include <isc/event.h>
 #include <isc/file.h>
 #include <isc/mem.h>
+#include <isc/mutex.h>
 #include <isc/net.h>
 #include <isc/netaddr.h>
 #include <isc/random.h>
@@ -75,8 +76,8 @@ struct controlkey {
 struct controlconnection {
 	isc_socket_t *			sock;
 	isccc_ccmsg_t			ccmsg;
-	bool			ccmsg_valid;
-	bool			sending;
+	bool				ccmsg_valid;
+	bool				sending;
 	isc_timer_t *			timer;
 	isc_buffer_t *			buffer;
 	controllistener_t *		listener;
@@ -91,22 +92,23 @@ struct controllistener {
 	isc_sockaddr_t			address;
 	isc_socket_t *			sock;
 	dns_acl_t *			acl;
-	bool			listening;
-	bool			exiting;
+	bool				listening;
+	bool				exiting;
 	controlkeylist_t		keys;
 	controlconnectionlist_t		connections;
 	isc_sockettype_t		type;
 	uint32_t			perm;
 	uint32_t			owner;
 	uint32_t			group;
-	bool			readonly;
+	bool				readonly;
 	ISC_LINK(controllistener_t)	link;
 };
 
 struct ns_controls {
 	ns_server_t			*server;
 	controllistenerlist_t 		listeners;
-	bool			shuttingdown;
+	bool				shuttingdown;
+	isc_mutex_t			symtab_lock;
 	isccc_symtab_t			*symtab;
 };
 
@@ -434,8 +436,10 @@ control_recvmessage(isc_task_t *task, isc_event_t *event) {
 	/*
 	 * Duplicate suppression (required for UDP).
 	 */
+	LOCK(&listener->controls->symtab_lock);
 	isccc_cc_cleansymtab(listener->controls->symtab, now);
 	result = isccc_cc_checkdup(listener->controls->symtab, request, now);
+	UNLOCK(&listener->controls->symtab_lock);
 	if (result != ISC_R_SUCCESS) {
 		if (result == ISC_R_EXISTS)
 			result = ISCCC_R_DUPLICATE;
@@ -1503,14 +1507,28 @@ ns_controls_create(ns_server_t *server, ns_controls_t **ctrlsp) {
 	isc_result_t result;
 	ns_controls_t *controls = isc_mem_get(mctx, sizeof(*controls));
 
-	if (controls == NULL)
+	if (controls == NULL) {
 		return (ISC_R_NOMEMORY);
-	controls->server = server;
+	}
+
+	*controls = (ns_controls_t){
+		.server = server,
+	};
+
 	ISC_LIST_INIT(controls->listeners);
-	controls->shuttingdown = false;
-	controls->symtab = NULL;
+
+	result = isc_mutex_init(&controls->symtab_lock);
+	if (result != ISC_R_SUCCESS) {
+		isc_mem_put(server->mctx, controls, sizeof(*controls));
+		return (result);
+	}
+
+	LOCK(&controls->symtab_lock);
 	result = isccc_cc_createsymtab(&controls->symtab);
+	UNLOCK(&controls->symtab_lock);
+
 	if (result != ISC_R_SUCCESS) {
+		isc_mutex_destroy(&controls->symtab_lock);
 		isc_mem_put(server->mctx, controls, sizeof(*controls));
 		return (result);
 	}
@@ -1524,7 +1542,10 @@ ns_controls_destroy(ns_controls_t **ctrlsp) {
 
 	REQUIRE(ISC_LIST_EMPTY(controls->listeners));
 
+	LOCK(&controls->symtab_lock);
 	isccc_symtab_destroy(&controls->symtab);
+	UNLOCK(&controls->symtab_lock);
+	isc_mutex_destroy(&controls->symtab_lock);
 	isc_mem_put(controls->server->mctx, controls, sizeof(*controls));
 	*ctrlsp = NULL;
 }
-- 
2.23.0

