Toggle diff (488 lines)
diff --git a/gnu/local.mk b/gnu/local.mk
index f2d595f2cc..cf6f35363f 100644
--- a/gnu/local.mk
+++ b/gnu/local.mk
@@ -919,6 +919,8 @@ dist_patch_DATA = \
%D%/packages/patches/crda-optional-gcrypt.patch \
%D%/packages/patches/clucene-contribs-lib.patch \
%D%/packages/patches/cube-nocheck.patch \
+ %D%/packages/patches/curl-CVE-2021-22890.patch \
+ %D%/packages/patches/curl-CVE-2021-22876.patch \
%D%/packages/patches/curl-use-ssl-cert-env.patch \
%D%/packages/patches/cursynth-wave-rand.patch \
%D%/packages/patches/cvs-CVE-2017-12836.patch \
diff --git a/gnu/packages/curl.scm b/gnu/packages/curl.scm
index 730676875c..fa02f281cf 100644
--- a/gnu/packages/curl.scm
+++ b/gnu/packages/curl.scm
@@ -61,7 +61,9 @@
(sha256
(base32
"12w7gskrglg6qrmp822j37fmbr0icrcxv7rib1fy5xiw80n5z7cr"))
- (patches (search-patches "curl-use-ssl-cert-env.patch"))))
+ (patches (search-patches "curl-use-ssl-cert-env.patch"
+ "curl-CVE-2021-22876.patch"
+ "curl-CVE-2021-22890.patch"))))
(build-system gnu-build-system)
(outputs '("out"
"doc")) ;1.2 MiB of man3 pages
diff --git a/gnu/packages/patches/curl-CVE-2021-22876.patch b/gnu/packages/patches/curl-CVE-2021-22876.patch
new file mode 100644
index 0000000000..b67a1be16a
--- /dev/null
+++ b/gnu/packages/patches/curl-CVE-2021-22876.patch
@@ -0,0 +1,147 @@
+From 7214288898f5625a6cc196e22a74232eada7861c Mon Sep 17 00:00:00 2001
+From: Viktor Szakats <commit@vsz.me>
+Date: Tue, 23 Feb 2021 14:54:46 +0100
+Subject: [PATCH] transfer: strip credentials from the auto-referer header
+ field
+
+Added test 2081 to verify.
+
+CVE-2021-22876
+
+Bug: https://curl.se/docs/CVE-2021-22876.html
+---
+ lib/transfer.c | 25 ++++++++++++++--
+ tests/data/Makefile.inc | 2 +-
+ tests/data/test2081 | 66 +++++++++++++++++++++++++++++++++++++++++
+ 3 files changed, 90 insertions(+), 3 deletions(-)
+ create mode 100644 tests/data/test2081
+
+diff --git a/lib/transfer.c b/lib/transfer.c
+index 1976bc0338bc..a68c021c84d6 100644
+--- a/lib/transfer.c
++++ b/lib/transfer.c
+@@ -1581,6 +1581,9 @@ CURLcode Curl_follow(struct Curl_easy *data,
+ data->state.followlocation++; /* count location-followers */
+
+ if(data->set.http_auto_referer) {
++ CURLU *u;
++ char *referer;
++
+ /* We are asked to automatically set the previous URL as the referer
+ when we get the next URL. We pick the ->url field, which may or may
+ not be 100% correct */
+@@ -1590,9 +1593,27 @@ CURLcode Curl_follow(struct Curl_easy *data,
+ data->change.referer_alloc = FALSE;
+ }
+
+- data->change.referer = strdup(data->change.url);
+- if(!data->change.referer)
++ /* Make a copy of the URL without crenditals and fragment */
++ u = curl_url();
++ if(!u)
++ return CURLE_OUT_OF_MEMORY;
++
++ uc = curl_url_set(u, CURLUPART_URL, data->change.url, 0);
++ if(!uc)
++ uc = curl_url_set(u, CURLUPART_FRAGMENT, NULL, 0);
++ if(!uc)
++ uc = curl_url_set(u, CURLUPART_USER, NULL, 0);
++ if(!uc)
++ uc = curl_url_set(u, CURLUPART_PASSWORD, NULL, 0);
++ if(!uc)
++ uc = curl_url_get(u, CURLUPART_URL, &referer, 0);
++
++ curl_url_cleanup(u);
++
++ if(uc || referer == NULL)
+ return CURLE_OUT_OF_MEMORY;
++
++ data->change.referer = referer;
+ data->change.referer_alloc = TRUE; /* yes, free this later */
+ }
+ }
+diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
+index 2c7a0ca89fd8..ea52683d2254 100644
+--- a/tests/data/Makefile.inc
++++ b/tests/data/Makefile.inc
+@@ -225,7 +225,7 @@ test2064 test2065 test2066 test2067 test2068 test2069 \
+ test2064 test2065 test2066 test2067 test2068 test2069 test2070 \
+ test2071 test2072 test2073 test2074 test2075 test2076 test2077 \
+ test2078 \
+-test2080 \
++test2080 test2081 \
+ test2100 \
+ \
+ test3000 test3001 test3002 test3003 test3004 test3005 test3006 test3007 \
+diff --git a/tests/data/test2081 b/tests/data/test2081
+new file mode 100644
+index 000000000000..a6733e737beb
+--- /dev/null
++++ b/tests/data/test2081
+@@ -0,0 +1,66 @@
++<testcase>
++<info>
++<keywords>
++HTTP
++HTTP GET
++referer
++followlocation
++--write-out
++</keywords>
++</info>
++
++# Server-side
++<reply>
++<data nocheck="yes">
++HTTP/1.1 301 This is a weirdo text message swsclose
++Location: data/%TESTNUMBER0002.txt?coolsite=yes
++Content-Length: 62
++Connection: close
++
++This server reply is for testing a simple Location: following
++</data>
++</reply>
++
++# Client-side
++<client>
++<server>
++http
++</server>
++ <name>
++Automatic referrer credential and anchor stripping check
++ </name>
++ <command>
++http://user:pass@%HOSTIP:%HTTPPORT/we/want/our/%TESTNUMBER#anchor --location --referer ';auto' --write-out '%{referer}\n'
++</command>
++</client>
++
++# Verify data after the test has been "shot"
++<verify>
++<errorcode>
++52
++</errorcode>
++<protocol>
++GET /we/want/our/%TESTNUMBER HTTP/1.1
++Host: %HOSTIP:%HTTPPORT
++Authorization: Basic dXNlcjpwYXNz
++User-Agent: curl/%VERSION
++Accept: */*
++
++GET /we/want/our/data/%TESTNUMBER0002.txt?coolsite=yes HTTP/1.1
++Host: %HOSTIP:%HTTPPORT
++Authorization: Basic dXNlcjpwYXNz
++User-Agent: curl/%VERSION
++Accept: */*
++Referer: http://%HOSTIP:%HTTPPORT/we/want/our/%TESTNUMBER
++
++</protocol>
++<stdout>
++HTTP/1.1 301 This is a weirdo text message swsclose
++Location: data/%TESTNUMBER0002.txt?coolsite=yes
++Content-Length: 62
++Connection: close
++
++http://%HOSTIP:%HTTPPORT/we/want/our/%TESTNUMBER
++</stdout>
++</verify>
++</testcase>
diff --git a/gnu/packages/patches/curl-CVE-2021-22890.patch b/gnu/packages/patches/curl-CVE-2021-22890.patch
new file mode 100644
index 0000000000..f01bc20530
--- /dev/null
+++ b/gnu/packages/patches/curl-CVE-2021-22890.patch
@@ -0,0 +1,499 @@
+From b09c8ee15771c614c4bf3ddac893cdb12187c844 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Fri, 19 Mar 2021 12:38:49 +0100
+Subject: [PATCH] vtls: add 'isproxy' argument to Curl_ssl_get/addsessionid()
+
+To make sure we set and extract the correct session.
+
+Reported-by: Mingtao Yang
+Bug: https://curl.se/docs/CVE-2021-22890.html
+
+CVE-2021-22890
+---
+ lib/vtls/bearssl.c | 8 +++++--
+ lib/vtls/gtls.c | 12 ++++++----
+ lib/vtls/mbedtls.c | 12 ++++++----
+ lib/vtls/mesalink.c | 14 ++++++++----
+ lib/vtls/openssl.c | 54 +++++++++++++++++++++++++++++++++-----------
+ lib/vtls/schannel.c | 10 ++++----
+ lib/vtls/sectransp.c | 10 ++++----
+ lib/vtls/vtls.c | 12 +++++++---
+ lib/vtls/vtls.h | 2 ++
+ lib/vtls/wolfssl.c | 13 +++++++----
+ 10 files changed, 103 insertions(+), 44 deletions(-)
+
+diff --git a/lib/vtls/bearssl.c b/lib/vtls/bearssl.c
+index 36c32d8d55be..39fc1a29209c 100644
+--- a/lib/vtls/bearssl.c
++++ b/lib/vtls/bearssl.c
+@@ -375,7 +375,8 @@ static CURLcode bearssl_connect_step1(struct Curl_easy *data,
+ void *session;
+
+ Curl_ssl_sessionid_lock(data);
+- if(!Curl_ssl_getsessionid(data, conn, &session, NULL, sockindex)) {
++ if(!Curl_ssl_getsessionid(data, conn, SSL_IS_PROXY() ? TRUE : FALSE,
++ &session, NULL, sockindex)) {
+ br_ssl_engine_set_session_parameters(&backend->ctx.eng, session);
+ infof(data, "BearSSL: re-using session ID\n");
+ }
+@@ -571,10 +572,13 @@ static CURLcode bearssl_connect_step3(struct Curl_easy *data,
+ br_ssl_engine_get_session_parameters(&backend->ctx.eng, session);
+ Curl_ssl_sessionid_lock(data);
+ incache = !(Curl_ssl_getsessionid(data, conn,
++ SSL_IS_PROXY() ? TRUE : FALSE,
+ &oldsession, NULL, sockindex));
+ if(incache)
+ Curl_ssl_delsessionid(data, oldsession);
+- ret = Curl_ssl_addsessionid(data, conn, session, 0, sockindex);
++ ret = Curl_ssl_addsessionid(data, conn,
++ SSL_IS_PROXY() ? TRUE : FALSE,
++ session, 0, sockindex);
+ Curl_ssl_sessionid_unlock(data);
+ if(ret) {
+ free(session);
+diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c
+index a75937b4646c..3b0d940a60e1 100644
+--- a/lib/vtls/gtls.c
++++ b/lib/vtls/gtls.c
+@@ -727,6 +727,7 @@ gtls_connect_step1(struct Curl_easy *data,
+
+ Curl_ssl_sessionid_lock(data);
+ if(!Curl_ssl_getsessionid(data, conn,
++ SSL_IS_PROXY() ? TRUE : FALSE,
+ &ssl_sessionid, &ssl_idsize, sockindex)) {
+ /* we got a session id, use it! */
+ gnutls_session_set_data(session, ssl_sessionid, ssl_idsize);
+@@ -1286,8 +1287,9 @@ gtls_connect_step3(struct Curl_easy *data,
+ gnutls_session_get_data(session, connect_sessionid, &connect_idsize);
+
+ Curl_ssl_sessionid_lock(data);
+- incache = !(Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL,
+- sockindex));
++ incache = !(Curl_ssl_getsessionid(data, conn,
++ SSL_IS_PROXY() ? TRUE : FALSE,
++ &ssl_sessionid, NULL, sockindex));
+ if(incache) {
+ /* there was one before in the cache, so instead of risking that the
+ previous one was rejected, we just kill that and store the new */
+@@ -1295,8 +1297,10 @@ gtls_connect_step3(struct Curl_easy *data,
+ }
+
+ /* store this session id */
+- result = Curl_ssl_addsessionid(data, conn, connect_sessionid,
+- connect_idsize, sockindex);
++ result = Curl_ssl_addsessionid(data, conn,
++ SSL_IS_PROXY() ? TRUE : FALSE,
++ connect_sessionid, connect_idsize,
++ sockindex);
+ Curl_ssl_sessionid_unlock(data);
+ if(result) {
+ free(connect_sessionid);
+diff --git a/lib/vtls/mbedtls.c b/lib/vtls/mbedtls.c
+index 95cd4d99b665..93a7ac1fd87d 100644
+--- a/lib/vtls/mbedtls.c
++++ b/lib/vtls/mbedtls.c
+@@ -463,7 +463,9 @@ mbed_connect_step1(struct Curl_easy *data, struct connectdata *conn,
+ void *old_session = NULL;
+
+ Curl_ssl_sessionid_lock(data);
+- if(!Curl_ssl_getsessionid(data, conn, &old_session, NULL, sockindex)) {
++ if(!Curl_ssl_getsessionid(data, conn,
++ SSL_IS_PROXY() ? TRUE : FALSE,
++ &old_session, NULL, sockindex)) {
+ ret = mbedtls_ssl_set_session(&backend->ssl, old_session);
+ if(ret) {
+ Curl_ssl_sessionid_unlock(data);
+@@ -724,6 +726,7 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
+ int ret;
+ mbedtls_ssl_session *our_ssl_sessionid;
+ void *old_ssl_sessionid = NULL;
++ bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
+
+ our_ssl_sessionid = malloc(sizeof(mbedtls_ssl_session));
+ if(!our_ssl_sessionid)
+@@ -742,11 +745,12 @@ mbed_connect_step3(struct Curl_easy *data, struct connectdata *conn,
+
+ /* If there's already a matching session in the cache, delete it */
+ Curl_ssl_sessionid_lock(data);
+- if(!Curl_ssl_getsessionid(data, conn, &old_ssl_sessionid, NULL, sockindex))
++ if(!Curl_ssl_getsessionid(data, conn, isproxy, &old_ssl_sessionid, NULL,
++ sockindex))
+ Curl_ssl_delsessionid(data, old_ssl_sessionid);
+
+- retcode = Curl_ssl_addsessionid(data, conn,
+- our_ssl_sessionid, 0, sockindex);
++ retcode = Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid,
++ 0, sockindex);
+ Curl_ssl_sessionid_unlock(data);
+ if(retcode) {
+ mbedtls_ssl_session_free(our_ssl_sessionid);
+diff --git a/lib/vtls/mesalink.c b/lib/vtls/mesalink.c
+index 4f1ab8627f49..5d6a1495d790 100644
+--- a/lib/vtls/mesalink.c
++++ b/lib/vtls/mesalink.c
+@@ -261,7 +261,9 @@ mesalink_connect_step1(struct Curl_easy *data,
+ void *ssl_sessionid = NULL;
+
+ Curl_ssl_sessionid_lock(data);
+- if(!Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL, sockindex)) {
++ 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);
+@@ -345,13 +347,14 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
+ bool incache;
+ SSL_SESSION *our_ssl_sessionid;
+ void *old_ssl_sessionid = NULL;
++ bool isproxy = SSL_IS_PROXY() ? TRUE : FALSE;
+
+ our_ssl_sessionid = SSL_get_session(BACKEND->handle);
+
+ Curl_ssl_sessionid_lock(data);
+ incache =
+- !(Curl_ssl_getsessionid(data, conn,
+- &old_ssl_sessionid, NULL, sockindex));
++ !(Curl_ssl_getsessionid(data, conn, isproxy, &old_ssl_sessionid, NULL,
++ sockindex));
+ if(incache) {
+ if(old_ssl_sessionid != our_ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing\n");
+@@ -361,8 +364,9 @@ mesalink_connect_step3(struct connectdata *conn, int sockindex)
+ }
+
+ if(!incache) {
+- result = Curl_ssl_addsessionid(
+- data, conn, our_ssl_sessionid, 0 /* unknown size */, sockindex);
++ result =
++ Curl_ssl_addsessionid(data, conn, isproxy, our_ssl_sessionid, 0,
++ sockindex);
+ if(result) {
+ Curl_ssl_sessionid_unlock(data);
+ failf(data, "failed to store ssl session");
+diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c
+index 498f8b9d1d08..68b98984b460 100644
+--- a/lib/vtls/openssl.c
++++ b/lib/vtls/openssl.c
+@@ -393,12 +393,23 @@ static int ossl_get_ssl_conn_index(void)
+ */
+ static int ossl_get_ssl_sockindex_index(void)
+ {
+- static int ssl_ex_data_sockindex_index = -1;
+- if(ssl_ex_data_sockindex_index < 0) {
+- ssl_ex_data_sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL,
+- NULL);
++ static int sockindex_index = -1;
++ if(sockindex_index < 0) {
++ sockindex_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
+ }
+- return ssl_ex_data_sockindex_index;
++ return sockindex_index;
++}
++
++/* Return an extra data index for proxy boolean.
++ * This index can be used with SSL_get_ex_data() and SSL_set_ex_data().
++ */
++static int ossl_get_proxy_index(void)
++{
++ static int proxy_index = -1;
++ if(proxy_index < 0) {
++ proxy_index = SSL_get_ex_new_index(0, NULL, NULL, NULL, NULL);
++ }
++ return proxy_index;
+ }
+
+ static int passwd_callback(char *buf, int num, int encrypting,
+@@ -1174,7 +1185,7 @@ static int ossl_init(void)
+
+ /* Initialize the extra data indexes */
+ if(ossl_get_ssl_data_index() < 0 || ossl_get_ssl_conn_index() < 0 ||
+- ossl_get_ssl_sockindex_index() < 0)
++ ossl_get_ssl_sockindex_index() < 0 || ossl_get_proxy_index() < 0)
+ return 0;
+
+ return 1;
+@@ -2432,8 +2443,10 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_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();
++ bool isproxy;
+
+- if(data_idx < 0 || connectdata_idx < 0 || sockindex_idx < 0)
++ if(data_idx < 0 || connectdata_idx < 0 || sockindex_idx < 0 || proxy_idx < 0)
+ return 0;
+
+ conn = (struct connectdata*) SSL_get_ex_data(ssl, connectdata_idx);
+@@ -2446,13 +2459,18 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
+ sockindex_ptr = (curl_socket_t*) SSL_get_ex_data(ssl, sockindex_idx);
+ sockindex = (int)(sockindex_ptr - conn->sock);
+
++ isproxy = SSL_get_ex_data(ssl, proxy_idx) ? TRUE : FALSE;
++
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ bool incache;
+ void *old_ssl_sessionid = NULL;
+
+ Curl_ssl_sessionid_lock(data);
+- incache = !(Curl_ssl_getsessionid(data, conn, &old_ssl_sessionid, NULL,
+- sockindex));
++ if(isproxy)
++ incache = FALSE;
++ else
++ incache = !(Curl_ssl_getsessionid(data, conn, isproxy,
++ &old_ssl_sessionid, NULL, sockindex));
+ if(incache) {
+ if(old_ssl_sessionid != ssl_sessionid) {
+ infof(data, "old SSL session ID is stale, removing\n");
+@@ -2462,8 +2480,8 @@ static int ossl_new_session_cb(SSL *ssl, SSL_SESSION *ssl_sessionid)
+ }
+
+ if(!incache) {
+- if(!Curl_ssl_addsessionid(data, conn, ssl_sessionid,
+- 0 /* unknown size */, sockindex)) {
++ if(!Curl_ssl_addsessionid(data, conn, isproxy, ssl_sessionid,
++ 0 /* unknown size */, sockindex)) {
+ /* the session has been put into the session cache */
+ res = 1;
+ }
+@@ -3193,17 +3211,27 @@ static CURLcode ossl_connect_step1(struct Curl_easy *data,
+ 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) {
++ 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
++
+ }
+
+ Curl_ssl_sessionid_lock(data);
+- if(!Curl_ssl_getsessionid(data, conn, &ssl_sessionid, NULL, sockindex)) {
++ 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);
+diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c
+index d7b89d43f892..931bd853eb8e 100644
+--- a/lib/vtls/schannel.c
++++ b/lib/vtls/schannel.c
+@@ -496,6 +496,7 @@ schannel_connect_step1(struct Curl_easy *data, struct connectdata *conn,
+ if(SSL_SET_OPTION(primary.sessionid)) {
+ Curl_ssl_sessionid_lock(data);
+ if(!Curl_ssl_getsessionid(data, conn,
++ SSL_IS_PROXY() ? TRUE : FALSE,
+ (void **)&old_cred, NULL, sockindex)) {
+ BACKEND->cred = old_cred;
+ DEBUGF(infof(data, "schannel: re-using exi