bind/backport-0022-Hold-qid-lock-when-calling-deref_portentry-as.patch
jiangheng ad37c37958 backport some patches from community
(cherry picked from commit a9fd9ece9b9436b6103d084920c6897ef1adbae6)
2022-09-03 21:36:21 +08:00

158 lines
4.8 KiB
Diff

From 86d9d04fd8931e47c527cef08ae8ee89a695b707 Mon Sep 17 00:00:00 2001
From: Mark Andrews <marka@isc.org>
Date: Thu, 22 Oct 2020 16:13:06 +1100
Subject: [PATCH] Hold qid->lock when calling deref_portentry() as
socket_search() need portentry to be unchanging.
WARNING: ThreadSanitizer: data race
Write of size 8 at 0x000000000001 by thread T1 (mutexes: write M1):
#0 deref_portentry lib/dns/dispatch.c:630
#1 deactivate_dispsocket lib/dns/dispatch.c:861
#2 udp_recv lib/dns/dispatch.c:1105
#3 udp_exrecv lib/dns/dispatch.c:1028
#4 dispatch lib/isc/task.c:1152
#5 run lib/isc/task.c:1344
#6 <null> <null>
Previous read of size 8 at 0x000000000001 by thread T2 (mutexes: write M1, write M2):
#0 socket_search lib/dns/dispatch.c:661
#1 get_dispsocket lib/dns/dispatch.c:744
#2 dns_dispatch_addresponse lib/dns/dispatch.c:3120
#3 resquery_send lib/dns/resolver.c:2467
#4 fctx_query lib/dns/resolver.c:2217
#5 fctx_try lib/dns/resolver.c:4245
#6 fctx_timeout lib/dns/resolver.c:4570
#7 dispatch lib/isc/task.c:1152
#8 run lib/isc/task.c:1344
#9 <null> <null>
(cherry picked from commit 5c253c416d0bc0cce7606667c6703f44a98e9494)
Conflict: NA
Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/86d9d04fd8931e47c527cef08ae8ee89a695b707
---
lib/dns/dispatch.c | 41 ++++++++++++++++++-----------------------
1 file changed, 18 insertions(+), 23 deletions(-)
diff --git a/lib/dns/dispatch.c b/lib/dns/dispatch.c
index 7cfff94868..80d76b79c9 100644
--- a/lib/dns/dispatch.c
+++ b/lib/dns/dispatch.c
@@ -599,34 +599,22 @@ new_portentry(dns_dispatch_t *disp, in_port_t port) {
}
/*%
- * The caller must not hold the qid->lock.
+ * The caller must hold the qid->lock.
*/
static void
deref_portentry(dns_dispatch_t *disp, dispportentry_t **portentryp) {
dispportentry_t *portentry = *portentryp;
- dns_qid_t *qid;
+ *portentryp = NULL;
REQUIRE(disp->port_table != NULL);
REQUIRE(portentry != NULL && portentry->refs > 0);
- qid = DNS_QID(disp);
- LOCK(&qid->lock);
- portentry->refs--;
-
- if (portentry->refs == 0) {
+ if (--portentry->refs == 0) {
ISC_LIST_UNLINK(disp->port_table[portentry->port %
DNS_DISPATCH_PORTTABLESIZE],
portentry, link);
isc_mempool_put(disp->portpool, portentry);
}
-
- /*
- * Set '*portentryp' to NULL inside the lock so that
- * dispsock->portentry does not change in socket_search.
- */
- *portentryp = NULL;
-
- UNLOCK(&qid->lock);
}
/*%
@@ -764,9 +752,9 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
if (result == ISC_R_SUCCESS) {
dispsock->socket = sock;
dispsock->host = *dest;
- dispsock->portentry = portentry;
dispsock->bucket = bucket;
LOCK(&qid->lock);
+ dispsock->portentry = portentry;
ISC_LIST_APPEND(qid->sock_table[bucket], dispsock, blink);
UNLOCK(&qid->lock);
*dispsockp = dispsock;
@@ -791,7 +779,7 @@ get_dispsocket(dns_dispatch_t *disp, isc_sockaddr_t *dest,
static void
destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) {
dispsocket_t *dispsock;
- dns_qid_t *qid;
+ dns_qid_t *qid = DNS_QID(disp);
/*
* The dispatch must be locked.
@@ -803,19 +791,24 @@ destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) {
disp->nsockets--;
dispsock->magic = 0;
- if (dispsock->portentry != NULL)
+ if (dispsock->portentry != NULL) {
+ /* socket_search() tests and dereferences portentry. */
+ LOCK(&qid->lock);
deref_portentry(disp, &dispsock->portentry);
- if (dispsock->socket != NULL)
+ UNLOCK(&qid->lock);
+ }
+ if (dispsock->socket != NULL) {
isc_socket_detach(&dispsock->socket);
+ }
if (ISC_LINK_LINKED(dispsock, blink)) {
- qid = DNS_QID(disp);
LOCK(&qid->lock);
ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
blink);
UNLOCK(&qid->lock);
}
- if (dispsock->task != NULL)
+ if (dispsock->task != NULL) {
isc_task_detach(&dispsock->task);
+ }
isc_mempool_put(disp->mgr->spool, dispsock);
*dispsockp = NULL;
@@ -828,7 +821,7 @@ destroy_dispsocket(dns_dispatch_t *disp, dispsocket_t **dispsockp) {
static void
deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) {
isc_result_t result;
- dns_qid_t *qid;
+ dns_qid_t *qid = DNS_QID(disp);
/*
* The dispatch must be locked.
@@ -840,14 +833,16 @@ deactivate_dispsocket(dns_dispatch_t *disp, dispsocket_t *dispsock) {
}
INSIST(dispsock->portentry != NULL);
+ /* socket_search() tests and dereferences portentry. */
+ LOCK(&qid->lock);
deref_portentry(disp, &dispsock->portentry);
+ UNLOCK(&qid->lock);
if (disp->nsockets > DNS_DISPATCH_POOLSOCKS)
destroy_dispsocket(disp, &dispsock);
else {
result = isc_socket_close(dispsock->socket);
- qid = DNS_QID(disp);
LOCK(&qid->lock);
ISC_LIST_UNLINK(qid->sock_table[dispsock->bucket], dispsock,
blink);
--
2.23.0