!230 fix CVE-2023-38039
From: @eaglegai Reviewed-by: @robertxw Signed-off-by: @robertxw
This commit is contained in:
commit
b3e7df02b3
212
backport-CVE-2023-38039.patch
Normal file
212
backport-CVE-2023-38039.patch
Normal file
@ -0,0 +1,212 @@
|
||||
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
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
|
||||
Name: curl
|
||||
Version: 8.1.2
|
||||
Release: 3
|
||||
Release: 4
|
||||
Summary: Curl is used in command lines or scripts to transfer data
|
||||
License: curl
|
||||
URL: https://curl.se/
|
||||
@ -18,6 +18,7 @@ Patch4: backport-curl-7.88.0-tests-warnings.patch
|
||||
Patch5: backport-CVE-2023-32001.patch
|
||||
Patch6: backport-vtls-avoid-memory-leak-if-sha256-call-fails.patch
|
||||
Patch7: backport-urlapi-make-sure-zoneid-is-also-duplicated-in-curl_u.patch
|
||||
Patch8: backport-CVE-2023-38039.patch
|
||||
|
||||
BuildRequires: automake brotli-devel coreutils gcc groff krb5-devel
|
||||
BuildRequires: libidn2-devel libnghttp2-devel libpsl-devel
|
||||
@ -202,6 +203,12 @@ rm -rf ${RPM_BUILD_ROOT}%{_libdir}/libcurl.la
|
||||
%{_mandir}/man3/*
|
||||
|
||||
%changelog
|
||||
* Thu Sep 14 2023 gaihuiying <eaglegai@163.com> - 8.1.2-4
|
||||
- Type:CVE
|
||||
- CVE:CVE-2023-38039
|
||||
- SUG:NA
|
||||
- DESC:fix CVE-2023-38039
|
||||
|
||||
* Wed Sep 06 2023 yanglu <yanglu72@h-partners.com> - 8.1.2-3
|
||||
- Type:bugfix
|
||||
- CVE:NA
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user