Fix CVE-2023-38039 in net-misc/curl.
Backport commit 3ee79c1674fd6f99e8efca52cd7510e08b766770 from
https://github.com/curl/curl/.
8.3.0 is not declared stable in upstream
https://gitweb.gentoo.org/repo/gentoo.git/log/net-misc/curl
BUG=b/301374600
TEST=presubmit
RELEASE_NOTE=Fix CVE-2023-38039 in net-misc/curl.
cos-patch: security-moderate
Change-Id: I9f6fa66afad2bb9eeb67b5c7df27b37eb38be64a
Reviewed-on: https://cos-review.googlesource.com/c/third_party/overlays/portage-stable/+/58329
Tested-by: Cusky Presubmit Bot <presubmit@cos-infra-prod.iam.gserviceaccount.com>
Main-Branch-Verified: Cusky Presubmit Bot <presubmit@cos-infra-prod.iam.gserviceaccount.com>
Reviewed-by: Oleksandr Tymoshenko <ovt@google.com>
diff --git a/net-misc/curl/curl-8.1.0-r2.ebuild b/net-misc/curl/curl-8.1.0-r3.ebuild
similarity index 99%
rename from net-misc/curl/curl-8.1.0-r2.ebuild
rename to net-misc/curl/curl-8.1.0-r3.ebuild
index 99b7001..f5fca63 100644
--- a/net-misc/curl/curl-8.1.0-r2.ebuild
+++ b/net-misc/curl/curl-8.1.0-r3.ebuild
@@ -113,6 +113,7 @@
"${FILESDIR}"/${P}-header-length.patch
# CVEs
"${FILESDIR}"/${PN}-CVE-2023-32001.patch
+ "${FILESDIR}"/${PN}-CVE-2023-38039.patch
)
src_prepare() {
diff --git a/net-misc/curl/files/curl-CVE-2023-38039.patch b/net-misc/curl/files/curl-CVE-2023-38039.patch
new file mode 100644
index 0000000..b080237
--- /dev/null
+++ b/net-misc/curl/files/curl-CVE-2023-38039.patch
@@ -0,0 +1,211 @@
+From 3ee79c1674fd6f99e8efca52cd7510e08b766770 Mon Sep 17 00:00:00 2001
+From: Daniel Stenberg <daniel@haxx.se>
+Date: Wed, 2 Aug 2023 23:34:48 +0200
+Subject: [PATCH] http: return error when receiving too large header set
+
+To avoid abuse. The limit is set to 300 KB for the accumulated size of
+all received HTTP headers for a single response. Incomplete research
+suggests that Chrome uses a 256-300 KB limit, while Firefox allows up to
+1MB.
+
+Closes #11582
+---
+ lib/c-hyper.c | 12 +++++++-----
+ lib/cf-h1-proxy.c | 4 +++-
+ lib/http.c | 34 ++++++++++++++++++++++++++++++----
+ lib/http.h | 9 +++++++++
+ lib/pingpong.c | 4 +++-
+ lib/urldata.h | 17 ++++++++---------
+ 6 files changed, 60 insertions(+), 20 deletions(-)
+
+diff --git a/lib/c-hyper.c b/lib/c-hyper.c
+index c29983c0b24a6..0b9d9ab478e67 100644
+--- a/lib/c-hyper.c
++++ b/lib/c-hyper.c
+@@ -182,8 +182,11 @@ static int hyper_each_header(void *userdata,
+ }
+ }
+
+- data->info.header_size += (curl_off_t)len;
+- data->req.headerbytecount += (curl_off_t)len;
++ result = Curl_bump_headersize(data, len, FALSE);
++ if(result) {
++ data->state.hresult = result;
++ return HYPER_ITER_BREAK;
++ }
+ return HYPER_ITER_CONTINUE;
+ }
+
+@@ -313,9 +316,8 @@ static CURLcode status_line(struct Curl_easy *data,
+ if(result)
+ return result;
+ }
+- data->info.header_size += (curl_off_t)len;
+- data->req.headerbytecount += (curl_off_t)len;
+- return CURLE_OK;
++ result = Curl_bump_headersize(data, len, FALSE);
++ return result;
+ }
+
+ /*
+diff --git a/lib/cf-h1-proxy.c b/lib/cf-h1-proxy.c
+index c9b157c9bccc7..b1d8cb618b7d1 100644
+--- a/lib/cf-h1-proxy.c
++++ b/lib/cf-h1-proxy.c
+@@ -587,7 +587,9 @@ static CURLcode recv_CONNECT_resp(struct Curl_cfilter *cf,
+ return result;
+ }
+
+- data->info.header_size += (long)perline;
++ result = Curl_bump_headersize(data, perline, TRUE);
++ if(result)
++ return result;
+
+ /* Newlines are CRLF, so the CR is ignored as the line isn't
+ really terminated until the LF comes. Treat a following CR
+diff --git a/lib/http.c b/lib/http.c
+index f7c71afd7d847..bc78ff97435c4 100644
+--- a/lib/http.c
++++ b/lib/http.c
+@@ -3920,6 +3920,29 @@ static CURLcode verify_header(struct Curl_easy *data)
+ return CURLE_OK;
+ }
+
++CURLcode Curl_bump_headersize(struct Curl_easy *data,
++ size_t delta,
++ bool connect_only)
++{
++ size_t bad = 0;
++ if(delta < MAX_HTTP_RESP_HEADER_SIZE) {
++ if(!connect_only)
++ data->req.headerbytecount += (unsigned int)delta;
++ data->info.header_size += (unsigned int)delta;
++ if(data->info.header_size > MAX_HTTP_RESP_HEADER_SIZE)
++ bad = data->info.header_size;
++ }
++ else
++ bad = data->info.header_size + delta;
++ if(bad) {
++ failf(data, "Too large response headers: %zu > %zu",
++ bad, MAX_HTTP_RESP_HEADER_SIZE);
++ return CURLE_RECV_ERROR;
++ }
++ return CURLE_OK;
++}
++
++
+ /*
+ * Read any HTTP header lines from the server and pass them to the client app.
+ */
+@@ -4173,8 +4196,9 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
+ if(result)
+ return result;
+
+- data->info.header_size += (long)headerlen;
+- data->req.headerbytecount += (long)headerlen;
++ result = Curl_bump_headersize(data, headerlen, FALSE);
++ if(result)
++ return result;
+
+ /*
+ * When all the headers have been parsed, see if we should give
+@@ -4496,8 +4520,10 @@ CURLcode Curl_http_readwrite_headers(struct Curl_easy *data,
+ if(result)
+ return result;
+
+- data->info.header_size += Curl_dyn_len(&data->state.headerb);
+- data->req.headerbytecount += Curl_dyn_len(&data->state.headerb);
++ result = Curl_bump_headersize(data, Curl_dyn_len(&data->state.headerb),
++ FALSE);
++ if(result)
++ return result;
+
+ Curl_dyn_reset(&data->state.headerb);
+ }
+diff --git a/lib/http.h b/lib/http.h
+index df3b4e38b8a88..4aeabc345938c 100644
+--- a/lib/http.h
++++ b/lib/http.h
+@@ -64,6 +64,10 @@ extern const struct Curl_handler Curl_handler_wss;
+
+ struct dynhds;
+
++CURLcode Curl_bump_headersize(struct Curl_easy *data,
++ size_t delta,
++ bool connect_only);
++
+ /* Header specific functions */
+ bool Curl_compareheader(const char *headerline, /* line to check */
+ const char *header, /* header keyword _with_ colon */
+@@ -183,6 +187,11 @@ CURLcode Curl_http_auth_act(struct Curl_easy *data);
+ #define EXPECT_100_THRESHOLD (1024*1024)
+ #endif
+
++/* MAX_HTTP_RESP_HEADER_SIZE is the maximum size of all response headers
++ combined that libcurl allows for a single HTTP response, any HTTP
++ version. This count includes CONNECT response headers. */
++#define MAX_HTTP_RESP_HEADER_SIZE (300*1024)
++
+ #endif /* CURL_DISABLE_HTTP */
+
+ /****************************************************************************
+diff --git a/lib/pingpong.c b/lib/pingpong.c
+index f3f7cb93cb9b7..523bbec189fe6 100644
+--- a/lib/pingpong.c
++++ b/lib/pingpong.c
+@@ -341,7 +341,9 @@ CURLcode Curl_pp_readresp(struct Curl_easy *data,
+ ssize_t clipamount = 0;
+ bool restart = FALSE;
+
+- data->req.headerbytecount += (long)gotbytes;
++ result = Curl_bump_headersize(data, gotbytes, FALSE);
++ if(result)
++ return result;
+
+ pp->nread_resp += gotbytes;
+ for(i = 0; i < gotbytes; ptr++, i++) {
+diff --git a/lib/urldata.h b/lib/urldata.h
+index e5446b6840f63..d21aa415dc94b 100644
+--- a/lib/urldata.h
++++ b/lib/urldata.h
+@@ -629,17 +629,16 @@ struct SingleRequest {
+ curl_off_t bytecount; /* total number of bytes read */
+ curl_off_t writebytecount; /* number of bytes written */
+
+- curl_off_t headerbytecount; /* only count received headers */
+- curl_off_t deductheadercount; /* this amount of bytes doesn't count when we
+- check if anything has been transferred at
+- the end of a connection. We use this
+- counter to make only a 100 reply (without a
+- following second response code) result in a
+- CURLE_GOT_NOTHING error code */
+-
+ curl_off_t pendingheader; /* this many bytes left to send is actually
+ header and not body */
+ struct curltime start; /* transfer started at this time */
++ unsigned int headerbytecount; /* only count received headers */
++ unsigned int deductheadercount; /* this amount of bytes doesn't count when
++ we check if anything has been transferred
++ at the end of a connection. We use this
++ counter to make only a 100 reply (without
++ a following second response code) result
++ in a CURLE_GOT_NOTHING error code */
+ enum {
+ HEADER_NORMAL, /* no bad header at all */
+ HEADER_PARTHEADER, /* part of the chunk is a bad header, the rest
+@@ -1089,7 +1088,6 @@ struct PureInfo {
+ int httpversion; /* the http version number X.Y = X*10+Y */
+ time_t filetime; /* If requested, this is might get set. Set to -1 if the
+ time was unretrievable. */
+- curl_off_t header_size; /* size of read header(s) in bytes */
+ curl_off_t request_size; /* the amount of bytes sent in the request(s) */
+ unsigned long proxyauthavail; /* what proxy auth types were announced */
+ unsigned long httpauthavail; /* what host auth types were announced */
+@@ -1097,6 +1095,7 @@ struct PureInfo {
+ char *contenttype; /* the content type of the object */
+ char *wouldredirect; /* URL this would've been redirected to if asked to */
+ curl_off_t retry_after; /* info from Retry-After: header */
++ unsigned int header_size; /* size of read header(s) in bytes */
+
+ /* PureInfo members 'conn_primary_ip', 'conn_primary_port', 'conn_local_ip'
+ and, 'conn_local_port' are copied over from the connectdata struct in