| From a801ebdc2b1c008fa72c31f1bf7773d99e6e2a2d Mon Sep 17 00:00:00 2001 |
| From: Harry Sintonen <sintonen@iki.fi> |
| Date: Tue, 3 Aug 2021 08:41:45 +0000 |
| Subject: [PATCH] openssl: associate/detach the transfer from connection |
| |
| CVE-2021-22901 |
| |
| Bug: https://curl.se/docs/CVE-2021-22901.html |
| |
| CVE: CVE-2021-22901 |
| |
| Upstream-Status: Backport [https://github.com/curl/curl/commit/7f4a9a9b2a49547eae24d2e19bc5c346e9026479] |
| |
| Signed-off-by: Mingli Yu <mingli.yu@windriver.com> |
| --- |
| lib/multi.c | 5 +- |
| lib/vtls/gskit.c | 4 +- |
| lib/vtls/gtls.c | 4 +- |
| lib/vtls/mbedtls.c | 4 +- |
| lib/vtls/mesalink.c | 4 +- |
| lib/vtls/nss.c | 4 +- |
| lib/vtls/openssl.c | 146 +++++++++++++++++++++++++++++++------------ |
| lib/vtls/schannel.c | 6 +- |
| lib/vtls/sectransp.c | 4 +- |
| lib/vtls/vtls.c | 23 ++++++- |
| lib/vtls/vtls.h | 12 ++++ |
| lib/vtls/wolfssl.c | 4 +- |
| 12 files changed, 170 insertions(+), 50 deletions(-) |
| |
| diff --git a/lib/multi.c b/lib/multi.c |
| index 85707a1..a4ff9ac 100644 |
| --- a/lib/multi.c |
| +++ b/lib/multi.c |
| @@ -875,8 +875,10 @@ bool Curl_multiplex_wanted(const struct Curl_multi *multi) |
| void Curl_detach_connnection(struct Curl_easy *data) |
| { |
| struct connectdata *conn = data->conn; |
| - if(conn) |
| + if(conn) { |
| Curl_llist_remove(&conn->easyq, &data->conn_queue, NULL); |
| + Curl_ssl_detach_conn(data, conn); |
| + } |
| data->conn = NULL; |
| } |
| |
| @@ -893,6 +895,7 @@ void Curl_attach_connnection(struct Curl_easy *data, |
| data->conn = conn; |
| Curl_llist_insert_next(&conn->easyq, conn->easyq.tail, data, |
| &data->conn_queue); |
| + Curl_ssl_associate_conn(data, conn); |
| } |
| |
| static int waitconnect_getsock(struct connectdata *conn, |
| diff --git a/lib/vtls/gskit.c b/lib/vtls/gskit.c |
| index 9b5f649..bd9c602 100644 |
| --- a/lib/vtls/gskit.c |
| +++ b/lib/vtls/gskit.c |
| @@ -1282,7 +1282,9 @@ const struct Curl_ssl Curl_ssl_gskit = { |
| Curl_none_set_engine_default, /* set_engine_default */ |
| Curl_none_engines_list, /* engines_list */ |
| Curl_none_false_start, /* false_start */ |
| - NULL /* sha256sum */ |
| + NULL, /* sha256sum */ |
| + NULL, /* associate_connection */ |
| + NULL /* disassociate_connection */ |
| }; |
| |
| #endif /* USE_GSKIT */ |
| diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c |
| index 28ca528..24e036b 100644 |
| --- a/lib/vtls/gtls.c |
| +++ b/lib/vtls/gtls.c |
| @@ -1683,7 +1683,9 @@ const struct Curl_ssl Curl_ssl_gnutls = { |
| Curl_none_set_engine_default, /* set_engine_default */ |
| Curl_none_engines_list, /* engines_list */ |
| Curl_none_false_start, /* false_start */ |
| - gtls_sha256sum /* sha256sum */ |
| + gtls_sha256sum, /* sha256sum */ |
| + NULL, /* associate_connection */ |
| + NULL /* disassociate_connection */ |
| }; |
| |
| #endif /* USE_GNUTLS */ |
| diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c |
| index bd0e080..fc973c7 100644 |
| --- a/lib/vtls/mbedtls.c |
| +++ b/lib/vtls/mbedtls.c |
| @@ -1112,7 +1112,9 @@ const struct Curl_ssl Curl_ssl_mbedtls = { |
| Curl_none_set_engine_default, /* set_engine_default */ |
| Curl_none_engines_list, /* engines_list */ |
| Curl_none_false_start, /* false_start */ |
| - mbedtls_sha256sum /* sha256sum */ |
| + mbedtls_sha256sumi, /* sha256sum */ |
| + NULL, /* associate_connection */ |
| + NULL /* disassociate_connection */ |
| }; |
| |
| #endif /* USE_MBEDTLS */ |
| diff --git a/lib/vtls/mesalink.c b/lib/vtls/mesalink.c |
| index ad807d3..8a91487 100644 |
| --- a/lib/vtls/mesalink.c |
| +++ b/lib/vtls/mesalink.c |
| @@ -666,7 +666,9 @@ const struct Curl_ssl Curl_ssl_mesalink = { |
| Curl_none_set_engine_default, /* set_engine_default */ |
| Curl_none_engines_list, /* engines_list */ |
| Curl_none_false_start, /* false_start */ |
| - NULL /* sha256sum */ |
| + NULL, /* sha256sum */ |
| + NULL, /* associate_connection */ |
| + NULL /* disassociate_connection */ |
| }; |
| |
| #endif |
| diff --git a/lib/vtls/nss.c b/lib/vtls/nss.c |
| index e5ab71c..fb9f763 100644 |
| --- a/lib/vtls/nss.c |
| +++ b/lib/vtls/nss.c |
| @@ -2444,7 +2444,9 @@ const struct Curl_ssl Curl_ssl_nss = { |
| Curl_none_set_engine_default, /* set_engine_default */ |
| Curl_none_engines_list, /* engines_list */ |
| nss_false_start, /* false_start */ |
| - nss_sha256sum /* sha256sum */ |
| + nss_sha256sum, /* sha256sum */ |
| + NULL, /* associate_connection */ |
| + NULL /* disassociate_connection */ |
| }; |
| |
| #endif /* USE_NSS */ |
| diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c |
| index 8304264..946b4c5 100644 |
| --- a/lib/vtls/openssl.c |
| +++ b/lib/vtls/openssl.c |
| @@ -244,6 +244,10 @@ struct ssl_backend_data { |
| #endif |
| }; |
| |
| +static void ossl_associate_connection(struct Curl_easy *data, |
| + struct connectdata *conn, |
| + int sockindex); |
| + |
| /* |
| * Number of bytes to read from the random number seed file. This must be |
| * a finite value (because some entropy "files" like /dev/urandom have |
| @@ -2527,6 +2531,7 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, |
| curl_socket_t sockfd = conn->sock[sockindex]; |
| struct ssl_connect_data *connssl = &conn->ssl[sockindex]; |
| ctx_option_t ctx_options = 0; |
| + void *ssl_sessionid = NULL; |
| |
| #ifdef SSL_CTRL_SET_TLSEXT_HOSTNAME |
| bool sni; |
| @@ -3224,46 +3229,23 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data, |
| } |
| #endif |
| |
| - /* Check if there's a cached ID we can/should use here! */ |
| - if(SSL_SET_OPTION(primary.sessionid)) { |
| - void *ssl_sessionid = NULL; |
| - int data_idx = ossl_get_ssl_data_index(); |
| - int connectdata_idx = ossl_get_ssl_conn_index(); |
| - int sockindex_idx = ossl_get_ssl_sockindex_index(); |
| - int proxy_idx = ossl_get_proxy_index(); |
| - |
| - if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 && |
| - proxy_idx >= 0) { |
| - /* Store the data needed for the "new session" callback. |
| - * The sockindex is stored as a pointer to an array element. */ |
| - SSL_set_ex_data(backend->handle, data_idx, data); |
| - SSL_set_ex_data(backend->handle, connectdata_idx, conn); |
| - SSL_set_ex_data(backend->handle, sockindex_idx, conn->sock + sockindex); |
| -#ifndef CURL_DISABLE_PROXY |
| - SSL_set_ex_data(backend->handle, proxy_idx, SSL_IS_PROXY() ? (void *) 1: |
| - NULL); |
| -#else |
| - SSL_set_ex_data(backend->handle, proxy_idx, NULL); |
| -#endif |
| - |
| - } |
| + ossl_associate_connection(data, conn, sockindex); |
| |
| - Curl_ssl_sessionid_lock(data); |
| - if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, |
| - &ssl_sessionid, NULL, sockindex)) { |
| - /* we got a session id, use it! */ |
| - if(!SSL_set_session(backend->handle, ssl_sessionid)) { |
| - Curl_ssl_sessionid_unlock(data); |
| - failf(data, "SSL: SSL_set_session failed: %s", |
| - ossl_strerror(ERR_get_error(), error_buffer, |
| - sizeof(error_buffer))); |
| - return CURLE_SSL_CONNECT_ERROR; |
| - } |
| - /* Informational message */ |
| - infof(data, "SSL re-using session ID\n"); |
| + Curl_ssl_sessionid_lock(data); |
| + if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE, |
| + &ssl_sessionid, NULL, sockindex)) { |
| + /* we got a session id, use it! */ |
| + if(!SSL_set_session(backend->handle, ssl_sessionid)) { |
| + Curl_ssl_sessionid_unlock(data); |
| + failf(data, "SSL: SSL_set_session failed: %s", |
| + ossl_strerror(ERR_get_error(), error_buffer, |
| + sizeof(error_buffer))); |
| + return CURLE_SSL_CONNECT_ERROR; |
| } |
| - Curl_ssl_sessionid_unlock(data); |
| + /* Informational message */ |
| + infof(data, "SSL re-using session ID\n"); |
| } |
| + Curl_ssl_sessionid_unlock(data); |
| |
| #ifndef CURL_DISABLE_PROXY |
| if(conn->proxy_ssl[sockindex].use) { |
| @@ -4481,6 +4463,90 @@ static void *ossl_get_internals(struct ssl_connect_data *connssl, |
| (void *)backend->ctx : (void *)backend->handle; |
| } |
| |
| +static void ossl_associate_connection(struct Curl_easy *data, |
| + struct connectdata *conn, |
| + int sockindex) |
| +{ |
| + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; |
| + struct ssl_backend_data *backend = connssl->backend; |
| + |
| + /* If we don't have SSL context, do nothing. */ |
| + if(!backend->handle) |
| + return; |
| + |
| + if(SSL_SET_OPTION(primary.sessionid)) { |
| + int data_idx = ossl_get_ssl_data_index(); |
| + int connectdata_idx = ossl_get_ssl_conn_index(); |
| + int sockindex_idx = ossl_get_ssl_sockindex_index(); |
| + int proxy_idx = ossl_get_proxy_index(); |
| + |
| + if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 && |
| + proxy_idx >= 0) { |
| + /* Store the data needed for the "new session" callback. |
| + * The sockindex is stored as a pointer to an array element. */ |
| + SSL_set_ex_data(backend->handle, data_idx, data); |
| + SSL_set_ex_data(backend->handle, connectdata_idx, conn); |
| + SSL_set_ex_data(backend->handle, sockindex_idx, conn->sock + sockindex); |
| +#ifndef CURL_DISABLE_PROXY |
| + SSL_set_ex_data(backend->handle, proxy_idx, SSL_IS_PROXY() ? (void *) 1: |
| + NULL); |
| +#else |
| + SSL_set_ex_data(backend->handle, proxy_idx, NULL); |
| +#endif |
| + } |
| + } |
| +} |
| + |
| +/* |
| + * Starting with TLS 1.3, the ossl_new_session_cb callback gets called after |
| + * the handshake. If the transfer that sets up the callback gets killed before |
| + * this callback arrives, we must make sure to properly clear the data to |
| + * avoid UAF problems. A future optimization could be to instead store another |
| + * transfer that might still be using the same connection. |
| + */ |
| + |
| +static void ossl_disassociate_connection(struct Curl_easy *data, |
| + int sockindex) |
| +{ |
| + struct connectdata *conn = data->conn; |
| + struct ssl_connect_data *connssl = &conn->ssl[sockindex]; |
| + struct ssl_backend_data *backend = connssl->backend; |
| + |
| + /* If we don't have SSL context, do nothing. */ |
| + if(!backend->handle) |
| + return; |
| + |
| + if(SSL_SET_OPTION(primary.sessionid)) { |
| + bool isproxy = FALSE; |
| + bool incache; |
| + void *old_ssl_sessionid = NULL; |
| + int data_idx = ossl_get_ssl_data_index(); |
| + int connectdata_idx = ossl_get_ssl_conn_index(); |
| + int sockindex_idx = ossl_get_ssl_sockindex_index(); |
| + int proxy_idx = ossl_get_proxy_index(); |
| + |
| + if(data_idx >= 0 && connectdata_idx >= 0 && sockindex_idx >= 0 && |
| + proxy_idx >= 0) { |
| + /* Invalidate the session cache entry, if any */ |
| + isproxy = SSL_get_ex_data(backend->handle, proxy_idx) ? TRUE : FALSE; |
| + |
| + /* Disable references to data in "new session" callback to avoid |
| + * accessing a stale pointer. */ |
| + SSL_set_ex_data(backend->handle, data_idx, NULL); |
| + SSL_set_ex_data(backend->handle, connectdata_idx, NULL); |
| + SSL_set_ex_data(backend->handle, sockindex_idx, NULL); |
| + SSL_set_ex_data(backend->handle, proxy_idx, NULL); |
| + } |
| + |
| + Curl_ssl_sessionid_lock(data); |
| + incache = !(Curl_ssl_getsessionid(data, conn, isproxy, |
| + &old_ssl_sessionid, NULL, sockindex)); |
| + if(incache) |
| + Curl_ssl_delsessionid(data, old_ssl_sessionid); |
| + Curl_ssl_sessionid_unlock(data); |
| + } |
| +} |
| + |
| const struct Curl_ssl Curl_ssl_openssl = { |
| { CURLSSLBACKEND_OPENSSL, "openssl" }, /* info */ |
| |
| @@ -4514,10 +4580,12 @@ const struct Curl_ssl Curl_ssl_openssl = { |
| ossl_engines_list, /* engines_list */ |
| Curl_none_false_start, /* false_start */ |
| #if (OPENSSL_VERSION_NUMBER >= 0x0090800fL) && !defined(OPENSSL_NO_SHA256) |
| - ossl_sha256sum /* sha256sum */ |
| + ossl_sha256sum, /* sha256sum */ |
| #else |
| - NULL /* sha256sum */ |
| + NULL, /* sha256sum */ |
| #endif |
| + ossl_associate_connection, /* associate_connection */ |
| + ossl_disassociate_connection /* disassociate_connection */ |
| }; |
| |
| #endif /* USE_OPENSSL */ |
| diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c |
| index 670310d..596106a 100644 |
| --- a/lib/vtls/schannel.c |
| +++ b/lib/vtls/schannel.c |
| @@ -325,7 +325,7 @@ get_alg_id_by_name(char *name) |
| |
| static CURLcode |
| set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers, |
| - int *algIds) |
| + ALG_ID *algIds) |
| { |
| char *startCur = ciphers; |
| int algCount = 0; |
| @@ -2429,7 +2429,9 @@ const struct Curl_ssl Curl_ssl_schannel = { |
| Curl_none_set_engine_default, /* set_engine_default */ |
| Curl_none_engines_list, /* engines_list */ |
| Curl_none_false_start, /* false_start */ |
| - schannel_sha256sum /* sha256sum */ |
| + schannel_sha256sum, /* sha256sum */ |
| + NULL, /* associate_connection */ |
| + NULL /* disassociate_connection */ |
| }; |
| |
| #endif /* USE_SCHANNEL */ |
| diff --git a/lib/vtls/sectransp.c b/lib/vtls/sectransp.c |
| index 6d1ea7e..37b41f8 100644 |
| --- a/lib/vtls/sectransp.c |
| +++ b/lib/vtls/sectransp.c |
| @@ -3311,7 +3311,9 @@ const struct Curl_ssl Curl_ssl_sectransp = { |
| Curl_none_set_engine_default, /* set_engine_default */ |
| Curl_none_engines_list, /* engines_list */ |
| sectransp_false_start, /* false_start */ |
| - sectransp_sha256sum /* sha256sum */ |
| + sectransp_sha256sum, /* sha256sum */ |
| + NULL, /* associate_connection */ |
| + NULL /* disassociate_connection */ |
| }; |
| |
| #ifdef __clang__ |
| diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c |
| index 00b6268..59a7efb 100644 |
| --- a/lib/vtls/vtls.c |
| +++ b/lib/vtls/vtls.c |
| @@ -579,6 +579,25 @@ CURLcode Curl_ssl_addsessionid(struct Curl_easy *data, |
| return CURLE_OK; |
| } |
| |
| +void Curl_ssl_associate_conn(struct Curl_easy *data, |
| + struct connectdata *conn) |
| +{ |
| + if(Curl_ssl->associate_connection) { |
| + Curl_ssl->associate_connection(data, conn, FIRSTSOCKET); |
| + if(conn->sock[SECONDARYSOCKET] && conn->bits.sock_accepted) |
| + Curl_ssl->associate_connection(data, conn, SECONDARYSOCKET); |
| + } |
| +} |
| + |
| +void Curl_ssl_detach_conn(struct Curl_easy *data, |
| + struct connectdata *conn) |
| +{ |
| + if(Curl_ssl->disassociate_connection) { |
| + Curl_ssl->disassociate_connection(data, FIRSTSOCKET); |
| + if(conn->sock[SECONDARYSOCKET] && conn->bits.sock_accepted) |
| + Curl_ssl->disassociate_connection(data, SECONDARYSOCKET); |
| + } |
| +} |
| |
| void Curl_ssl_close_all(struct Curl_easy *data) |
| { |
| @@ -1212,7 +1231,9 @@ static const struct Curl_ssl Curl_ssl_multi = { |
| Curl_none_set_engine_default, /* set_engine_default */ |
| Curl_none_engines_list, /* engines_list */ |
| Curl_none_false_start, /* false_start */ |
| - NULL /* sha256sum */ |
| + NULL, /* sha256sum */ |
| + NULL, /* associate_connection */ |
| + NULL /* disassociate_connection */ |
| }; |
| |
| const struct Curl_ssl *Curl_ssl = |
| diff --git a/lib/vtls/vtls.h b/lib/vtls/vtls.h |
| index 1351215..94049f9 100644 |
| --- a/lib/vtls/vtls.h |
| +++ b/lib/vtls/vtls.h |
| @@ -75,6 +75,11 @@ struct Curl_ssl { |
| bool (*false_start)(void); |
| CURLcode (*sha256sum)(const unsigned char *input, size_t inputlen, |
| unsigned char *sha256sum, size_t sha256sumlen); |
| + |
| + void (*associate_connection)(struct Curl_easy *data, |
| + struct connectdata *conn, |
| + int sockindex); |
| + void (*disassociate_connection)(struct Curl_easy *data, int sockindex); |
| }; |
| |
| #ifdef USE_SSL |
| @@ -264,6 +269,11 @@ bool Curl_ssl_cert_status_request(void); |
| |
| bool Curl_ssl_false_start(void); |
| |
| +void Curl_ssl_associate_conn(struct Curl_easy *data, |
| + struct connectdata *conn); |
| +void Curl_ssl_detach_conn(struct Curl_easy *data, |
| + struct connectdata *conn); |
| + |
| #define SSL_SHUTDOWN_TIMEOUT 10000 /* ms */ |
| |
| #else /* if not USE_SSL */ |
| @@ -290,6 +300,8 @@ bool Curl_ssl_false_start(void); |
| #define Curl_ssl_cert_status_request() FALSE |
| #define Curl_ssl_false_start() FALSE |
| #define Curl_ssl_tls13_ciphersuites() FALSE |
| +#define Curl_ssl_associate_conn(a,b) Curl_nop_stmt |
| +#define Curl_ssl_detach_conn(a,b) Curl_nop_stmt |
| #endif |
| |
| #endif /* HEADER_CURL_VTLS_H */ |
| diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c |
| index f1b12b1..f734a84 100644 |
| --- a/lib/vtls/wolfssl.c |
| +++ b/lib/vtls/wolfssl.c |
| @@ -1165,7 +1165,9 @@ const struct Curl_ssl Curl_ssl_wolfssl = { |
| Curl_none_set_engine_default, /* set_engine_default */ |
| Curl_none_engines_list, /* engines_list */ |
| Curl_none_false_start, /* false_start */ |
| - wolfssl_sha256sum /* sha256sum */ |
| + wolfssl_sha256sum, /* sha256sum */ |
| + NULL, /* associate_connection */ |
| + NULL /* disassociate_connection */ |
| }; |
| |
| #endif |
| -- |
| 2.31.1 |
| |