]> git.ipfire.org Git - thirdparty/curl.git/commitdiff
mbedtls: fix handling of blocked sends
authorStefan Eissing <stefan@eissing.org>
Sat, 28 Dec 2024 11:19:19 +0000 (12:19 +0100)
committerDaniel Stenberg <daniel@haxx.se>
Mon, 30 Dec 2024 09:20:27 +0000 (10:20 +0100)
mbedtls is picky when a mbedtls_ssl_write) was previously blocked. It
requires to be called with the same amount of bytes again, or it will
lose bytes, e.g. reporting all was sent but they were not. Remember the
blocked length and use that when set.

Reported-by: Tamás Bálint Misius
Fixes #15801
Closes #15846

docs/KNOWN_BUGS
lib/vtls/mbedtls.c
tests/http/test_08_caddy.py

index 606fa66f07083f58c5178b902f9940be9c8ac152..bdb029bf049c00ae04616e5a9495788bdaecb927 100644 (file)
@@ -21,6 +21,7 @@ problems may have been fixed or changed somewhat since this was written.
  2.7 Client cert (MTLS) issues with Schannel
  2.11 Schannel TLS 1.2 handshake bug in old Windows versions
  2.13 CURLOPT_CERTINFO results in CURLE_OUT_OF_MEMORY with Schannel
+ 2.14 mbedTLS and CURLE_AGAIN handling
 
  3. Email protocols
  3.1 IMAP SEARCH ALL truncated response
@@ -159,6 +160,10 @@ problems may have been fixed or changed somewhat since this was written.
 
  https://github.com/curl/curl/issues/8741
 
+2.14 mbedTLS and CURLE_AGAIN handling
+
+ https://github.com/curl/curl/issues/15801
+
 3. Email protocols
 
 3.1 IMAP SEARCH ALL truncated response
index e5d162df8370966d7ac37db9ffe0f48b66d4cc5d..f2c7b6c2388a74927012e4269b74f1bb78b06c6a 100644 (file)
@@ -101,8 +101,10 @@ struct mbed_ssl_backend_data {
   const char *protocols[3];
 #endif
   int *ciphersuites;
+  size_t send_blocked_len;
   BIT(initialized); /* mbedtls_ssl_context is initialized */
   BIT(sent_shutdown);
+  BIT(send_blocked);
 };
 
 /* apply threading? */
@@ -1196,6 +1198,17 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
 
   (void)data;
   DEBUGASSERT(backend);
+  /* mbedtls is picky when a mbedtls_ssl_write) was previously blocked.
+   * It requires to be called with the same amount of bytes again, or it
+   * will lose bytes, e.g. reporting all was sent but they were not.
+   * Remember the blocked length and use that when set. */
+  if(backend->send_blocked) {
+    DEBUGASSERT(backend->send_blocked_len <= len);
+    CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> previously blocked "
+                "on %zu bytes", len, backend->send_blocked_len);
+    len = backend->send_blocked_len;
+  }
+
   ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
 
   if(ret < 0) {
@@ -1207,6 +1220,14 @@ static ssize_t mbed_send(struct Curl_cfilter *cf, struct Curl_easy *data,
 #endif
       ) ? CURLE_AGAIN : CURLE_SEND_ERROR;
     ret = -1;
+    if((*curlcode == CURLE_AGAIN) && !backend->send_blocked) {
+      backend->send_blocked = TRUE;
+      backend->send_blocked_len = len;
+    }
+  }
+  else {
+    CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> %d", len, ret);
+    backend->send_blocked = FALSE;
   }
 
   return ret;
index 2f7f649c082a80ecc11ce24201cb165ca87458d0..418eaae70f3642968cc15c9cd60b803aa9910be0 100644 (file)
@@ -212,6 +212,8 @@ class TestCaddy:
 
     @pytest.mark.parametrize("proto", ['http/1.1', 'h2', 'h3'])
     def test_08_08_earlydata(self, env: Env, httpd, caddy, proto):
+        if proto == 'h3' and not env.have_h3():
+            pytest.skip("h3 not supported")
         count = 2
         docname = 'data10k.data'
         url = f'https://{env.domain1}:{caddy.port}/{docname}'