Skip to content

Commit 25b46c0

Browse files
committed
Fix curl using mbedtls wrong
See curl/curl#15801 This would cause ranges of bytes to simply disappear from HTTP/2 streams >_>
1 parent d9ab96c commit 25b46c0

File tree

2 files changed

+103
-0
lines changed

2 files changed

+103
-0
lines changed

.github/build.sh

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -597,6 +597,7 @@ function compile_curl() {
597597
return
598598
fi
599599
get_and_cd curl-8.10.1.tar.gz curl_version
600+
patch_breakpoint $patches_real/curl-mbedtls-usage.patch apply
600601
curl_version+="+nghttp2-$nghttp2_version"
601602
curl_version+="+zlib-$zlib_version"
602603
mkdir build

patches/curl-mbedtls-usage.patch

Lines changed: 102 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,102 @@
1+
diff --strip-trailing-cr -Naur curl-8.10.1.old/lib/vtls/mbedtls.c curl-8.10.1.new/lib/vtls/mbedtls.c
2+
--- curl-8.10.1.old/lib/vtls/mbedtls.c 2024-12-22 20:24:54.944116200 +0100
3+
+++ curl-8.10.1.new/lib/vtls/mbedtls.c 2024-12-22 20:22:04.927962100 +0100
4+
@@ -113,6 +113,11 @@
5+
int *ciphersuites;
6+
BIT(initialized); /* mbedtls_ssl_context is initialized */
7+
BIT(sent_shutdown);
8+
+ BIT(ww_buffer_valid);
9+
+ unsigned char *ww_buffer;
10+
+ size_t ww_buffer_size;
11+
+ size_t ww_buffer_used;
12+
+ size_t ww_buffer_from;
13+
};
14+
15+
/* apply threading? */
16+
@@ -1174,14 +1179,73 @@
17+
struct mbed_ssl_backend_data *backend =
18+
(struct mbed_ssl_backend_data *)connssl->backend;
19+
int ret = -1;
20+
+ size_t orig_len = len;
21+
+
22+
+ if(backend->ww_buffer_valid) {
23+
+ if(backend->ww_buffer_used) {
24+
+ // if there were bytes in the fragment, match the last byte against what
25+
+ // libcurl is retrying to get us to send
26+
+ DEBUGASSERT(len);
27+
+ DEBUGASSERT(*(unsigned char *)mem == backend->ww_buffer[backend->ww_buffer_used - 1]);
28+
+ }
29+
+ // restore the same arguments as were passed to the last call (functionally
30+
+ // speaking anyway; the pointer will be different but the data it points to
31+
+ // will be the same)
32+
+ len = backend->ww_buffer_used - backend->ww_buffer_from;
33+
+ mem = backend->ww_buffer + backend->ww_buffer_from;
34+
+ }
35+
36+
(void)data;
37+
DEBUGASSERT(backend);
38+
ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
39+
40+
+ if(ret >= 0 && backend->ww_buffer_valid) {
41+
+ // some of the data we stashed away is done sending, but we can't fully give
42+
+ // control back to libcurl until all this data is done sending, and it may
43+
+ // very well yet result in MBEDTLS_ERR_SSL_WANT_WRITE returns from mbedtls
44+
+ DEBUGASSERT(backend->ww_buffer_from + ret <= backend->ww_buffer_used);
45+
+ backend->ww_buffer_from += ret;
46+
+ if(backend->ww_buffer_from < backend->ww_buffer_used)
47+
+ // if we're not done sending the data we stashed away, tell libcurl that
48+
+ // we're still working on it
49+
+ ret = MBEDTLS_ERR_SSL_WANT_WRITE;
50+
+ }
51+
+ if(ret != MBEDTLS_ERR_SSL_WANT_WRITE && backend->ww_buffer_valid && backend->ww_buffer_from == backend->ww_buffer_used) {
52+
+ // if there were bytes in the fragment, tell libcurl that we have finally
53+
+ // managed to send that one last byte that we kept for matching against; if
54+
+ // not, tell it that the lack of bytes has been successfully sent
55+
+ ret = backend->ww_buffer_used ? 1 : 0;
56+
+ backend->ww_buffer_from = 0;
57+
+ backend->ww_buffer_used = 0;
58+
+ backend->ww_buffer_valid = FALSE;
59+
+ }
60+
+ if(ret == MBEDTLS_ERR_SSL_WANT_WRITE && !backend->ww_buffer_valid) {
61+
+ if(backend->ww_buffer_size < len) {
62+
+ backend->ww_buffer_size = len;
63+
+ Curl_safefree(backend->ww_buffer);
64+
+ backend->ww_buffer = malloc(backend->ww_buffer_size);
65+
+ if(!backend->ww_buffer)
66+
+ return CURLE_OUT_OF_MEMORY;
67+
+ }
68+
+ memcpy(backend->ww_buffer, mem, len);
69+
+ backend->ww_buffer_used = len;
70+
+ backend->ww_buffer_valid = TRUE;
71+
+ if(len) {
72+
+ // if there were bytes in the fragment, report that all of them but the
73+
+ // last one has been sent (any number could be reported that is less than
74+
+ // len, but the remaining bytes will be attempted to sent again later and
75+
+ // we have to match them against what is already committed inside mbedtls;
76+
+ // it's by far the easiest to hold on to just one, which is fast to match)
77+
+ ret = len - 1;
78+
+ }
79+
+ // if there were no bytes in the fragment, let the original logic return
80+
+ // CURLE_AGAIN, as this is the only way to make libcurl keep trying to send
81+
+ // the lack of bytes
82+
+ }
83+
+
84+
if(ret < 0) {
85+
CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> -0x%04X",
86+
- len, -ret);
87+
+ orig_len, -ret);
88+
*curlcode = ((ret == MBEDTLS_ERR_SSL_WANT_WRITE)
89+
#ifdef TLS13_SUPPORT
90+
|| (ret == MBEDTLS_ERR_SSL_RECEIVED_NEW_SESSION_TICKET)
91+
@@ -1304,6 +1368,11 @@
92+
mbedtls_x509_crl_free(&backend->crl);
93+
#endif
94+
Curl_safefree(backend->ciphersuites);
95+
+ Curl_safefree(backend->ww_buffer);
96+
+ backend->ww_buffer_size = 0;
97+
+ backend->ww_buffer_used = 0;
98+
+ backend->ww_buffer_from = 0;
99+
+ backend->ww_buffer_valid = FALSE;
100+
mbedtls_ssl_config_free(&backend->config);
101+
mbedtls_ssl_free(&backend->ssl);
102+
mbedtls_ctr_drbg_free(&backend->ctr_drbg);

0 commit comments

Comments
 (0)