Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
211 changes: 211 additions & 0 deletions pkgs/tools/networking/curl/CVE-2023-38039.patch
Original file line number Diff line number Diff line change
@@ -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
7 changes: 5 additions & 2 deletions pkgs/tools/networking/curl/default.nix
Original file line number Diff line number Diff line change
Expand Up @@ -52,16 +52,19 @@ stdenv.mkDerivation (finalAttrs: {
src = fetchurl {
urls = [
"https://curl.haxx.se/download/curl-${finalAttrs.version}.tar.bz2"
"https://github.com/curl/curl/releases/download/curl-${finalAttrs.version}/curl-${finalAttrs.version}.tar.bz2"
"https://github.com/curl/curl/releases/download/curl-${builtins.replaceStrings [ "." ] [ "_" ] finalAttrs.version}/curl-${finalAttrs.version}.tar.bz2"
];
hash = "sha256-UdKvcieZE7XUyrH+Hzi5RM9wkEyIvuJGtb1XWETnA1o=";
};

patches = [
./7.79.1-darwin-no-systemconfiguration.patch

# Affected versions: 7.84.0 to and including 8.1.2
# https://curl.se/docs/CVE-2023-32001.html
./CVE-2023-32001.patch

# https://curl.se/docs/CVE-2023-38039.html
./CVE-2023-38039.patch
];

outputs = [ "bin" "dev" "out" "man" "devdoc" ];
Expand Down