From 24d6c2889f15f5141ff8d37b59f9099e8aae0f38 Mon Sep 17 00:00:00 2001 From: Jay Satiro Date: Fri, 9 Feb 2024 03:41:30 -0500 Subject: [PATCH] schannel: fix hang on unexpected server close - Treat TLS connection close (either due to a close_notify from the server or just closed due to receiving 0) as pending data. This is because in some cases schannel_recv knows the connection is closed but has to return actual pending data so it can't return 0 or an error to indicate no more data. In this case schannel_recv must be called again, which only happens if readwrite_data sees that there is still pending data. Prior to this change if the total size of the body that libcurl expected to receive from the server was unknown then it was possible under some network conditions that libcurl would hang waiting to receive more data, when in fact a close_notify alert indicating no more data would be sent was already processed. Fixes https://github.com/curl/curl/issues/12894 Closes https://github.com/curl/curl/pull/12910 --- lib/vtls/schannel.c | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 45c3373713..d9d0b9f72d 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -2133,7 +2133,6 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, infof(data, "schannel: server indicated shutdown in a prior call"); goto cleanup; } - /* It's debatable what to return when !len. Regardless we can't return immediately because there may be data to decrypt (in the case we want to decrypt all encrypted cached data) so handle !len later in cleanup. @@ -2317,10 +2316,10 @@ schannel_recv(struct Curl_cfilter *cf, struct Curl_easy *data, /* In Windows 2000 SEC_I_CONTEXT_EXPIRED (close_notify) is not returned so we have to work around that in cleanup. */ backend->recv_sspi_close_notify = true; - if(!backend->recv_connection_closed) { + if(!backend->recv_connection_closed) backend->recv_connection_closed = true; - infof(data, "schannel: server closed the connection"); - } + infof(data, + "schannel: server close notification received (close_notify)"); goto cleanup; } } @@ -2443,7 +2442,10 @@ static bool schannel_data_pending(struct Curl_cfilter *cf, if(backend->ctxt) /* SSL/TLS is in use */ return (backend->decdata_offset > 0 || - (backend->encdata_offset > 0 && !backend->encdata_is_incomplete)); + (backend->encdata_offset > 0 && !backend->encdata_is_incomplete) || + backend->recv_connection_closed || + backend->recv_sspi_close_notify || + backend->recv_unrecoverable_err); else return FALSE; } -- 2.47.3