Skip to content

Commit 09b3296

Browse files
committed
Revise curl mbedtls fix
This is the official fix, see curl/curl#15846. The main difference is that we'll have to document our sockets as being picky about what is passed to them when retrying writes: the exact same must be passed as the previous time, potentially followed by new data.
1 parent 25b46c0 commit 09b3296

File tree

1 file changed

+33
-88
lines changed

1 file changed

+33
-88
lines changed

patches/curl-mbedtls-usage.patch

Lines changed: 33 additions & 88 deletions
Original file line numberDiff line numberDiff line change
@@ -1,102 +1,47 @@
11
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 @@
2+
--- curl-8.10.1.old/lib/vtls/mbedtls.c 2025-01-05 21:12:50.543969206 +0100
3+
+++ curl-8.10.1.new/lib/vtls/mbedtls.c 2025-01-05 21:12:50.583970677 +0100
4+
@@ -111,8 +111,10 @@
5+
const char *protocols[3];
6+
#endif
57
int *ciphersuites;
8+
+ size_t send_blocked_len;
69
BIT(initialized); /* mbedtls_ssl_context is initialized */
710
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;
11+
+ BIT(send_blocked);
1312
};
1413

1514
/* 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-
+ }
15+
@@ -1177,6 +1179,17 @@
3516

3617
(void)data;
3718
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
19+
+ /* mbedtls is picky when a mbedtls_ssl_write) was previously blocked.
20+
+ * It requires to be called with the same amount of bytes again, or it
21+
+ * will lose bytes, e.g. reporting all was sent but they were not.
22+
+ * Remember the blocked length and use that when set. */
23+
+ if(backend->send_blocked) {
24+
+ DEBUGASSERT(backend->send_blocked_len <= len);
25+
+ CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> previously blocked "
26+
+ "on %zu bytes", len, backend->send_blocked_len);
27+
+ len = backend->send_blocked_len;
8228
+ }
8329
+
30+
ret = mbedtls_ssl_write(&backend->ssl, (unsigned char *)mem, len);
31+
8432
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);
33+
@@ -1188,6 +1201,14 @@
9334
#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);
35+
)? CURLE_AGAIN : CURLE_SEND_ERROR;
36+
ret = -1;
37+
+ if((*curlcode == CURLE_AGAIN) && !backend->send_blocked) {
38+
+ backend->send_blocked = TRUE;
39+
+ backend->send_blocked_len = len;
40+
+ }
41+
+ }
42+
+ else {
43+
+ CURL_TRC_CF(data, cf, "mbedtls_ssl_write(len=%zu) -> %d", len, ret);
44+
+ backend->send_blocked = FALSE;
45+
}
46+
47+
return ret;

0 commit comments

Comments
 (0)