262 lines
7.4 KiB
Diff
262 lines
7.4 KiB
Diff
|
|
From 6cfab7e4f737803e0fc686ea7b7be0d9215489c2 Mon Sep 17 00:00:00 2001
|
||
|
|
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
|
||
|
|
Date: Tue, 14 Jun 2022 09:17:08 +0200
|
||
|
|
Subject: [PATCH] Gracefully handle uv_read_start() failures
|
||
|
|
|
||
|
|
Under specific rare timing circumstances the uv_read_start() could
|
||
|
|
fail with UV_EINVAL when the connection is reset between the connect (or
|
||
|
|
accept) and the uv_read_start() call on the nmworker loop. Handle such
|
||
|
|
situation gracefully by propagating the errors from uv_read_start() into
|
||
|
|
upper layers, so the socket can be internally closed().
|
||
|
|
|
||
|
|
(cherry picked from commit b432d5d3bcccf199141564b6a87d2cdac296ed7e)
|
||
|
|
Conflict: adapt isc__nm_start_reading modify
|
||
|
|
Reference: https://gitlab.isc.org/isc-projects/bind9/-/commit/6cfab7e4f737803e0fc686ea7b7be0d9215489c2
|
||
|
|
---
|
||
|
|
lib/isc/netmgr/netmgr-int.h | 4 ++--
|
||
|
|
lib/isc/netmgr/netmgr.c | 32 +++++++++++++++++++++-----------
|
||
|
|
lib/isc/netmgr/tcp.c | 10 ++++++++--
|
||
|
|
lib/isc/netmgr/tcpdns.c | 25 +++++++++++++++++++------
|
||
|
|
lib/isc/netmgr/udp.c | 10 ++++++++--
|
||
|
|
5 files changed, 58 insertions(+), 23 deletions(-)
|
||
|
|
|
||
|
|
diff --git a/lib/isc/netmgr/netmgr-int.h b/lib/isc/netmgr/netmgr-int.h
|
||
|
|
index e43bc9f..326535c 100644
|
||
|
|
--- a/lib/isc/netmgr/netmgr-int.h
|
||
|
|
+++ b/lib/isc/netmgr/netmgr-int.h
|
||
|
|
@@ -1560,11 +1560,11 @@ isc__nm_tcp_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
|
||
|
|
void
|
||
|
|
isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread, const uv_buf_t *buf);
|
||
|
|
|
||
|
|
-void
|
||
|
|
+isc_result_t
|
||
|
|
isc__nm_start_reading(isc_nmsocket_t *sock);
|
||
|
|
void
|
||
|
|
isc__nm_stop_reading(isc_nmsocket_t *sock);
|
||
|
|
-void
|
||
|
|
+isc_result_t
|
||
|
|
isc__nm_process_sock_buffer(isc_nmsocket_t *sock);
|
||
|
|
void
|
||
|
|
isc__nm_resume_processing(void *arg);
|
||
|
|
diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c
|
||
|
|
index 701f9a9..71c6d62 100644
|
||
|
|
--- a/lib/isc/netmgr/netmgr.c
|
||
|
|
+++ b/lib/isc/netmgr/netmgr.c
|
||
|
|
@@ -2162,12 +2162,13 @@ isc__nm_alloc_cb(uv_handle_t *handle, size_t size, uv_buf_t *buf) {
|
||
|
|
worker->recvbuf_inuse = true;
|
||
|
|
}
|
||
|
|
|
||
|
|
-void
|
||
|
|
+isc_result_t
|
||
|
|
isc__nm_start_reading(isc_nmsocket_t *sock) {
|
||
|
|
+ isc_result_t result = ISC_R_SUCCESS;
|
||
|
|
int r;
|
||
|
|
|
||
|
|
if (sock->reading) {
|
||
|
|
- return;
|
||
|
|
+ return (ISC_R_SUCCESS);
|
||
|
|
}
|
||
|
|
|
||
|
|
switch (sock->type) {
|
||
|
|
@@ -2187,8 +2188,14 @@ isc__nm_start_reading(isc_nmsocket_t *sock) {
|
||
|
|
INSIST(0);
|
||
|
|
ISC_UNREACHABLE();
|
||
|
|
}
|
||
|
|
- RUNTIME_CHECK(r == 0);
|
||
|
|
- sock->reading = true;
|
||
|
|
+
|
||
|
|
+ if (r != 0) {
|
||
|
|
+ result = isc__nm_uverr2result(r);
|
||
|
|
+ } else {
|
||
|
|
+ sock->reading = true;
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ return (result);
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
@@ -2250,7 +2257,7 @@ processbuffer(isc_nmsocket_t *sock) {
|
||
|
|
* limit. In this case we'll be called again by resume_processing()
|
||
|
|
* later.
|
||
|
|
*/
|
||
|
|
-void
|
||
|
|
+isc_result_t
|
||
|
|
isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
|
||
|
|
for (;;) {
|
||
|
|
int_fast32_t ah = atomic_load(&sock->ah);
|
||
|
|
@@ -2261,7 +2268,10 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
|
||
|
|
* Don't reset the timer until we have a
|
||
|
|
* full DNS message.
|
||
|
|
*/
|
||
|
|
- isc__nm_start_reading(sock);
|
||
|
|
+ result = isc__nm_start_reading(sock);
|
||
|
|
+ if (result != ISC_R_SUCCESS) {
|
||
|
|
+ return (result);
|
||
|
|
+ }
|
||
|
|
/*
|
||
|
|
* Start the timer only if there are no externally used
|
||
|
|
* active handles, there's always one active handle
|
||
|
|
@@ -2271,11 +2281,11 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
|
||
|
|
if (ah == 1) {
|
||
|
|
isc__nmsocket_timer_start(sock);
|
||
|
|
}
|
||
|
|
- return;
|
||
|
|
+ goto done;
|
||
|
|
case ISC_R_CANCELED:
|
||
|
|
isc__nmsocket_timer_stop(sock);
|
||
|
|
isc__nm_stop_reading(sock);
|
||
|
|
- return;
|
||
|
|
+ goto done;
|
||
|
|
case ISC_R_SUCCESS:
|
||
|
|
/*
|
||
|
|
* Stop the timer on the successful message read, this
|
||
|
|
@@ -2289,13 +2299,15 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
|
||
|
|
ah >= STREAM_CLIENTS_PER_CONN)
|
||
|
|
{
|
||
|
|
isc__nm_stop_reading(sock);
|
||
|
|
- return;
|
||
|
|
+ goto done;
|
||
|
|
}
|
||
|
|
break;
|
||
|
|
default:
|
||
|
|
INSIST(0);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
+done:
|
||
|
|
+ return (ISC_R_SUCCESS);
|
||
|
|
}
|
||
|
|
|
||
|
|
void
|
||
|
|
diff --git a/lib/isc/netmgr/tcp.c b/lib/isc/netmgr/tcp.c
|
||
|
|
index 009e431..735b29d 100644
|
||
|
|
--- a/lib/isc/netmgr/tcp.c
|
||
|
|
+++ b/lib/isc/netmgr/tcp.c
|
||
|
|
@@ -743,18 +743,24 @@ isc__nm_async_tcpstartread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||
|
|
isc__netievent_tcpstartread_t *ievent =
|
||
|
|
(isc__netievent_tcpstartread_t *)ev0;
|
||
|
|
isc_nmsocket_t *sock = ievent->sock;
|
||
|
|
+ isc_result_t result;
|
||
|
|
|
||
|
|
REQUIRE(VALID_NMSOCK(sock));
|
||
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
||
|
|
UNUSED(worker);
|
||
|
|
|
||
|
|
if (isc__nmsocket_closing(sock)) {
|
||
|
|
+ result = ISC_R_CANCELED;
|
||
|
|
+ } else {
|
||
|
|
+ result = isc__nm_start_reading(sock);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (result != ISC_R_SUCCESS) {
|
||
|
|
sock->reading = true;
|
||
|
|
- isc__nm_tcp_failed_read_cb(sock, ISC_R_CANCELED);
|
||
|
|
+ isc__nm_tcp_failed_read_cb(sock, result);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
- isc__nm_start_reading(sock);
|
||
|
|
isc__nmsocket_timer_start(sock);
|
||
|
|
}
|
||
|
|
|
||
|
|
diff --git a/lib/isc/netmgr/tcpdns.c b/lib/isc/netmgr/tcpdns.c
|
||
|
|
index 4689f56..3bc8e05 100644
|
||
|
|
--- a/lib/isc/netmgr/tcpdns.c
|
||
|
|
+++ b/lib/isc/netmgr/tcpdns.c
|
||
|
|
@@ -709,6 +709,7 @@ isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||
|
|
isc__netievent_tcpdnsread_t *ievent =
|
||
|
|
(isc__netievent_tcpdnsread_t *)ev0;
|
||
|
|
isc_nmsocket_t *sock = ievent->sock;
|
||
|
|
+ isc_result_t result;
|
||
|
|
|
||
|
|
UNUSED(worker);
|
||
|
|
|
||
|
|
@@ -716,12 +717,15 @@ isc__nm_async_tcpdnsread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
||
|
|
|
||
|
|
if (isc__nmsocket_closing(sock)) {
|
||
|
|
- sock->reading = true;
|
||
|
|
- isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
|
||
|
|
- return;
|
||
|
|
+ result = ISC_R_CANCELED;
|
||
|
|
+ } else {
|
||
|
|
+ result = isc__nm_process_sock_buffer(sock);
|
||
|
|
}
|
||
|
|
|
||
|
|
- isc__nm_process_sock_buffer(sock);
|
||
|
|
+ if (result != ISC_R_SUCCESS) {
|
||
|
|
+ sock->reading = true;
|
||
|
|
+ isc__nm_failed_read_cb(sock, result, false);
|
||
|
|
+ }
|
||
|
|
}
|
||
|
|
|
||
|
|
/*
|
||
|
|
@@ -813,6 +817,7 @@ isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread,
|
||
|
|
isc_nmsocket_t *sock = uv_handle_get_data((uv_handle_t *)stream);
|
||
|
|
uint8_t *base = NULL;
|
||
|
|
size_t len;
|
||
|
|
+ isc_result_t result;
|
||
|
|
|
||
|
|
REQUIRE(VALID_NMSOCK(sock));
|
||
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
||
|
|
@@ -856,7 +861,10 @@ isc__nm_tcpdns_read_cb(uv_stream_t *stream, ssize_t nread,
|
||
|
|
sock->read_timeout = atomic_load(&sock->mgr->idle);
|
||
|
|
}
|
||
|
|
|
||
|
|
- isc__nm_process_sock_buffer(sock);
|
||
|
|
+ result = isc__nm_process_sock_buffer(sock);
|
||
|
|
+ if (result != ISC_R_SUCCESS) {
|
||
|
|
+ isc__nm_failed_read_cb(sock, result, true);
|
||
|
|
+ }
|
||
|
|
free:
|
||
|
|
isc__nm_free_uvbuf(sock, buf);
|
||
|
|
}
|
||
|
|
@@ -999,7 +1007,12 @@ accept_connection(isc_nmsocket_t *ssock, isc_quota_t *quota) {
|
||
|
|
* prep_destroy()->tcpdns_close_direct().
|
||
|
|
*/
|
||
|
|
isc_nmhandle_attach(handle, &csock->recv_handle);
|
||
|
|
- isc__nm_process_sock_buffer(csock);
|
||
|
|
+ result = isc__nm_process_sock_buffer(csock);
|
||
|
|
+ if (result != ISC_R_SUCCESS) {
|
||
|
|
+ isc_nmhandle_detach(&csock->recv_handle);
|
||
|
|
+ isc_nmhandle_detach(&handle);
|
||
|
|
+ goto failure;
|
||
|
|
+ }
|
||
|
|
|
||
|
|
/*
|
||
|
|
* The initial timer has been set, update the read timeout for the next
|
||
|
|
diff --git a/lib/isc/netmgr/udp.c b/lib/isc/netmgr/udp.c
|
||
|
|
index 305ac29..1af63af 100644
|
||
|
|
--- a/lib/isc/netmgr/udp.c
|
||
|
|
+++ b/lib/isc/netmgr/udp.c
|
||
|
|
@@ -879,6 +879,7 @@ void
|
||
|
|
isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||
|
|
isc__netievent_udpread_t *ievent = (isc__netievent_udpread_t *)ev0;
|
||
|
|
isc_nmsocket_t *sock = ievent->sock;
|
||
|
|
+ isc_result_t result;
|
||
|
|
|
||
|
|
UNUSED(worker);
|
||
|
|
|
||
|
|
@@ -886,12 +887,17 @@ isc__nm_async_udpread(isc__networker_t *worker, isc__netievent_t *ev0) {
|
||
|
|
REQUIRE(sock->tid == isc_nm_tid());
|
||
|
|
|
||
|
|
if (isc__nmsocket_closing(sock)) {
|
||
|
|
+ result = ISC_R_CANCELED;
|
||
|
|
+ } else {
|
||
|
|
+ result = isc__nm_start_reading(sock);
|
||
|
|
+ }
|
||
|
|
+
|
||
|
|
+ if (result != ISC_R_SUCCESS) {
|
||
|
|
sock->reading = true;
|
||
|
|
- isc__nm_failed_read_cb(sock, ISC_R_CANCELED, false);
|
||
|
|
+ isc__nm_failed_read_cb(sock, result, false);
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
- isc__nm_start_reading(sock);
|
||
|
|
isc__nmsocket_timer_start(sock);
|
||
|
|
}
|
||
|
|
|
||
|
|
--
|
||
|
|
2.27.0
|
||
|
|
|