]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
schannel: fix hang on unexpected server close
authorJay Satiro <raysatiro@yahoo.com>
Fri, 9 Feb 2024 08:41:30 +0000 (03:41 -0500)
committerJay Satiro <raysatiro@yahoo.com>
Tue, 13 Feb 2024 08:45:21 +0000 (03:45 -0500)
- 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

index 45c3373713c9a60f8d7f2798687dd6c55f7f70c9..d9d0b9f72d0620b742f4384c4bcfd82eaf68a8ac 100644 (file)
@@ -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;
 }