Blame SOURCES/bind-9.16-CVE-2022-0396.patch

dc3c8a
From 33064cd077cf6fa386f0a5a840c2161868da7b3a Mon Sep 17 00:00:00 2001
dc3c8a
From: =?UTF-8?q?Ond=C5=99ej=20Sur=C3=BD?= <ondrej@isc.org>
dc3c8a
Date: Tue, 8 Feb 2022 12:42:34 +0100
dc3c8a
Subject: [PATCH] Run .closehandle_cb asynchrounosly in nmhandle_detach_cb()
dc3c8a
dc3c8a
When sock->closehandle_cb is set, we need to run nmhandle_detach_cb()
dc3c8a
asynchronously to ensure correct order of multiple packets processing in
dc3c8a
the isc__nm_process_sock_buffer().  When not run asynchronously, it
dc3c8a
would cause:
dc3c8a
dc3c8a
  a) out-of-order processing of the return codes from processbuffer();
dc3c8a
dc3c8a
  b) stack growth because the next TCP DNS message read callback will
dc3c8a
     be called from within the current TCP DNS message read callback.
dc3c8a
dc3c8a
The sock->closehandle_cb is set to isc__nm_resume_processing() for TCP
dc3c8a
sockets which calls isc__nm_process_sock_buffer().  If the read callback
dc3c8a
(called from isc__nm_process_sock_buffer()->processbuffer()) doesn't
dc3c8a
attach to the nmhandle (f.e. because it wants to drop the processing or
dc3c8a
we send the response directly via uv_try_write()), the
dc3c8a
isc__nm_resume_processing() (via .closehandle_cb) would call
dc3c8a
isc__nm_process_sock_buffer() recursively.
dc3c8a
dc3c8a
The below shortened code path shows how the stack can grow:
dc3c8a
dc3c8a
 1: ns__client_request(handle, ...);
dc3c8a
 2: isc_nm_tcpdns_sequential(handle);
dc3c8a
 3: ns_query_start(client, handle);
dc3c8a
 4:   query_lookup(qctx);
dc3c8a
 5:     query_send(qctcx->client);
dc3c8a
 6:       isc__nmhandle_detach(&client->reqhandle);
dc3c8a
 7:         nmhandle_detach_cb(&handle);
dc3c8a
 8:           sock->closehandle_cb(sock); // isc__nm_resume_processing
dc3c8a
 9:             isc__nm_process_sock_buffer(sock);
dc3c8a
10:               processbuffer(sock); // isc__nm_tcpdns_processbuffer
dc3c8a
11:                 isc_nmhandle_attach(req->handle, &handle);
dc3c8a
12:                 isc__nm_readcb(sock, req, ISC_R_SUCCESS);
dc3c8a
13:                   isc__nm_async_readcb(NULL, ...);
dc3c8a
14:                     uvreq->cb.recv(...); // ns__client_request
dc3c8a
dc3c8a
Instead, if 'sock->closehandle_cb' is set, we need to run detach the
dc3c8a
handle asynchroniously in 'isc__nmhandle_detach', so that on line 8 in
dc3c8a
the code flow above does not start this recursion. This ensures the
dc3c8a
correct order when processing multiple packets in the function
dc3c8a
'isc__nm_process_sock_buffer()' and prevents the stack growth.
dc3c8a
dc3c8a
When not run asynchronously, the out-of-order processing leaves the
dc3c8a
first TCP socket open until all requests on the stream have been
dc3c8a
processed.
dc3c8a
dc3c8a
If the pipelining is disabled on the TCP via `keep-response-order`
dc3c8a
configuration option, named would keep the first socket in lingering
dc3c8a
CLOSE_WAIT state when the client sends an incomplete packet and then
dc3c8a
closes the connection from the client side.
dc3c8a
dc3c8a
(cherry picked from commit afee2b5a7bc933a2d987907fc327a9f118fdbd17)
dc3c8a
---
dc3c8a
 lib/isc/netmgr/netmgr.c | 6 +++++-
dc3c8a
 1 file changed, 5 insertions(+), 1 deletion(-)
dc3c8a
dc3c8a
diff --git a/lib/isc/netmgr/netmgr.c b/lib/isc/netmgr/netmgr.c
dc3c8a
index 3283eb6e4f..0ed3182fb6 100644
dc3c8a
--- a/lib/isc/netmgr/netmgr.c
dc3c8a
+++ b/lib/isc/netmgr/netmgr.c
dc3c8a
@@ -1746,8 +1746,12 @@ isc__nmhandle_detach(isc_nmhandle_t **handlep FLARG) {
dc3c8a
 	handle = *handlep;
dc3c8a
 	*handlep = NULL;
dc3c8a
 
dc3c8a
+	/*
dc3c8a
+	 * If the closehandle_cb is set, it needs to run asynchronously to
dc3c8a
+	 * ensure correct ordering of the isc__nm_process_sock_buffer().
dc3c8a
+	 */
dc3c8a
 	sock = handle->sock;
dc3c8a
-	if (sock->tid == isc_nm_tid()) {
dc3c8a
+	if (sock->tid == isc_nm_tid() && sock->closehandle_cb == NULL) {
dc3c8a
 		nmhandle_detach_cb(&handle FLARG_PASS);
dc3c8a
 	} else {
dc3c8a
 		isc__netievent_detach_t *event =
dc3c8a
-- 
dc3c8a
2.34.1
dc3c8a