Skip to content

Commit bbbba3d

Browse files
committed
(PA-6291): Applied following curl patches to curl 7.88.1:
1. CVE-2024-2004 2. CVE-2024-2398
1 parent 68650ed commit bbbba3d

File tree

3 files changed

+280
-0
lines changed

3 files changed

+280
-0
lines changed

configs/components/curl.rb

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@
3333
pkg.apply_patch 'resources/patches/curl/CVE-2023-38545.patch'
3434
pkg.apply_patch 'resources/patches/curl/CVE-2023-38546.patch'
3535
pkg.apply_patch 'resources/patches/curl/CVE-2023-46218.patch'
36+
pkg.apply_patch 'resources/patches/curl/CVE-2024-2004.patch'
37+
pkg.apply_patch 'resources/patches/curl/CVE-2024-2398.patch'
3638

3739
configure_options = []
3840
configure_options << "--with-ssl=#{settings[:prefix]}"
Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,63 @@
1+
setopt: Fix disabling all protocols
2+
3+
When disabling all protocols without enabling any, the resulting
4+
set of allowed protocols remained the default set. Clearing the
5+
allowed set before inspecting the passed value from --proto make
6+
the set empty even in the errorpath of no protocols enabled.
7+
8+
Co-authored-by: Dan Fandrich <[email protected]>
9+
Reported-by: Dan Fandrich <[email protected]>
10+
Reviewed-by: Daniel Stenberg <[email protected]>
11+
Closes: #13004
12+
---
13+
diff --git a/lib/setopt.c b/lib/setopt.c
14+
index 604693ad9..d6b62c5c9 100644
15+
--- a/lib/setopt.c
16+
+++ b/lib/setopt.c
17+
@@ -150,6 +150,12 @@ static CURLcode setstropt_userpwd(char *option, char **userp, char **passwdp)
18+
19+
static CURLcode protocol2num(const char *str, curl_prot_t *val)
20+
{
21+
+ /*
22+
+ * We are asked to cherry-pick protocols, so play it safe and disallow all
23+
+ * protocols to start with, and re-add the wanted ones back in.
24+
+ */
25+
+ *val = 0;
26+
+
27+
if(!str)
28+
return CURLE_BAD_FUNCTION_ARGUMENT;
29+
30+
@@ -158,8 +164,6 @@ static CURLcode protocol2num(const char *str, curl_prot_t *val)
31+
return CURLE_OK;
32+
}
33+
34+
- *val = 0;
35+
-
36+
do {
37+
const char *token = str;
38+
size_t tlen;
39+
@@ -2668,22 +2672,18 @@ CURLcode Curl_vsetopt(struct Curl_easy *data, CURLoption option, va_list param)
40+
break;
41+
42+
case CURLOPT_PROTOCOLS_STR: {
43+
- curl_prot_t prot;
44+
argptr = va_arg(param, char *);
45+
- result = protocol2num(argptr, &prot);
46+
+ result = protocol2num(argptr, &data->set.allowed_protocols);
47+
if(result)
48+
return result;
49+
- data->set.allowed_protocols = prot;
50+
break;
51+
}
52+
53+
case CURLOPT_REDIR_PROTOCOLS_STR: {
54+
- curl_prot_t prot;
55+
argptr = va_arg(param, char *);
56+
- result = protocol2num(argptr, &prot);
57+
+ result = protocol2num(argptr, &data->set.redir_protocols);
58+
if(result)
59+
return result;
60+
- data->set.redir_protocols = prot;
61+
break;
62+
}
63+
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
http2: push headers better cleanup
2+
3+
provide common cleanup method for push headers
4+
5+
Co-authored-by: Stefan Eissing <@[email protected]>
6+
Reviewed-by: Daniel Stenberg <[email protected]>
7+
8+
Closes #13054
9+
---
10+
diff --git a/lib/http2.c b/lib/http2.c
11+
index bdb5e7378..f2c02da7c 100644
12+
--- a/lib/http2.c
13+
+++ b/lib/http2.c
14+
@@ -144,6 +144,161 @@ static void cf_h2_ctx_free(struct cf_h2_ctx *ctx)
15+
}
16+
}
17+
18+
+static CURLcode h2_progress_egress(struct Curl_cfilter *cf,
19+
+ struct Curl_easy *data);
20+
+
21+
+/**
22+
+ * All about the H2 internals of a stream
23+
+ */
24+
+struct h2_stream_ctx {
25+
+ int32_t id; /* HTTP/2 protocol identifier for stream */
26+
+ struct bufq recvbuf; /* response buffer */
27+
+ struct bufq sendbuf; /* request buffer */
28+
+ struct h1_req_parser h1; /* parsing the request */
29+
+ struct dynhds resp_trailers; /* response trailer fields */
30+
+ size_t resp_hds_len; /* amount of response header bytes in recvbuf */
31+
+ size_t upload_blocked_len;
32+
+ curl_off_t upload_left; /* number of request bytes left to upload */
33+
+ curl_off_t nrcvd_data; /* number of DATA bytes received */
34+
+
35+
+ char **push_headers; /* allocated array */
36+
+ size_t push_headers_used; /* number of entries filled in */
37+
+ size_t push_headers_alloc; /* number of entries allocated */
38+
+
39+
+ int status_code; /* HTTP response status code */
40+
+ uint32_t error; /* stream error code */
41+
+ uint32_t local_window_size; /* the local recv window size */
42+
+ bool resp_hds_complete; /* we have a complete, final response */
43+
+ bool closed; /* TRUE on stream close */
44+
+ bool reset; /* TRUE on stream reset */
45+
+ bool close_handled; /* TRUE if stream closure is handled by libcurl */
46+
+ bool bodystarted;
47+
+ bool send_closed; /* transfer is done sending, we might have still
48+
+ buffered data in stream->sendbuf to upload. */
49+
+};
50+
+
51+
+#define H2_STREAM_CTX(d) ((struct h2_stream_ctx *)(((d) && \
52+
+ (d)->req.p.http)? \
53+
+ ((struct HTTP *)(d)->req.p.http)->h2_ctx \
54+
+ : NULL))
55+
+#define H2_STREAM_LCTX(d) ((struct HTTP *)(d)->req.p.http)->h2_ctx
56+
+#define H2_STREAM_ID(d) (H2_STREAM_CTX(d)? \
57+
+ H2_STREAM_CTX(d)->id : -2)
58+
+
59+
+/*
60+
+ * Mark this transfer to get "drained".
61+
+ */
62+
+static void drain_stream(struct Curl_cfilter *cf,
63+
+ struct Curl_easy *data,
64+
+ struct h2_stream_ctx *stream)
65+
+{
66+
+ unsigned char bits;
67+
+
68+
+ (void)cf;
69+
+ bits = CURL_CSELECT_IN;
70+
+ if(!stream->send_closed &&
71+
+ (stream->upload_left || stream->upload_blocked_len))
72+
+ bits |= CURL_CSELECT_OUT;
73+
+ if(data->state.select_bits != bits) {
74+
+ CURL_TRC_CF(data, cf, "[%d] DRAIN select_bits=%x",
75+
+ stream->id, bits);
76+
+ data->state.select_bits = bits;
77+
+ Curl_expire(data, 0, EXPIRE_RUN_NOW);
78+
+ }
79+
+}
80+
+
81+
+static CURLcode http2_data_setup(struct Curl_cfilter *cf,
82+
+ struct Curl_easy *data,
83+
+ struct h2_stream_ctx **pstream)
84+
+{
85+
+ struct cf_h2_ctx *ctx = cf->ctx;
86+
+ struct h2_stream_ctx *stream;
87+
+
88+
+ (void)cf;
89+
+ DEBUGASSERT(data);
90+
+ if(!data->req.p.http) {
91+
+ failf(data, "initialization failure, transfer not http initialized");
92+
+ return CURLE_FAILED_INIT;
93+
+ }
94+
+ stream = H2_STREAM_CTX(data);
95+
+ if(stream) {
96+
+ *pstream = stream;
97+
+ return CURLE_OK;
98+
+ }
99+
+
100+
+ stream = calloc(1, sizeof(*stream));
101+
+ if(!stream)
102+
+ return CURLE_OUT_OF_MEMORY;
103+
+
104+
+ stream->id = -1;
105+
+ Curl_bufq_initp(&stream->sendbuf, &ctx->stream_bufcp,
106+
+ H2_STREAM_SEND_CHUNKS, BUFQ_OPT_NONE);
107+
+ Curl_h1_req_parse_init(&stream->h1, H1_PARSE_DEFAULT_MAX_LINE_LEN);
108+
+ Curl_dynhds_init(&stream->resp_trailers, 0, DYN_HTTP_REQUEST);
109+
+ stream->resp_hds_len = 0;
110+
+ stream->bodystarted = FALSE;
111+
+ stream->status_code = -1;
112+
+ stream->closed = FALSE;
113+
+ stream->close_handled = FALSE;
114+
+ stream->error = NGHTTP2_NO_ERROR;
115+
+ stream->local_window_size = H2_STREAM_WINDOW_SIZE;
116+
+ stream->upload_left = 0;
117+
+ stream->nrcvd_data = 0;
118+
+
119+
+ H2_STREAM_LCTX(data) = stream;
120+
+ *pstream = stream;
121+
+ return CURLE_OK;
122+
+}
123+
+
124+
+static void free_push_headers(struct h2_stream_ctx *stream)
125+
+{
126+
+ size_t i;
127+
+ for(i = 0; i<stream->push_headers_used; i++)
128+
+ free(stream->push_headers[i]);
129+
+ Curl_safefree(stream->push_headers);
130+
+ stream->push_headers_used = 0;
131+
+}
132+
+
133+
+static void http2_data_done(struct Curl_cfilter *cf,
134+
+ struct Curl_easy *data, bool premature)
135+
+{
136+
+ struct cf_h2_ctx *ctx = cf->ctx;
137+
+ struct h2_stream_ctx *stream = H2_STREAM_CTX(data);
138+
+
139+
+ DEBUGASSERT(ctx);
140+
+ (void)premature;
141+
+ if(!stream)
142+
+ return;
143+
+
144+
+ if(ctx->h2) {
145+
+ bool flush_egress = FALSE;
146+
+ /* returns error if stream not known, which is fine here */
147+
+ (void)nghttp2_session_set_stream_user_data(ctx->h2, stream->id, NULL);
148+
+
149+
+ if(!stream->closed && stream->id > 0) {
150+
+ /* RST_STREAM */
151+
+ CURL_TRC_CF(data, cf, "[%d] premature DATA_DONE, RST stream",
152+
+ stream->id);
153+
+ stream->closed = TRUE;
154+
+ stream->reset = TRUE;
155+
+ stream->send_closed = TRUE;
156+
+ nghttp2_submit_rst_stream(ctx->h2, NGHTTP2_FLAG_NONE,
157+
+ stream->id, NGHTTP2_STREAM_CLOSED);
158+
+ flush_egress = TRUE;
159+
+ }
160+
+
161+
+ if(flush_egress)
162+
+ nghttp2_session_send(ctx->h2);
163+
+ }
164+
+
165+
+ Curl_bufq_free(&stream->sendbuf);
166+
+ Curl_h1_req_parse_free(&stream->h1);
167+
+ Curl_dynhds_free(&stream->resp_trailers);
168+
+ free_push_headers(stream);
169+
+ free(stream);
170+
+ H2_STREAM_LCTX(data) = NULL;
171+
+}
172+
+
173+
static int h2_client_new(struct Curl_cfilter *cf,
174+
nghttp2_session_callbacks *cbs)
175+
{
176+
@@ -702,6 +857,7 @@ static int push_promise(struct Curl_cfilter *cf,
177+
struct HTTP *newstream;
178+
struct curl_pushheaders heads;
179+
CURLMcode rc;
180+
+ CURLcode result;
181+
size_t i;
182+
/* clone the parent */
183+
struct Curl_easy *newhandle = h2_duphandle(cf, data);
184+
@@ -738,11 +894,7 @@ static int push_promise(struct Curl_cfilter *cf,
185+
Curl_set_in_callback(data, false);
186+
187+
/* free the headers again */
188+
- for(i = 0; i<stream->push_headers_used; i++)
189+
- free(stream->push_headers[i]);
190+
- free(stream->push_headers);
191+
- stream->push_headers = NULL;
192+
- stream->push_headers_used = 0;
193+
+ free_push_headers(stream);
194+
195+
if(rv) {
196+
DEBUGASSERT((rv > CURL_PUSH_OK) && (rv <= CURL_PUSH_ERROROUT));
197+
@@ -1198,14 +1350,14 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame,
198+
if(stream->push_headers_alloc > 1000) {
199+
/* this is beyond crazy many headers, bail out */
200+
failf(data_s, "Too many PUSH_PROMISE headers");
201+
- Curl_safefree(stream->push_headers);
202+
+ free_push_headers(stream);
203+
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
204+
}
205+
stream->push_headers_alloc *= 2;
206+
- headp = Curl_saferealloc(stream->push_headers,
207+
- stream->push_headers_alloc * sizeof(char *));
208+
+ headp = realloc(stream->push_headers,
209+
+ stream->push_headers_alloc * sizeof(char *));
210+
if(!headp) {
211+
- stream->push_headers = NULL;
212+
+ free_push_headers(stream);
213+
return NGHTTP2_ERR_TEMPORAL_CALLBACK_FAILURE;
214+
}
215+
stream->push_headers = headp;

0 commit comments

Comments
 (0)