summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorYogita Urade <yogita.urade@windriver.com>2025-04-22 11:48:14 +0000
committerSteve Sakoman <steve@sakoman.com>2025-04-28 08:18:53 -0700
commit2e67952192f95cd7465c5c795e5d420aba8c9827 (patch)
tree71c400f0446776efdd483babb4040d0d00d0b251
parentf8ca40f3d1c504e065dc4e52bc059ef438d754eb (diff)
downloadpoky-2e67952192f95cd7465c5c795e5d420aba8c9827.tar.gz
curl: fix CVE-2024-11053
When asked to both use a `.netrc` file for credentials and to follow HTTP redirects, curl could leak the password used for the first host to the followed-to host under certain circumstances. This flaw only manifests itself if the netrc file has an entry that matches the redirect target hostname but the entry either omits just the password or omits both login and password. CVE-2024-11053-0001 is the dependent commit, CVE-2024-11053-0002 is actual CVE fix and the actual fix caused a regression that was fixed by CVE-2024-11053-0003. Reference: https://curl.se/docs/CVE-2024-11053.html https://git.launchpad.net/ubuntu/+source/curl/commit/?h=applied/ubuntu/noble-devel&id=9ea469c352a313104f750dea93e78df8d868c435 Upstream patches: https://github.com/curl/curl/commit/9bee39bfed2c413b4cc4eb306a57ac92a1854907 https://github.com/curl/curl/commit/e9b9bbac22c26cf67316fa8e6c6b9e831af3194 https://github.com/curl/curl/commit/9fce2c55d4b0273ac99b59bd8cb982a6d96b88cf (From OE-Core rev: 084d8ca3b47b47333edba87f6aa427a12ee574f2) Signed-off-by: Yogita Urade <yogita.urade@windriver.com> Signed-off-by: Steve Sakoman <steve@sakoman.com>
-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