Merge branch 'tcp-reset-connection-on-failed-send-9.18' into 'v9.18.28-release'

[9.18][CVE-2024-0760 (part 3)] Reset the TCP connection on a failed send

See merge request isc-private/bind9!722
This commit is contained in:
Nicki Křížek
2024-07-03 15:51:09 +00:00
4 changed files with 56 additions and 42 deletions
+32 -4
View File
@@ -2369,14 +2369,41 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
int_fast32_t ah = atomic_load(&sock->ah);
isc_result_t result = processbuffer(sock);
switch (result) {
case ISC_R_NOMORE:
case ISC_R_NOMORE: {
/*
* Don't reset the timer until we have a
* full DNS message.
*/
result = isc__nm_start_reading(sock);
if (result != ISC_R_SUCCESS) {
return (result);
/*
* Restart reading if we have less data in the send
* queue than the send buffer size, this means that the
* TCP client has started reading some data again.
* Starting reading when we go under the limit instead
* of waiting for all data has been flushed allows
* faster recovery (in case there was a congestion and
* now there isn't).
*/
size_t write_queue_size =
uv_stream_get_write_queue_size(
&sock->uv_handle.stream);
if (write_queue_size < ISC_NETMGR_TCP_SENDBUF_SIZE) {
if (sock->reading_throttled) {
isc_log_write(isc_lctx,
ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_NETMGR,
ISC_LOG_DEBUG(3),
"resuming TCP "
"connection, the other "
"side is reading the "
"data again (%zu)",
write_queue_size);
sock->reading_throttled = false;
}
result = isc__nm_start_reading(sock);
if (result != ISC_R_SUCCESS) {
return (result);
}
}
/*
* Start the timer only if there are no externally used
@@ -2388,6 +2415,7 @@ isc__nm_process_sock_buffer(isc_nmsocket_t *sock) {
isc__nmsocket_timer_start(sock);
}
goto done;
}
case ISC_R_CANCELED:
isc__nmsocket_timer_stop(sock);
isc__nm_stop_reading(sock);
+11 -19
View File
@@ -1162,25 +1162,10 @@ tcpdns_maybe_restart_reading(isc_nmsocket_t *sock) {
if (!sock->client && sock->reading_throttled &&
!uv_is_active(&sock->uv_handle.handle))
{
/*
* Restart reading if we have less data in the send queue than
* the send buffer size, this means that the TCP client has
* started reading some data again. Starting reading when we go
* under the limit instead of waiting for all data has been
* flushed allows faster recovery (in case there was a
* congestion and now there isn't).
*/
size_t write_queue_size =
uv_stream_get_write_queue_size(&sock->uv_handle.stream);
if (write_queue_size < ISC_NETMGR_TCP_SENDBUF_SIZE) {
isc_log_write(
isc_lctx, ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_NETMGR, ISC_LOG_DEBUG(3),
"resuming TCP connection, the other side "
"is reading the data again (%zu)",
write_queue_size);
sock->reading_throttled = false;
isc__nm_start_reading(sock);
isc_result_t result = isc__nm_process_sock_buffer(sock);
if (result != ISC_R_SUCCESS) {
atomic_store(&sock->reading, true);
isc__nm_failed_read_cb(sock, result, false);
}
}
}
@@ -1284,6 +1269,13 @@ isc__nm_async_tcpdnssend(isc__networker_t *worker, isc__netievent_t *ev0) {
goto fail;
}
isc_log_write(isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
ISC_LOG_DEBUG(3),
"throttling TCP connection, the other side is not "
"reading the data, switching to uv_write()");
sock->reading_throttled = true;
isc__nm_stop_reading(sock);
r = uv_write(&uvreq->uv_req.write, &sock->uv_handle.stream, bufs, nbufs,
tcpdns_send_cb);
if (r < 0) {
+12 -19
View File
@@ -1377,6 +1377,14 @@ tls_cycle_output(isc_nmsocket_t *sock) {
break;
}
isc_log_write(
isc_lctx, ISC_LOGCATEGORY_GENERAL, ISC_LOGMODULE_NETMGR,
ISC_LOG_DEBUG(3),
"throttling TCP connection, the other side is not "
"reading the data, switching to uv_write()");
sock->reading_throttled = true;
isc__nm_stop_reading(sock);
r = uv_write(&req->uv_req.write, &sock->uv_handle.stream,
&req->uvbuf, 1, tls_write_cb);
if (r < 0) {
@@ -1820,25 +1828,10 @@ tlsdns_maybe_restart_reading(isc_nmsocket_t *sock) {
if (!sock->client && sock->reading_throttled &&
!uv_is_active(&sock->uv_handle.handle))
{
/*
* Restart reading if we have less data in the send queue than
* the send buffer size, this means that the TCP client has
* started reading some data again. Starting reading when we go
* under the limit instead of waiting for all data has been
* flushed allows faster recovery (in case there was a
* congestion and now there isn't).
*/
size_t write_queue_size =
uv_stream_get_write_queue_size(&sock->uv_handle.stream);
if (write_queue_size < ISC_NETMGR_TCP_SENDBUF_SIZE) {
isc_log_write(
isc_lctx, ISC_LOGCATEGORY_GENERAL,
ISC_LOGMODULE_NETMGR, ISC_LOG_DEBUG(3),
"resuming TCP connection, the other side "
"is reading the data again (%zu)",
write_queue_size);
sock->reading_throttled = false;
isc__nm_start_reading(sock);
isc_result_t result = isc__nm_process_sock_buffer(sock);
if (result != ISC_R_SUCCESS) {
atomic_store(&sock->reading, true);
isc__nm_failed_read_cb(sock, result, false);
}
}
}
+1
View File
@@ -333,6 +333,7 @@ client_senddone(isc_nmhandle_t *handle, isc_result_t result, void *cbarg) {
NS_LOGMODULE_CLIENT, ISC_LOG_DEBUG(3),
"send failed: %s",
isc_result_totext(result));
isc_nm_bad_request(handle);
}
}