Merge #217110: curl: patch CVEs fixed in 7.88.0

...into staging-22.11
This commit is contained in:
Vladimír Čunát
2023-02-22 10:57:12 +01:00
3 changed files with 553 additions and 0 deletions

View File

@@ -0,0 +1,318 @@
From 076a2f629119222aeeb50f5a03bf9f9052fabb9a Mon Sep 17 00:00:00 2001
From: Daniel Stenberg <daniel@haxx.se>
Date: Tue, 27 Dec 2022 11:50:20 +0100
Subject: [PATCH] share: add sharing of HSTS cache among handles
Closes #10138
---
docs/libcurl/opts/CURLSHOPT_SHARE.3 | 4 +++
docs/libcurl/symbols-in-versions | 1 +
include/curl/curl.h | 1 +
lib/hsts.c | 15 +++++++++
lib/hsts.h | 2 ++
lib/setopt.c | 48 ++++++++++++++++++++++++-----
lib/share.c | 32 +++++++++++++++++--
lib/share.h | 6 +++-
lib/transfer.c | 3 ++
lib/url.c | 6 +++-
lib/urldata.h | 2 ++
11 files changed, 109 insertions(+), 11 deletions(-)
diff --git a/docs/libcurl/opts/CURLSHOPT_SHARE.3 b/docs/libcurl/opts/CURLSHOPT_SHARE.3
index 72079d8fbafce..78593b63293a8 100644
--- a/docs/libcurl/opts/CURLSHOPT_SHARE.3
+++ b/docs/libcurl/opts/CURLSHOPT_SHARE.3
@@ -78,6 +78,10 @@ Added in 7.61.0.
Note that when you use the multi interface, all easy handles added to the same
multi handle will share PSL cache by default without using this option.
+.IP CURL_LOCK_DATA_HSTS
+The in-memory HSTS cache.
+
+Added in 7.88.0
.SH PROTOCOLS
All
.SH EXAMPLE
diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions
index 6de01a08ccf5e..54605eed000db 100644
--- a/docs/libcurl/symbols-in-versions
+++ b/docs/libcurl/symbols-in-versions
@@ -73,6 +73,7 @@ CURL_LOCK_ACCESS_SINGLE 7.10.3
CURL_LOCK_DATA_CONNECT 7.10.3
CURL_LOCK_DATA_COOKIE 7.10.3
CURL_LOCK_DATA_DNS 7.10.3
+CURL_LOCK_DATA_HSTS 7.88.0
CURL_LOCK_DATA_NONE 7.10.3
CURL_LOCK_DATA_PSL 7.61.0
CURL_LOCK_DATA_SHARE 7.10.4
diff --git a/include/curl/curl.h b/include/curl/curl.h
index 139df99950bcc..5758e3b21fb48 100644
--- a/include/curl/curl.h
+++ b/include/curl/curl.h
@@ -2953,6 +2953,7 @@ typedef enum {
CURL_LOCK_DATA_SSL_SESSION,
CURL_LOCK_DATA_CONNECT,
CURL_LOCK_DATA_PSL,
+ CURL_LOCK_DATA_HSTS,
CURL_LOCK_DATA_LAST
} curl_lock_data;
diff --git a/lib/hsts.c b/lib/hsts.c
index c449120f3148b..339237be1c621 100644
--- a/lib/hsts.c
+++ b/lib/hsts.c
@@ -39,3 +39,4 @@
+#include "share.h"
/* The last 3 #include files should be in this order */
#include "curl_printf.h"
@@ -551,4 +552,18 @@ CURLcode Curl_hsts_loadcb(struct Curl_easy *data, struct hsts *h)
return CURLE_OK;
}
+void Curl_hsts_loadfiles(struct Curl_easy *data)
+{
+ struct curl_slist *l = data->set.hstslist;
+ if(l) {
+ Curl_share_lock(data, CURL_LOCK_DATA_HSTS, CURL_LOCK_ACCESS_SINGLE);
+
+ while(l) {
+ (void)Curl_hsts_loadfile(data, data->hsts, l->data);
+ l = l->next;
+ }
+ Curl_share_unlock(data, CURL_LOCK_DATA_HSTS);
+ }
+}
+
#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
diff --git a/lib/hsts.h b/lib/hsts.h
index 0e36a7756bdb2..3da7574e249d6 100644
--- a/lib/hsts.h
+++ b/lib/hsts.h
@@ -59,9 +59,11 @@ CURLcode Curl_hsts_loadfile(struct Curl_easy *data,
struct hsts *h, const char *file);
CURLcode Curl_hsts_loadcb(struct Curl_easy *data,
struct hsts *h);
+void Curl_hsts_loadfiles(struct Curl_easy *data);
#else
#define Curl_hsts_cleanup(x)
#define Curl_hsts_loadcb(x,y) CURLE_OK
#define Curl_hsts_save(x,y,z)
+#define Curl_hsts_loadfiles(x)
#endif /* CURL_DISABLE_HTTP || CURL_DISABLE_HSTS */
#endif /* HEADER_CURL_HSTS_H */
diff --git a/lib/setopt.c b/lib/setopt.c
index f6083dceb7651..ebe24f95c0550 100644
--- a/lib/setopt.c
+++ b/lib/setopt.c
@@ -2262,9 +2262,14 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->cookies = NULL;
#endif
+#ifndef CURL_DISABLE_HSTS
+ if(data->share->hsts == data->hsts)
+ data->hsts = NULL;
+#endif
+#ifdef USE_SSL
if(data->share->sslsession == data->state.session)
data->state.session = NULL;
-
+#endif
#ifdef USE_LIBPSL
if(data->psl == &data->share->psl)
data->psl = data->multi? &data->multi->psl: NULL;
@@ -2298,10 +2303,19 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
data->cookies = data->share->cookies;
}
#endif /* CURL_DISABLE_HTTP */
+#ifndef CURL_DISABLE_HSTS
+ if(data->share->hsts) {
+ /* first free the private one if any */
+ Curl_hsts_cleanup(&data->hsts);
+ data->hsts = data->share->hsts;
+ }
+#endif /* CURL_DISABLE_HTTP */
+#ifdef USE_SSL
if(data->share->sslsession) {
data->set.general_ssl.max_ssl_sessions = data->share->max_ssl_sessions;
data->state.session = data->share->sslsession;
}
+#endif
#ifdef USE_LIBPSL
if(data->share->specifier & (1 << CURL_LOCK_DATA_PSL))
data->psl = &data->share->psl;
@@ -3053,19 +3067,39 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
case CURLOPT_HSTSWRITEDATA:
data->set.hsts_write_userp = va_arg(param, void *);
break;
- case CURLOPT_HSTS:
+ case CURLOPT_HSTS: {
+ struct curl_slist *h;
if(!data->hsts) {
data->hsts = Curl_hsts_init();
if(!data->hsts)
return CURLE_OUT_OF_MEMORY;
}
argptr = va_arg(param, char *);
- result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
- if(result)
- return result;
- if(argptr)
- (void)Curl_hsts_loadfile(data, data->hsts, argptr);
+ if(argptr) {
+ result = Curl_setstropt(&data->set.str[STRING_HSTS], argptr);
+ if(result)
+ return result;
+ /* this needs to build a list of file names to read from, so that it can
+ read them later, as we might get a shared HSTS handle to load them
+ into */
+ h = curl_slist_append(data->set.hstslist, argptr);
+ if(!h) {
+ curl_slist_free_all(data->set.hstslist);
+ data->set.hstslist = NULL;
+ return CURLE_OUT_OF_MEMORY;
+ }
+ data->set.hstslist = h; /* store the list for later use */
+ }
+ else {
+ /* clear the list of HSTS files */
+ curl_slist_free_all(data->set.hstslist);
+ data->set.hstslist = NULL;
+ if(!data->share || !data->share->hsts)
+ /* throw away the HSTS cache unless shared */
+ Curl_hsts_cleanup(&data->hsts);
+ }
break;
+ }
case CURLOPT_HSTS_CTRL:
arg = va_arg(param, long);
if(arg & CURLHSTS_ENABLE) {
diff --git a/lib/share.c b/lib/share.c
index 1a083e72a085f..69ee00bf827f9 100644
--- a/lib/share.c
+++ b/lib/share.c
@@ -29,9 +29,11 @@
#include "share.h"
#include "psl.h"
#include "vtls/vtls.h"
-#include "curl_memory.h"
+#include "hsts.h"
-/* The last #include file should be: */
+/* The last 3 #include files should be in this order */
+#include "curl_printf.h"
+#include "curl_memory.h"
#include "memdebug.h"
struct Curl_share *
@@ -89,6 +91,18 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
#endif
break;
+ case CURL_LOCK_DATA_HSTS:
+#ifndef CURL_DISABLE_HSTS
+ if(!share->hsts) {
+ share->hsts = Curl_hsts_init();
+ if(!share->hsts)
+ res = CURLSHE_NOMEM;
+ }
+#else /* CURL_DISABLE_HSTS */
+ res = CURLSHE_NOT_BUILT_IN;
+#endif
+ break;
+
case CURL_LOCK_DATA_SSL_SESSION:
#ifdef USE_SSL
if(!share->sslsession) {
@@ -141,6 +155,16 @@ curl_share_setopt(struct Curl_share *share, CURLSHoption option, ...)
#endif
break;
+ case CURL_LOCK_DATA_HSTS:
+#ifndef CURL_DISABLE_HSTS
+ if(share->hsts) {
+ Curl_hsts_cleanup(&share->hsts);
+ }
+#else /* CURL_DISABLE_HSTS */
+ res = CURLSHE_NOT_BUILT_IN;
+#endif
+ break;
+
case CURL_LOCK_DATA_SSL_SESSION:
#ifdef USE_SSL
Curl_safefree(share->sslsession);
@@ -207,6 +231,10 @@ curl_share_cleanup(struct Curl_share *share)
Curl_cookie_cleanup(share->cookies);
#endif
+#ifndef CURL_DISABLE_HSTS
+ Curl_hsts_cleanup(&share->hsts);
+#endif
+
#ifdef USE_SSL
if(share->sslsession) {
size_t i;
diff --git a/lib/share.h b/lib/share.h
index 32be41691a2f9..24497305556ff 100644
--- a/lib/share.h
+++ b/lib/share.h
@@ -59,10 +59,14 @@ struct Curl_share {
#ifdef USE_LIBPSL
struct PslCache psl;
#endif
-
+#ifndef CURL_DISABLE_HSTS
+ struct hsts *hsts;
+#endif
+#ifdef USE_SSL
struct Curl_ssl_session *sslsession;
size_t max_ssl_sessions;
long sessionage;
+#endif
};
CURLSHcode Curl_share_lock(struct Curl_easy *, curl_lock_data,
diff --git a/lib/transfer.c b/lib/transfer.c
index 90d9c7b1846ab..e58619a84c3d5 100644
--- a/lib/transfer.c
+++ b/lib/transfer.c
@@ -1396,6 +1396,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
if(data->state.resolve)
result = Curl_loadhostpairs(data);
+ /* If there is a list of hsts files to read */
+ Curl_hsts_loadfiles(data);
+
if(!result) {
/* Allow data->set.use_port to set which port to use. This needs to be
* disabled for example when we follow Location: headers to URLs using
diff --git a/lib/url.c b/lib/url.c
index 6a18022bd0769..815c33fec6fad 100644
--- a/lib/url.c
+++ b/lib/url.c
@@ -437,7 +437,11 @@ CURLcode Curl_close(struct Curl_easy **datap)
Curl_altsvc_save(data, data->asi, data->set.str[STRING_ALTSVC]);
Curl_altsvc_cleanup(&data->asi);
Curl_hsts_save(data, data->hsts, data->set.str[STRING_HSTS]);
- Curl_hsts_cleanup(&data->hsts);
+#ifndef CURL_DISABLE_HSTS
+ if(!data->share || !data->share->hsts)
+ Curl_hsts_cleanup(&data->hsts);
+ curl_slist_free_all(data->set.hstslist); /* clean up list */
+#endif
#if !defined(CURL_DISABLE_HTTP) && !defined(CURL_DISABLE_CRYPTO_AUTH)
Curl_http_auth_cleanup_digest(data);
#endif
diff --git a/lib/urldata.h b/lib/urldata.h
index 54e4863429e68..82cc340d11af3 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -1659,6 +1659,8 @@ struct UserDefined {
curl_easy_setopt(COOKIEFILE) calls */
#endif
#ifndef CURL_DISABLE_HSTS
+ struct curl_slist *hstslist; /* list of HSTS files set by
+ curl_easy_setopt(HSTS) calls */
curl_hstsread_callback hsts_read;
void *hsts_read_userp;
curl_hstswrite_callback hsts_write;

View File

@@ -0,0 +1,233 @@
From 119fb187192a9ea13dc90d9d20c215fc82799ab9 Mon Sep 17 00:00:00 2001
From: Patrick Monnerat <patrick@monnerat.net>
Date: Mon, 13 Feb 2023 08:33:09 +0100
Subject: [PATCH] content_encoding: do not reset stage counter for each header
Test 418 verifies
Closes #10492
---
lib/content_encoding.c | 7 +-
lib/urldata.h | 1 +
tests/data/Makefile.inc | 2 +-
tests/data/test387 | 2 +-
tests/data/test418 | 152 ++++++++++++++++++++++++++++++++++++++++
5 files changed, 158 insertions(+), 6 deletions(-)
create mode 100644 tests/data/test418
diff --git a/lib/content_encoding.c b/lib/content_encoding.c
index a68474df85de6..2bd4fef6481c7 100644
--- a/lib/content_encoding.c
+++ b/lib/content_encoding.c
@@ -1047,3 +1047,2 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
{
struct SingleRequest *k = &data->req;
- int counter = 0;
@@ -1084,9 +1083,9 @@ CURLcode Curl_build_unencoding_stack(struct Curl_easy *data,
if(!encoding)
encoding = &error_encoding; /* Defer error at stack use. */
- if(++counter >= MAX_ENCODE_STACK) {
- failf(data, "Reject response due to %u content encodings",
- counter);
+ if(k->writer_stack_depth++ >= MAX_ENCODE_STACK) {
+ failf(data, "Reject response due to more than %u content encodings",
+ MAX_ENCODE_STACK);
return CURLE_BAD_CONTENT_ENCODING;
}
/* Stack the unencoding stage. */
diff --git a/lib/urldata.h b/lib/urldata.h
index 0e2c04a04100f..35213f81b8215 100644
--- a/lib/urldata.h
+++ b/lib/urldata.h
@@ -689,6 +689,7 @@ struct SingleRequest {
struct dohdata *doh; /* DoH specific data for this request */
#endif
unsigned char setcookies;
+ unsigned char writer_stack_depth; /* Unencoding stack depth. */
BIT(header); /* incoming data has HTTP header */
BIT(content_range); /* set TRUE if Content-Range: was found */
BIT(upload_done); /* set to TRUE when doing chunked transfer-encoding
diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
index 533325d98f03c..762c41ca24760 100644
--- a/tests/data/Makefile.inc
+++ b/tests/data/Makefile.inc
@@ -68,6 +68,7 @@ test380 test381 test383 test384 test385 test386 test387 test388 test389 \
test390 test391 test392 test393 test394 test395 test396 test397 test398 \
test399 test400 test401 test402 test403 test404 test405 test406 test407 \
test408 test409 test410 test411 test412 test413 test414 test415 \
+test418 \
\
test430 test431 test432 test433 test434 test435 test436 \
\
diff --git a/tests/data/test387 b/tests/data/test387
index 015ec25f1d57a..644fc7f367db5 100644
--- a/tests/data/test387
+++ b/tests/data/test387
@@ -47,7 +47,7 @@ Accept: */*
61
</errorcode>
<stderr mode="text">
-curl: (61) Reject response due to 5 content encodings
+curl: (61) Reject response due to more than 5 content encodings
</stderr>
</verify>
</testcase>
diff --git a/tests/data/test418 b/tests/data/test418
new file mode 100644
index 0000000000000..50e974e60aa9f
--- /dev/null
+++ b/tests/data/test418
@@ -0,0 +1,152 @@
+<testcase>
+<info>
+<keywords>
+HTTP
+gzip
+</keywords>
+</info>
+
+#
+# Server-side
+<reply>
+<data nocheck="yes">
+HTTP/1.1 200 OK
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+Transfer-Encoding: gzip
+
+-foo-
+</data>
+</reply>
+
+#
+# Client-side
+<client>
+<server>
+http
+</server>
+ <name>
+Response with multiple Transfer-Encoding headers
+ </name>
+ <command>
+http://%HOSTIP:%HTTPPORT/%TESTNUMBER -sS
+</command>
+</client>
+
+#
+# Verify data after the test has been "shot"
+<verify>
+<protocol crlf="yes">
+GET /%TESTNUMBER HTTP/1.1
+Host: %HOSTIP:%HTTPPORT
+User-Agent: curl/%VERSION
+Accept: */*
+
+</protocol>
+
+# CURLE_BAD_CONTENT_ENCODING is 61
+<errorcode>
+61
+</errorcode>
+<stderr mode="text">
+curl: (61) Reject response due to more than 5 content encodings
+</stderr>
+</verify>
+</testcase>

View File

@@ -61,6 +61,8 @@ stdenv.mkDerivation (finalAttrs: {
./7.79.1-darwin-no-systemconfiguration.patch
./CVE-2022-43551.patch
./CVE-2022-43552.patch
./CVE-2023-23915.patch # also fixes CVE-2023-23914
./CVE-2023-23916.patch
];
outputs = [ "bin" "dev" "out" "man" "devdoc" ];