summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--meta/recipes-support/curl/curl/CVE-2024-11053-0001.patch353
-rw-r--r--meta/recipes-support/curl/curl/CVE-2024-11053-0002.patch728
-rw-r--r--meta/recipes-support/curl/curl/CVE-2024-11053-0003.patch130
-rw-r--r--meta/recipes-support/curl/curl_8.7.1.bb3
4 files changed, 1214 insertions, 0 deletions
diff --git a/meta/recipes-support/curl/curl/CVE-2024-11053-0001.patch b/meta/recipes-support/curl/curl/CVE-2024-11053-0001.patch
new file mode 100644
index 0000000000..52ba390cde
--- /dev/null
+++ b/meta/recipes-support/curl/curl/CVE-2024-11053-0001.patch
@@ -0,0 +1,353 @@
1From 9bee39bfed2c413b4cc4eb306a57ac92a1854907 Mon Sep 17 00:00:00 2001
2From: Daniel Stenberg <daniel@haxx.se>
3Date: Sat, 12 Oct 2024 23:54:39 +0200
4Subject: [PATCH] url: use same credentials on redirect
5
6Previously it could lose the username and only use the password.
7
8Added test 998 and 999 to verify.
9
10Reported-by: Tobias Bora
11Fixes #15262
12Closes #15282
13
14Changes:
15- Test files are added in Makefile.inc.
16
17CVE: CVE-2024-11053
18Upstream-Status: Backport [https://github.com/curl/curl/commit/9bee39bfed2c413b4cc4eb306a57ac92a1854907]
19
20Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
21---
22 lib/transfer.c | 3 ++
23 lib/url.c | 19 +++++----
24 lib/urldata.h | 9 +++-
25 tests/data/Makefile.inc | 2 +-
26 tests/data/test998 | 92 +++++++++++++++++++++++++++++++++++++++++
27 tests/data/test999 | 81 ++++++++++++++++++++++++++++++++++++
28 6 files changed, 195 insertions(+), 11 deletions(-)
29 create mode 100644 tests/data/test998
30 create mode 100644 tests/data/test999
31
32diff --git a/lib/transfer.c b/lib/transfer.c
33index e31d1d6..ccd042b 100644
34--- a/lib/transfer.c
35+++ b/lib/transfer.c
36@@ -700,6 +700,9 @@ CURLcode Curl_pretransfer(struct Curl_easy *data)
37 return CURLE_OUT_OF_MEMORY;
38 }
39
40+ if(data->set.str[STRING_USERNAME] ||
41+ data->set.str[STRING_PASSWORD])
42+ data->state.creds_from = CREDS_OPTION;
43 if(!result)
44 result = Curl_setstropt(&data->state.aptr.user,
45 data->set.str[STRING_USERNAME]);
46diff --git a/lib/url.c b/lib/url.c
47index 224b9f3..05431b9 100644
48--- a/lib/url.c
49+++ b/lib/url.c
50@@ -1899,10 +1899,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
51 return result;
52
53 /*
54- * User name and password set with their own options override the
55- * credentials possibly set in the URL.
56+ * username and password set with their own options override the credentials
57+ * possibly set in the URL, but netrc does not.
58 */
59- if(!data->set.str[STRING_PASSWORD]) {
60+ if(!data->state.aptr.passwd || (data->state.creds_from != CREDS_OPTION)) {
61 uc = curl_url_get(uh, CURLUPART_PASSWORD, &data->state.up.password, 0);
62 if(!uc) {
63 char *decoded;
64@@ -1915,12 +1915,13 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
65 result = Curl_setstropt(&data->state.aptr.passwd, decoded);
66 if(result)
67 return result;
68+ data->state.creds_from = CREDS_URL;
69 }
70 else if(uc != CURLUE_NO_PASSWORD)
71 return Curl_uc_to_curlcode(uc);
72 }
73
74- if(!data->set.str[STRING_USERNAME]) {
75+ if(!data->state.aptr.user || (data->state.creds_from != CREDS_OPTION)) {
76 /* we don't use the URL API's URL decoder option here since it rejects
77 control codes and we want to allow them for some schemes in the user
78 and password fields */
79@@ -1934,13 +1935,10 @@ static CURLcode parseurlandfillconn(struct Curl_easy *data,
80 return result;
81 conn->user = decoded;
82 result = Curl_setstropt(&data->state.aptr.user, decoded);
83+ data->state.creds_from = CREDS_URL;
84 }
85 else if(uc != CURLUE_NO_USER)
86 return Curl_uc_to_curlcode(uc);
87- else if(data->state.aptr.passwd) {
88- /* no user was set but a password, set a blank user */
89- result = Curl_setstropt(&data->state.aptr.user, "");
90- }
91 if(result)
92 return result;
93 }
94@@ -2730,7 +2728,8 @@ static CURLcode override_login(struct Curl_easy *data,
95 int ret;
96 bool url_provided = FALSE;
97
98- if(data->state.aptr.user) {
99+ if(data->state.aptr.user &&
100+ (data->state.creds_from != CREDS_NETRC)) {
101 /* there was a user name in the URL. Use the URL decoded version */
102 userp = &data->state.aptr.user;
103 url_provided = TRUE;
104@@ -2778,6 +2777,7 @@ static CURLcode override_login(struct Curl_easy *data,
105 result = Curl_setstropt(&data->state.aptr.user, *userp);
106 if(result)
107 return result;
108+ data->state.creds_from = CREDS_NETRC;
109 }
110 }
111 if(data->state.aptr.user) {
112@@ -2795,6 +2795,7 @@ static CURLcode override_login(struct Curl_easy *data,
113 CURLcode result = Curl_setstropt(&data->state.aptr.passwd, *passwdp);
114 if(result)
115 return result;
116+ data->state.creds_from = CREDS_NETRC;
117 }
118 if(data->state.aptr.passwd) {
119 uc = curl_url_set(data->state.uh, CURLUPART_PASSWORD,
120diff --git a/lib/urldata.h b/lib/urldata.h
121index ce28f25..b68d023 100644
122--- a/lib/urldata.h
123+++ b/lib/urldata.h
124@@ -1207,6 +1207,11 @@ struct urlpieces {
125 char *query;
126 };
127
128+#define CREDS_NONE 0
129+#define CREDS_URL 1 /* from URL */
130+#define CREDS_OPTION 2 /* set with a CURLOPT_ */
131+#define CREDS_NETRC 3 /* found in netrc */
132+
133 struct UrlState {
134 /* Points to the connection cache */
135 struct conncache *conn_cache;
136@@ -1344,7 +1349,6 @@ struct UrlState {
137 char *proxyuser;
138 char *proxypasswd;
139 } aptr;
140-
141 unsigned char httpwant; /* when non-zero, a specific HTTP version requested
142 to be used in the library's request(s) */
143 unsigned char httpversion; /* the lowest HTTP version*10 reported by any
144@@ -1354,6 +1358,9 @@ struct UrlState {
145 unsigned char select_bits; /* != 0 -> bitmask of socket events for this
146 transfer overriding anything the socket may
147 report */
148+ unsigned int creds_from:2; /* where is the server credentials originating
149+ from, see the CREDS_* defines above */
150+
151 #ifdef CURLDEBUG
152 BIT(conncache_lock);
153 #endif
154diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
155index d89e565..03cb6a0 100644
156--- a/tests/data/Makefile.inc
157+++ b/tests/data/Makefile.inc
158@@ -126,7 +126,7 @@ test952 test953 test954 test955 test956 test957 test958 test959 test960 \
159 test961 test962 test963 test964 test965 test966 test967 test968 test969 \
160 test970 test971 test972 test973 test974 test975 test976 test977 test978 \
161 test979 test980 test981 test982 test983 test984 test985 test986 test987 \
162-test988 test989 test990 test991 test992 \
163+test988 test989 test990 test991 test992 test998 test999 \
164 \
165 test1000 test1001 test1002 test1003 test1004 test1005 test1006 test1007 \
166 test1008 test1009 test1010 test1011 test1012 test1013 test1014 test1015 \
167diff --git a/tests/data/test998 b/tests/data/test998
168new file mode 100644
169index 0000000..596b18e
170--- /dev/null
171+++ b/tests/data/test998
172@@ -0,0 +1,92 @@
173+<testcase>
174+ <info>
175+ <keywords>
176+ HTTP
177+ --location-trusted
178+ </keywords>
179+ </info>
180+
181+ #
182+ # Server-side
183+ <reply>
184+ <data>
185+ HTTP/1.1 301 redirect
186+ Date: Tue, 09 Nov 2010 14:49:00 GMT
187+ Server: test-server/fake
188+ Content-Length: 0
189+ Connection: close
190+ Content-Type: text/html
191+ Location: http://somewhere.else.example/a/path/%TESTNUMBER0002
192+
193+ </data>
194+ <data2>
195+ HTTP/1.1 200 OK
196+ Date: Tue, 09 Nov 2010 14:49:00 GMT
197+ Content-Length: 6
198+ Content-Type: text/html
199+ Funny-head: yesyes
200+
201+ -foo-
202+ </data2>
203+
204+ <datacheck>
205+ HTTP/1.1 301 redirect
206+ Date: Tue, 09 Nov 2010 14:49:00 GMT
207+ Server: test-server/fake
208+ Content-Length: 0
209+ Connection: close
210+ Content-Type: text/html
211+ Location: http://somewhere.else.example/a/path/%TESTNUMBER0002
212+
213+ HTTP/1.1 200 OK
214+ Date: Tue, 09 Nov 2010 14:49:00 GMT
215+ Content-Length: 6
216+ Content-Type: text/html
217+ Funny-head: yesyes
218+
219+ -foo-
220+ </datacheck>
221+
222+ </reply>
223+
224+ #
225+ # Client-side
226+ <client>
227+ <features>
228+ proxy
229+ </features>
230+ <server>
231+ http
232+ </server>
233+ <name>
234+ HTTP with auth in URL redirected to another host
235+ </name>
236+ <command>
237+ -x %HOSTIP:%HTTPPORT http://alberto:einstein@somwhere.example/%TESTNUMBER --location-trusted
238+ </command>
239+ </client>
240+
241+ #
242+ # Verify data after the test has been "shot"
243+ <verify>
244+ <strip>
245+ QUIT
246+ </strip>
247+ <protocol>
248+ GET http://somwhere.example/998 HTTP/1.1
249+ Host: somwhere.example
250+ Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg==
251+ User-Agent: curl/%VERSION
252+ Accept: */*
253+ Proxy-Connection: Keep-Alive
254+
255+ GET http://somewhere.else.example/a/path/9980002 HTTP/1.1
256+ Host: somewhere.else.example
257+ Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg==
258+ User-Agent: curl/%VERSION
259+ Accept: */*
260+ Proxy-Connection: Keep-Alive
261+
262+ </protocol>
263+ </verify>
264+ </testcase>
265diff --git a/tests/data/test999 b/tests/data/test999
266new file mode 100644
267index 0000000..184821d
268--- /dev/null
269+++ b/tests/data/test999
270@@ -0,0 +1,81 @@
271+<testcase>
272+ <info>
273+ <keywords>
274+ HTTP
275+ --location-trusted
276+ </keywords>
277+ </info>
278+
279+ #
280+ # Server-side
281+ <reply>
282+ <data nocheck="yes">
283+ HTTP/1.1 200 OK
284+ Date: Tue, 09 Nov 2010 14:49:00 GMT
285+ Content-Length: 6
286+ Content-Type: text/html
287+ Funny-head: yesyes
288+
289+ -foo-
290+ </data>
291+
292+ <datacheck>
293+ HTTP/1.1 301 redirect
294+ Date: Tue, 09 Nov 2010 14:49:00 GMT
295+ Server: test-server/fake
296+ Content-Length: 0
297+ Connection: close
298+ Content-Type: text/html
299+ Location: http://somewhere.else.example/a/path/%TESTNUMBER0002
300+
301+ HTTP/1.1 200 OK
302+ Date: Tue, 09 Nov 2010 14:49:00 GMT
303+ Content-Length: 6
304+ Content-Type: text/html
305+ Funny-head: yesyes
306+
307+ -foo-
308+ </datacheck>
309+
310+ </reply>
311+
312+ #
313+ # Client-side
314+ <client>
315+ <features>
316+ proxy
317+ </features>
318+ <server>
319+ http
320+ </server>
321+ <name>
322+ HTTP with auth in first URL but not second
323+ </name>
324+ <command>
325+ -x %HOSTIP:%HTTPPORT http://alberto:einstein@somwhere.example/%TESTNUMBER http://somewhere.else.example/%TESTNUMBER
326+ </command>
327+ </client>
328+
329+ #
330+ # Verify data after the test has been "shot"
331+ <verify>
332+ <strip>
333+ QUIT
334+ </strip>
335+ <protocol>
336+ GET http://somwhere.example/%TESTNUMBER HTTP/1.1
337+ Host: somwhere.example
338+ Authorization: Basic YWxiZXJ0bzplaW5zdGVpbg==
339+ User-Agent: curl/%VERSION
340+ Accept: */*
341+ Proxy-Connection: Keep-Alive
342+
343+ GET http://somewhere.else.example/%TESTNUMBER HTTP/1.1
344+ Host: somewhere.else.example
345+ User-Agent: curl/%VERSION
346+ Accept: */*
347+ Proxy-Connection: Keep-Alive
348+
349+ </protocol>
350+ </verify>
351+ </testcase>
352--
3532.40.0
diff --git a/meta/recipes-support/curl/curl/CVE-2024-11053-0002.patch b/meta/recipes-support/curl/curl/CVE-2024-11053-0002.patch
new file mode 100644
index 0000000000..7f45f79cf2
--- /dev/null
+++ b/meta/recipes-support/curl/curl/CVE-2024-11053-0002.patch
@@ -0,0 +1,728 @@
1From e9b9bbac22c26cf67316fa8e6c6b9e831af31949 Mon Sep 17 00:00:00 2001
2From: Daniel Stenberg <daniel@haxx.se>
3Date: Fri, 15 Nov 2024 11:06:36 +0100
4Subject: [PATCH] netrc: address several netrc parser flaws
5
6- make sure that a match that returns a username also returns a
7 password, that should be blank if no password is found
8
9- fix handling of multiple logins for same host where the password/login
10 order might be reversed.
11
12- reject credentials provided in the .netrc if they contain ASCII control
13 codes - if the used protocol does not support such (like HTTP and WS do)
14
15Reported-by: Harry Sintonen
16
17Add test 478, 479 and 480 to verify. Updated unit 1304.
18
19Closes #15586
20
21Changes:
22- Refresh patch context.
23- Adjust `%LOGDIR/` to 'log/' due to its absence in code.
24- Backported only required enum found_state defination from:
25 https://github.com/curl/curl/commit/3b43a05e000aa8f65bda513f733a73fefe35d5ca
26- Replaces the previous usage of the state_login, state_password, and
27 state_our_login variables with the found_state enum, which includes the
28 values NONE, LOGIN, and PASSWORD. As a result, all conditionals and memory
29 management logic associated with these variables were updated.
30
31CVE: CVE-2024-11053
32Upstream-Status: Backport [https://github.com/curl/curl/commit/e9b9bbac22c26cf67316fa8e6c6b9e831af3194]
33
34Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
35---
36 lib/netrc.c | 122 ++++++++++++++++++++++------------------
37 lib/url.c | 59 ++++++++++++-------
38 tests/data/Makefile.inc | 2 +-
39 tests/data/test478 | 73 ++++++++++++++++++++++++
40 tests/data/test479 | 107 +++++++++++++++++++++++++++++++++++
41 tests/data/test480 | 38 +++++++++++++
42 tests/unit/unit1304.c | 75 +++++++-----------------
43 7 files changed, 347 insertions(+), 129 deletions(-)
44 create mode 100644 tests/data/test478
45 create mode 100644 tests/data/test479
46 create mode 100644 tests/data/test480
47
48diff --git a/lib/netrc.c b/lib/netrc.c
49index cd2a284..64efdc0 100644
50--- a/lib/netrc.c
51+++ b/lib/netrc.c
52@@ -49,6 +49,15 @@ enum host_lookup_state {
53 MACDEF
54 };
55
56+enum found_state {
57+ NONE,
58+ LOGIN,
59+ PASSWORD
60+};
61+
62+#define FOUND_LOGIN 1
63+#define FOUND_PASSWORD 2
64+
65 #define NETRC_FILE_MISSING 1
66 #define NETRC_FAILED -1
67 #define NETRC_SUCCESS 0
68@@ -59,23 +68,20 @@ enum host_lookup_state {
69 * Returns zero on success.
70 */
71 static int parsenetrc(const char *host,
72- char **loginp,
73+ char **loginp, /* might point to a username */
74 char **passwordp,
75 char *netrcfile)
76 {
77 FILE *file;
78 int retcode = NETRC_FILE_MISSING;
79 char *login = *loginp;
80- char *password = *passwordp;
81- bool specific_login = (login && *login != 0);
82- bool login_alloc = FALSE;
83- bool password_alloc = FALSE;
84+ char *password = NULL;
85+ bool specific_login = login; /* points to something */
86 enum host_lookup_state state = NOTHING;
87-
88- char state_login = 0; /* Found a login keyword */
89- char state_password = 0; /* Found a password keyword */
90- int state_our_login = TRUE; /* With specific_login, found *our* login
91- name (or login-less line) */
92+ enum found_state keyword = NONE;
93+ unsigned char found = 0; /* login + password found bits, as they can come in
94+ any order */
95+ bool our_login = FALSE; /* found our login name */
96
97 DEBUGASSERT(netrcfile);
98
99@@ -97,7 +103,7 @@ static int parsenetrc(const char *host,
100 continue;
101 }
102 tok = netrcbuffer;
103- while(tok) {
104+ while(tok && !done) {
105 while(ISBLANK(*tok))
106 tok++;
107 /* tok is first non-space letter */
108@@ -156,11 +162,6 @@ static int parsenetrc(const char *host,
109 }
110 }
111
112- if((login && *login) && (password && *password)) {
113- done = TRUE;
114- break;
115- }
116-
117 switch(state) {
118 case NOTHING:
119 if(strcasecompare("macdef", tok)) {
120@@ -175,6 +176,12 @@ static int parsenetrc(const char *host,
121 after this we need to search for 'login' and
122 'password'. */
123 state = HOSTFOUND;
124+ keyword = NONE;
125+ found = 0;
126+ our_login = FALSE;
127+ Curl_safefree(password);
128+ if(!specific_login)
129+ Curl_safefree(login);
130 }
131 else if(strcasecompare("default", tok)) {
132 state = HOSTVALID;
133@@ -198,48 +205,55 @@ static int parsenetrc(const char *host,
134 break;
135 case HOSTVALID:
136 /* we are now parsing sub-keywords concerning "our" host */
137- if(state_login) {
138+ if(keyword == LOGIN) {
139 if(specific_login) {
140- state_our_login = !Curl_timestrcmp(login, tok);
141+ our_login = !Curl_timestrcmp(login, tok);
142 }
143- else if(!login || Curl_timestrcmp(login, tok)) {
144- if(login_alloc) {
145- free(login);
146- login_alloc = FALSE;
147- }
148+ else {
149+ our_login = TRUE;
150+ free(login);
151 login = strdup(tok);
152 if(!login) {
153 retcode = NETRC_FAILED; /* allocation failed */
154 goto out;
155 }
156- login_alloc = TRUE;
157 }
158- state_login = 0;
159+ found |= FOUND_LOGIN;
160+ keyword = NONE;
161 }
162- else if(state_password) {
163- if((state_our_login || !specific_login)
164- && (!password || Curl_timestrcmp(password, tok))) {
165- if(password_alloc) {
166- free(password);
167- password_alloc = FALSE;
168- }
169- password = strdup(tok);
170- if(!password) {
171- retcode = NETRC_FAILED; /* allocation failed */
172- goto out;
173- }
174- password_alloc = TRUE;
175+ else if(keyword == PASSWORD) {
176+ free(password);
177+ password = strdup(tok);
178+ if(!password) {
179+ retcode = NETRC_FAILED; /* allocation failed */
180+ goto out;
181 }
182- state_password = 0;
183+ found |= FOUND_PASSWORD;
184+ keyword = NONE;
185 }
186 else if(strcasecompare("login", tok))
187- state_login = 1;
188+ keyword = LOGIN;
189 else if(strcasecompare("password", tok))
190- state_password = 1;
191+ keyword = PASSWORD;
192 else if(strcasecompare("machine", tok)) {
193- /* ok, there's machine here go => */
194+ /* a new machine here */
195 state = HOSTFOUND;
196- state_our_login = FALSE;
197+ keyword = NONE;
198+ found = 0;
199+ Curl_safefree(password);
200+ if(!specific_login)
201+ Curl_safefree(login);
202+ }
203+ else if(strcasecompare("default", tok)) {
204+ state = HOSTVALID;
205+ retcode = NETRC_SUCCESS; /* we did find our host */
206+ Curl_safefree(password);
207+ if(!specific_login)
208+ Curl_safefree(login);
209+ }
210+ if((found == (FOUND_PASSWORD|FOUND_LOGIN)) && our_login) {
211+ done = TRUE;
212+ break;
213 }
214 break;
215 } /* switch (state) */
216@@ -249,24 +263,22 @@ static int parsenetrc(const char *host,
217
218 out:
219 Curl_dyn_free(&buf);
220+ if(!retcode && !password && our_login) {
221+ /* success without a password, set a blank one */
222+ password = strdup("");
223+ if(!password)
224+ retcode = 1; /* out of memory */
225+ }
226 if(!retcode) {
227 /* success */
228- if(login_alloc) {
229- if(*loginp)
230- free(*loginp);
231+ if(!specific_login)
232 *loginp = login;
233- }
234- if(password_alloc) {
235- if(*passwordp)
236- free(*passwordp);
237- *passwordp = password;
238- }
239+ *passwordp = password;
240 }
241 else {
242- if(login_alloc)
243+ if(!specific_login)
244 free(login);
245- if(password_alloc)
246- free(password);
247+ free(password);
248 }
249 fclose(file);
250 }
251diff --git a/lib/url.c b/lib/url.c
252index 05431b9..1439c9e 100644
253--- a/lib/url.c
254+++ b/lib/url.c
255@@ -2699,6 +2699,17 @@ static CURLcode parse_remote_port(struct Curl_easy *data,
256 return CURLE_OK;
257 }
258
259+static bool str_has_ctrl(const char *input)
260+{
261+ const unsigned char *str = (const unsigned char *)input;
262+ while(*str) {
263+ if(*str < 0x20)
264+ return TRUE;
265+ str++;
266+ }
267+ return FALSE;
268+}
269+
270 /*
271 * Override the login details from the URL with that in the CURLOPT_USERPWD
272 * option or a .netrc file, if applicable.
273@@ -2730,29 +2741,39 @@ static CURLcode override_login(struct Curl_easy *data,
274
275 if(data->state.aptr.user &&
276 (data->state.creds_from != CREDS_NETRC)) {
277- /* there was a user name in the URL. Use the URL decoded version */
278+ /* there was a username with a length in the URL. Use the URL decoded
279+ version */
280 userp = &data->state.aptr.user;
281 url_provided = TRUE;
282 }
283
284- ret = Curl_parsenetrc(conn->host.name,
285- userp, passwdp,
286- data->set.str[STRING_NETRC_FILE]);
287- if(ret > 0) {
288- infof(data, "Couldn't find host %s in the %s file; using defaults",
289- conn->host.name,
290- (data->set.str[STRING_NETRC_FILE] ?
291- data->set.str[STRING_NETRC_FILE] : ".netrc"));
292- }
293- else if(ret < 0) {
294- failf(data, ".netrc parser error");
295- return CURLE_READ_ERROR;
296- }
297- else {
298- /* set bits.netrc TRUE to remember that we got the name from a .netrc
299- file, so that it is safe to use even if we followed a Location: to a
300- different host or similar. */
301- conn->bits.netrc = TRUE;
302+ if(!*passwdp) {
303+ ret = Curl_parsenetrc(conn->host.name, userp, passwdp,
304+ data->set.str[STRING_NETRC_FILE]);
305+ if(ret > 0) {
306+ infof(data, "Couldn't find host %s in the %s file; using defaults",
307+ conn->host.name,
308+ (data->set.str[STRING_NETRC_FILE] ?
309+ data->set.str[STRING_NETRC_FILE] : ".netrc"));
310+ }
311+ else if(ret < 0) {
312+ failf(data, ".netrc parser error");
313+ return CURLE_READ_ERROR;
314+ }
315+ else {
316+ if(!(conn->handler->flags&PROTOPT_USERPWDCTRL)) {
317+ /* if the protocol can't handle control codes in credentials, make
318+ sure there are none */
319+ if(str_has_ctrl(*userp) || str_has_ctrl(*passwdp)) {
320+ failf(data, "control code detected in .netrc credentials");
321+ return CURLE_READ_ERROR;
322+ }
323+ }
324+ /* set bits.netrc TRUE to remember that we got the name from a .netrc
325+ file, so that it is safe to use even if we followed a Location: to a
326+ different host or similar. */
327+ conn->bits.netrc = TRUE;
328+ }
329 }
330 if(url_provided) {
331 Curl_safefree(conn->user);
332diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
333index 03cb6a0..e3508cb 100644
334--- a/tests/data/Makefile.inc
335+++ b/tests/data/Makefile.inc
336@@ -73,7 +73,7 @@ test426 test427 test428 test429 test430 test431 test432 test433 test434 \
337 test435 test436 test437 test438 test439 test440 test441 test442 test443 \
338 test444 test445 test446 test447 test448 test449 test450 test451 test452 \
339 test453 test454 test455 test456 test457 test458 test459 test460 test461 \
340-test462 test463 test467 test468 \
341+test462 test463 test467 test468 test478 test479 test480 \
342 \
343 test490 test491 test492 test493 test494 test495 test496 test497 test498 \
344 test499 test500 test501 test502 test503 test504 test505 test506 test507 \
345diff --git a/tests/data/test478 b/tests/data/test478
346new file mode 100644
347index 0000000..4acc72e
348--- /dev/null
349+++ b/tests/data/test478
350@@ -0,0 +1,73 @@
351+<testcase>
352+ <info>
353+ <keywords>
354+ netrc
355+ HTTP
356+ </keywords>
357+ </info>
358+ #
359+ # Server-side
360+ <reply>
361+ <data crlf="yes">
362+ HTTP/1.1 200 OK
363+ Date: Tue, 09 Nov 2010 14:49:00 GMT
364+ Server: test-server/fake
365+ Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
366+ ETag: "21025-dc7-39462498"
367+ Accept-Ranges: bytes
368+ Content-Length: 6
369+ Connection: close
370+ Content-Type: text/html
371+ Funny-head: yesyes
372+
373+ -foo-
374+ </data>
375+ </reply>
376+
377+ #
378+ # Client-side
379+ <client>
380+ <server>
381+ http
382+ </server>
383+ <features>
384+ proxy
385+ </features>
386+ <name>
387+ .netrc with multiple accounts for same host
388+ </name>
389+ <command>
390+ --netrc --netrc-file log/netrc%TESTNUMBER -x http://%HOSTIP:%HTTPPORT/ http://debbie@github.com/
391+ </command>
392+ <file name="log/netrc%TESTNUMBER" >
393+
394+ machine github.com
395+ password weird
396+ password firstone
397+ login daniel
398+
399+ machine github.com
400+
401+ machine github.com
402+ login debbie
403+
404+ machine github.com
405+ password weird
406+ password "second\r"
407+ login debbie
408+
409+ </file>
410+ </client>
411+
412+ <verify>
413+ <protocol>
414+ GET http://github.com/ HTTP/1.1
415+ Host: github.com
416+ Authorization: Basic %b64[debbie:second%0D]b64%
417+ User-Agent: curl/%VERSION
418+ Accept: */*
419+ Proxy-Connection: Keep-Alive
420+
421+ </protocol>
422+ </verify>
423+ </testcase>
424diff --git a/tests/data/test479 b/tests/data/test479
425new file mode 100644
426index 0000000..62a2057
427--- /dev/null
428+++ b/tests/data/test479
429@@ -0,0 +1,107 @@
430+<testcase>
431+ <info>
432+ <keywords>
433+ netrc
434+ HTTP
435+ </keywords>
436+ </info>
437+ #
438+ # Server-side
439+ <reply>
440+ <data crlf="yes">
441+ HTTP/1.1 301 Follow this you fool
442+ Date: Tue, 09 Nov 2010 14:49:00 GMT
443+ Server: test-server/fake
444+ Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
445+ ETag: "21025-dc7-39462498"
446+ Accept-Ranges: bytes
447+ Content-Length: 6
448+ Connection: close
449+ Location: http://b.com/%TESTNUMBER0002
450+
451+ -foo-
452+ </data>
453+
454+ <data2 crlf="yes">
455+ HTTP/1.1 200 OK
456+ Date: Tue, 09 Nov 2010 14:49:00 GMT
457+ Server: test-server/fake
458+ Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
459+ ETag: "21025-dc7-39462498"
460+ Accept-Ranges: bytes
461+ Content-Length: 7
462+ Connection: close
463+
464+ target
465+ </data2>
466+
467+ <datacheck crlf="yes">
468+ HTTP/1.1 301 Follow this you fool
469+ Date: Tue, 09 Nov 2010 14:49:00 GMT
470+ Server: test-server/fake
471+ Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
472+ ETag: "21025-dc7-39462498"
473+ Accept-Ranges: bytes
474+ Content-Length: 6
475+ Connection: close
476+ Location: http://b.com/%TESTNUMBER0002
477+
478+ HTTP/1.1 200 OK
479+ Date: Tue, 09 Nov 2010 14:49:00 GMT
480+ Server: test-server/fake
481+ Last-Modified: Tue, 13 Jun 2000 12:10:00 GMT
482+ ETag: "21025-dc7-39462498"
483+ Accept-Ranges: bytes
484+ Content-Length: 7
485+ Connection: close
486+
487+ target
488+ </datacheck>
489+ </reply>
490+
491+ #
492+ # Client-side
493+ <client>
494+ <server>
495+ http
496+ </server>
497+ <features>
498+ proxy
499+ </features>
500+ <name>
501+ .netrc with redirect and default without password
502+ </name>
503+ <command>
504+ --netrc --netrc-file log/netrc%TESTNUMBER -L -x http://%HOSTIP:%HTTPPORT/ http://a.com/
505+ </command>
506+ <file name="log/netrc%TESTNUMBER" >
507+
508+ machine a.com
509+ login alice
510+ password alicespassword
511+
512+ default
513+ login bob
514+
515+ </file>
516+ </client>
517+
518+ <verify>
519+ <protocol>
520+ GET http://a.com/ HTTP/1.1
521+ Host: a.com
522+ Authorization: Basic %b64[alice:alicespassword]b64%
523+ User-Agent: curl/%VERSION
524+ Accept: */*
525+ Proxy-Connection: Keep-Alive
526+
527+ GET http://b.com/%TESTNUMBER0002 HTTP/1.1
528+ Host: b.com
529+ Authorization: Basic %b64[bob:]b64%
530+ User-Agent: curl/%VERSION
531+ Accept: */*
532+ Proxy-Connection: Keep-Alive
533+
534+ </protocol>
535+ </verify>
536+ </testcase>
537diff --git a/tests/data/test480 b/tests/data/test480
538new file mode 100644
539index 0000000..47db7ab
540--- /dev/null
541+++ b/tests/data/test480
542@@ -0,0 +1,38 @@
543+<testcase>
544+ <info>
545+ <keywords>
546+ netrc
547+ pop3
548+ </keywords>
549+ </info>
550+ #
551+ # Server-side
552+ <reply>
553+
554+ </reply>
555+
556+ #
557+ # Client-side
558+ <client>
559+ <server>
560+ pop3
561+ </server>
562+ <name>
563+ Reject .netrc with credentials using CRLF for POP3
564+ </name>
565+ <command>
566+ --netrc --netrc-file log/netrc%TESTNUMBER pop3://%HOSTIP:%POP3PORT/%TESTNUMBER
567+ </command>
568+ <file name="log/netrc%TESTNUMBER" >
569+ machine %HOSTIP
570+ login alice
571+ password "password\r\ncommand"
572+ </file>
573+ </client>
574+
575+ <verify>
576+ <errorcode>
577+ 26
578+ </errorcode>
579+ </verify>
580+ </testcase>
581diff --git a/tests/unit/unit1304.c b/tests/unit/unit1304.c
582index 0288562..b2b4366 100644
583--- a/tests/unit/unit1304.c
584+++ b/tests/unit/unit1304.c
585@@ -32,13 +32,8 @@ static char *password;
586
587 static CURLcode unit_setup(void)
588 {
589- password = strdup("");
590- login = strdup("");
591- if(!password || !login) {
592- Curl_safefree(password);
593- Curl_safefree(login);
594- return CURLE_OUT_OF_MEMORY;
595- }
596+ password = NULL;
597+ login = NULL;
598 return CURLE_OK;
599 }
600
601@@ -56,76 +51,48 @@ UNITTEST_START
602 */
603 result = Curl_parsenetrc("test.example.com", &login, &password, arg);
604 fail_unless(result == 1, "Host not found should return 1");
605- abort_unless(password != NULL, "returned NULL!");
606- fail_unless(password[0] == 0, "password should not have been changed");
607- abort_unless(login != NULL, "returned NULL!");
608- fail_unless(login[0] == 0, "login should not have been changed");
609+ abort_unless(password == NULL, "password did not return NULL!");
610+ abort_unless(login == NULL, "user did not return NULL!");
611
612 /*
613 * Test a non existent login in our netrc file.
614 */
615- free(login);
616- login = strdup("me");
617- abort_unless(login != NULL, "returned NULL!");
618+ login = (char *)"me";
619 result = Curl_parsenetrc("example.com", &login, &password, arg);
620 fail_unless(result == 0, "Host should have been found");
621- abort_unless(password != NULL, "returned NULL!");
622- fail_unless(password[0] == 0, "password should not have been changed");
623- abort_unless(login != NULL, "returned NULL!");
624- fail_unless(strncmp(login, "me", 2) == 0,
625- "login should not have been changed");
626+ abort_unless(password == NULL, "password is not NULL!");
627
628 /*
629 * Test a non existent login and host in our netrc file.
630 */
631- free(login);
632- login = strdup("me");
633- abort_unless(login != NULL, "returned NULL!");
634+ login = (char *)"me";
635 result = Curl_parsenetrc("test.example.com", &login, &password, arg);
636 fail_unless(result == 1, "Host not found should return 1");
637- abort_unless(password != NULL, "returned NULL!");
638- fail_unless(password[0] == 0, "password should not have been changed");
639- abort_unless(login != NULL, "returned NULL!");
640- fail_unless(strncmp(login, "me", 2) == 0,
641- "login should not have been changed");
642+ abort_unless(password == NULL, "password is not NULL!");
643
644 /*
645 * Test a non existent login (substring of an existing one) in our
646 * netrc file.
647 */
648- free(login);
649- login = strdup("admi");
650- abort_unless(login != NULL, "returned NULL!");
651+ login = (char *)"admi";
652 result = Curl_parsenetrc("example.com", &login, &password, arg);
653 fail_unless(result == 0, "Host should have been found");
654- abort_unless(password != NULL, "returned NULL!");
655- fail_unless(password[0] == 0, "password should not have been changed");
656- abort_unless(login != NULL, "returned NULL!");
657- fail_unless(strncmp(login, "admi", 4) == 0,
658- "login should not have been changed");
659+ abort_unless(password == NULL, "password is not NULL!");
660
661 /*
662 * Test a non existent login (superstring of an existing one)
663 * in our netrc file.
664 */
665- free(login);
666- login = strdup("adminn");
667- abort_unless(login != NULL, "returned NULL!");
668+ login = (char *)"adminn";
669 result = Curl_parsenetrc("example.com", &login, &password, arg);
670 fail_unless(result == 0, "Host should have been found");
671- abort_unless(password != NULL, "returned NULL!");
672- fail_unless(password[0] == 0, "password should not have been changed");
673- abort_unless(login != NULL, "returned NULL!");
674- fail_unless(strncmp(login, "adminn", 6) == 0,
675- "login should not have been changed");
676+ abort_unless(password == NULL, "password is not NULL!");
677
678 /*
679 * Test for the first existing host in our netrc file
680 * with login[0] = 0.
681 */
682- free(login);
683- login = strdup("");
684- abort_unless(login != NULL, "returned NULL!");
685+ login = NULL;
686 result = Curl_parsenetrc("example.com", &login, &password, arg);
687 fail_unless(result == 0, "Host should have been found");
688 abort_unless(password != NULL, "returned NULL!");
689@@ -139,8 +106,9 @@ UNITTEST_START
690 * with login[0] != 0.
691 */
692 free(password);
693- password = strdup("");
694- abort_unless(password != NULL, "returned NULL!");
695+ free(login);
696+ password = NULL;
697+ login = NULL;
698 result = Curl_parsenetrc("example.com", &login, &password, arg);
699 fail_unless(result == 0, "Host should have been found");
700 abort_unless(password != NULL, "returned NULL!");
701@@ -154,11 +122,9 @@ UNITTEST_START
702 * with login[0] = 0.
703 */
704 free(password);
705- password = strdup("");
706- abort_unless(password != NULL, "returned NULL!");
707+ password = NULL;
708 free(login);
709- login = strdup("");
710- abort_unless(login != NULL, "returned NULL!");
711+ login = NULL;
712 result = Curl_parsenetrc("curl.example.com", &login, &password, arg);
713 fail_unless(result == 0, "Host should have been found");
714 abort_unless(password != NULL, "returned NULL!");
715@@ -172,8 +138,9 @@ UNITTEST_START
716 * with login[0] != 0.
717 */
718 free(password);
719- password = strdup("");
720- abort_unless(password != NULL, "returned NULL!");
721+ free(login);
722+ password = NULL;
723+ login = NULL;
724 result = Curl_parsenetrc("curl.example.com", &login, &password, arg);
725 fail_unless(result == 0, "Host should have been found");
726 abort_unless(password != NULL, "returned NULL!");
727--
7282.40.0
diff --git a/meta/recipes-support/curl/curl/CVE-2024-11053-0003.patch b/meta/recipes-support/curl/curl/CVE-2024-11053-0003.patch
new file mode 100644
index 0000000000..32fb1812d6
--- /dev/null
+++ b/meta/recipes-support/curl/curl/CVE-2024-11053-0003.patch
@@ -0,0 +1,130 @@
1From 9fce2c55d4b0273ac99b59bd8cb982a6d96b88cf Mon Sep 17 00:00:00 2001
2From: Daniel Stenberg <daniel@haxx.se>
3Date: Tue, 17 Dec 2024 23:56:42 +0100
4Subject: [PATCH] netrc: fix password-only entries
5
6When a specific hostname matched, and only a password is set before
7another machine is specified in the netrc file, the parser would not be
8happy and stop there and return the password-only state. It instead
9continued and did not return a match.
10
11Add test 2005 to verify this case
12
13Regression from e9b9bba, shipped in 8.11.1.
14
15Reported-by: Ben Zanin
16Fixes #15767
17Closes #15768
18
19CVE: CVE-2024-11053
20Upstream-Status: Backport [https://github.com/curl/curl/commit/9fce2c55d4b0273ac99b59bd8cb982a6d96b88cf]
21
22Signed-off-by: Yogita Urade <yogita.urade@windriver.com>
23---
24 lib/netrc.c | 7 +++++-
25 tests/data/Makefile.inc | 2 +-
26 tests/data/test2005 | 55 +++++++++++++++++++++++++++++++++++++++++
27 3 files changed, 62 insertions(+), 2 deletions(-)
28 create mode 100644 tests/data/test2005
29
30diff --git a/lib/netrc.c b/lib/netrc.c
31index 64efdc0..695e89a 100644
32--- a/lib/netrc.c
33+++ b/lib/netrc.c
34@@ -228,7 +228,8 @@ static int parsenetrc(const char *host,
35 retcode = NETRC_FAILED; /* allocation failed */
36 goto out;
37 }
38- found |= FOUND_PASSWORD;
39+ if(!specific_login || our_login)
40+ found |= FOUND_PASSWORD;
41 keyword = NONE;
42 }
43 else if(strcasecompare("login", tok))
44@@ -237,6 +238,10 @@ static int parsenetrc(const char *host,
45 keyword = PASSWORD;
46 else if(strcasecompare("machine", tok)) {
47 /* a new machine here */
48+ if(found & FOUND_PASSWORD) {
49+ done = TRUE;
50+ break;
51+ }
52 state = HOSTFOUND;
53 keyword = NONE;
54 found = 0;
55diff --git a/tests/data/Makefile.inc b/tests/data/Makefile.inc
56index e3508cb..dc2af79 100644
57--- a/tests/data/Makefile.inc
58+++ b/tests/data/Makefile.inc
59@@ -230,7 +230,7 @@ test1941 test1942 test1943 test1944 test1945 test1946 test1947 test1948 \
60 test1955 test1956 test1957 test1958 test1959 test1960 test1964 \
61 test1970 test1971 test1972 test1973 test1974 test1975 \
62 \
63-test2000 test2001 test2002 test2003 test2004 \
64+test2000 test2001 test2002 test2003 test2004 test2005 \
65 \
66 test2023 \
67 test2024 test2025 test2026 test2027 test2028 test2029 test2030 test2031 \
68diff --git a/tests/data/test2005 b/tests/data/test2005
69new file mode 100644
70index 0000000..66afe84
71--- /dev/null
72+++ b/tests/data/test2005
73@@ -0,0 +1,55 @@
74+<testcase>
75+ <info>
76+ <keywords>
77+ HTTP
78+ netrc
79+ </keywords>
80+ </info>
81+ #
82+ # Server-side
83+ <reply>
84+ <data>
85+ HTTP/1.1 200 OK
86+ Date: Fri, 05 Aug 2022 10:09:00 GMT
87+ Server: test-server/fake
88+ Content-Type: text/plain
89+ Content-Length: 6
90+ Connection: close
91+
92+ -foo-
93+ </data>
94+ </reply>
95+
96+ #
97+ # Client-side
98+ <client>
99+ <server>
100+ http
101+ </server>
102+ <name>
103+ netrc match with password only in file, no username. machine follows
104+ </name>
105+ <command>
106+ --netrc-optional --netrc-file log/netrc%TESTNUMBER http://%HOSTIP:%HTTPPORT/
107+ </command>
108+ <file name="log/netrc%TESTNUMBER" >
109+ machine %HOSTIP
110+ password 5up3r53cr37
111+
112+ machine example.com
113+ </file>
114+ </client>
115+
116+ #
117+ # Verify data after the test has been "shot"
118+ <verify>
119+ <protocol>
120+ GET / HTTP/1.1
121+ Host: %HOSTIP:%HTTPPORT
122+ Authorization: Basic %b64[:5up3r53cr37]b64%
123+ User-Agent: curl/%VERSION
124+ Accept: */*
125+
126+ </protocol>
127+ </verify>
128+ </testcase>
129--
1302.40.0
diff --git a/meta/recipes-support/curl/curl_8.7.1.bb b/meta/recipes-support/curl/curl_8.7.1.bb
index ddd591dd96..6d6563591c 100644
--- a/meta/recipes-support/curl/curl_8.7.1.bb
+++ b/meta/recipes-support/curl/curl_8.7.1.bb
@@ -20,6 +20,9 @@ SRC_URI = " \
20 file://CVE-2024-7264-2.patch \ 20 file://CVE-2024-7264-2.patch \
21 file://CVE-2024-8096.patch \ 21 file://CVE-2024-8096.patch \
22 file://CVE-2024-9681.patch \ 22 file://CVE-2024-9681.patch \
23 file://CVE-2024-11053-0001.patch \
24 file://CVE-2024-11053-0002.patch \
25 file://CVE-2024-11053-0003.patch \
23" 26"
24SRC_URI[sha256sum] = "6fea2aac6a4610fbd0400afb0bcddbe7258a64c63f1f68e5855ebc0c659710cd" 27SRC_URI[sha256sum] = "6fea2aac6a4610fbd0400afb0bcddbe7258a64c63f1f68e5855ebc0c659710cd"
25 28