diff options
author | Armin Kuster <akuster@mvista.com> | 2016-02-05 08:57:11 -0800 |
---|---|---|
committer | Richard Purdie <richard.purdie@linuxfoundation.org> | 2016-03-03 11:11:40 +0000 |
commit | 8ca73f8fa4ff7f9edb101ee563e5547d3edc46cb (patch) | |
tree | fb0793c4ed8839c18631a71e75d2e8a20daccd93 | |
parent | d25973e203b8298005389983bf17f613c940c40e (diff) | |
download | poky-8ca73f8fa4ff7f9edb101ee563e5547d3edc46cb.tar.gz |
curl: Security fix CVE-2016-0754
CVE-2016-0754 curl: remote file name path traversal in curl tool for Windows
(From OE-Core master rev: b2c9b48dea2fd968c307a809ff95f2e686435222)
minor tweak to tool_operate.c to get it to apply
(From OE-Core rev: b8df558ece47e51653e1fc0fb0637ec2cdf2907b)
Signed-off-by: Armin Kuster <akuster@mvista.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
Signed-off-by: Armin Kuster <akuster@mvista.com>
Signed-off-by: Joshua Lock <joshua.g.lock@intel.com>
Signed-off-by: Richard Purdie <richard.purdie@linuxfoundation.org>
-rw-r--r-- | meta/recipes-support/curl/curl/CVE-2016-0754.patch | 384 | ||||
-rw-r--r-- | meta/recipes-support/curl/curl_7.40.0.bb | 3 |
2 files changed, 386 insertions, 1 deletions
diff --git a/meta/recipes-support/curl/curl/CVE-2016-0754.patch b/meta/recipes-support/curl/curl/CVE-2016-0754.patch new file mode 100644 index 0000000000..b4683f435a --- /dev/null +++ b/meta/recipes-support/curl/curl/CVE-2016-0754.patch | |||
@@ -0,0 +1,384 @@ | |||
1 | From b1bb4ca6d8777683b6a549fb61dba36759da26f4 Mon Sep 17 00:00:00 2001 | ||
2 | From: Ray Satiro <raysatiro@yahoo.com> | ||
3 | Date: Tue, 26 Jan 2016 23:23:15 +0100 | ||
4 | Subject: [PATCH] curl: avoid local drive traversal when saving file (Windows) | ||
5 | |||
6 | curl does not sanitize colons in a remote file name that is used as the | ||
7 | local file name. This may lead to a vulnerability on systems where the | ||
8 | colon is a special path character. Currently Windows/DOS is the only OS | ||
9 | where this vulnerability applies. | ||
10 | |||
11 | CVE-2016-0754 | ||
12 | |||
13 | Bug: http://curl.haxx.se/docs/adv_20160127B.html | ||
14 | |||
15 | Upstream-Status: Backport | ||
16 | http://curl.haxx.se/CVE-2016-0754.patch | ||
17 | |||
18 | CVE: CVE-2016-0754 | ||
19 | Signed-off-by: Armin Kuster <akuster@mvista.com> | ||
20 | |||
21 | --- | ||
22 | src/tool_cb_hdr.c | 40 ++++++------ | ||
23 | src/tool_doswin.c | 174 ++++++++++++++++++++++++++++++++++++++++++++--------- | ||
24 | src/tool_doswin.h | 2 +- | ||
25 | src/tool_operate.c | 29 ++++++--- | ||
26 | 4 files changed, 187 insertions(+), 58 deletions(-) | ||
27 | |||
28 | Index: curl-7.40.0/src/tool_cb_hdr.c | ||
29 | =================================================================== | ||
30 | --- curl-7.40.0.orig/src/tool_cb_hdr.c | ||
31 | +++ curl-7.40.0/src/tool_cb_hdr.c | ||
32 | @@ -28,6 +28,7 @@ | ||
33 | #include "curlx.h" | ||
34 | |||
35 | #include "tool_cfgable.h" | ||
36 | +#include "tool_doswin.h" | ||
37 | #include "tool_msgs.h" | ||
38 | #include "tool_cb_hdr.h" | ||
39 | |||
40 | @@ -111,18 +112,24 @@ size_t tool_header_cb(void *ptr, size_t | ||
41 | */ | ||
42 | len = (ssize_t)cb - (p - str); | ||
43 | filename = parse_filename(p, len); | ||
44 | - if(filename) { | ||
45 | - outs->filename = filename; | ||
46 | - outs->alloc_filename = TRUE; | ||
47 | - outs->is_cd_filename = TRUE; | ||
48 | - outs->s_isreg = TRUE; | ||
49 | - outs->fopened = FALSE; | ||
50 | - outs->stream = NULL; | ||
51 | - hdrcbdata->honor_cd_filename = FALSE; | ||
52 | - break; | ||
53 | - } | ||
54 | - else | ||
55 | + if(!filename) | ||
56 | + return failure; | ||
57 | + | ||
58 | +#if defined(MSDOS) || defined(WIN32) | ||
59 | + if(sanitize_file_name(&filename)) { | ||
60 | + free(filename); | ||
61 | return failure; | ||
62 | + } | ||
63 | +#endif /* MSDOS || WIN32 */ | ||
64 | + | ||
65 | + outs->filename = filename; | ||
66 | + outs->alloc_filename = TRUE; | ||
67 | + outs->is_cd_filename = TRUE; | ||
68 | + outs->s_isreg = TRUE; | ||
69 | + outs->fopened = FALSE; | ||
70 | + outs->stream = NULL; | ||
71 | + hdrcbdata->honor_cd_filename = FALSE; | ||
72 | + break; | ||
73 | } | ||
74 | } | ||
75 | |||
76 | @@ -178,15 +185,12 @@ static char *parse_filename(const char * | ||
77 | } | ||
78 | |||
79 | /* scan for the end letter and stop there */ | ||
80 | - q = p; | ||
81 | - while(*q) { | ||
82 | - if(q[1] && (q[0] == '\\')) | ||
83 | - q++; | ||
84 | - else if(q[0] == stop) | ||
85 | + for(q = p; *q; ++q) { | ||
86 | + if(*q == stop) { | ||
87 | + *q = '\0'; | ||
88 | break; | ||
89 | - q++; | ||
90 | + } | ||
91 | } | ||
92 | - *q = '\0'; | ||
93 | |||
94 | /* make sure the file name doesn't end in \r or \n */ | ||
95 | q = strchr(p, '\r'); | ||
96 | Index: curl-7.40.0/src/tool_doswin.c | ||
97 | =================================================================== | ||
98 | --- curl-7.40.0.orig/src/tool_doswin.c | ||
99 | +++ curl-7.40.0/src/tool_doswin.c | ||
100 | @@ -85,42 +85,106 @@ __pragma(warning(pop)) | ||
101 | # include <fcntl.h> /* _use_lfn(f) prototype */ | ||
102 | #endif | ||
103 | |||
104 | -static const char *msdosify (const char *file_name); | ||
105 | -static char *rename_if_dos_device_name (char *file_name); | ||
106 | +static char *msdosify(const char *file_name); | ||
107 | +static char *rename_if_dos_device_name(const char *file_name); | ||
108 | |||
109 | -/* | ||
110 | - * sanitize_dos_name: returns a newly allocated string holding a | ||
111 | - * valid file name which will be a transformation of given argument | ||
112 | - * in case this wasn't already a valid file name. | ||
113 | - * | ||
114 | - * This function takes ownership of given argument, free'ing it before | ||
115 | - * returning. Caller is responsible of free'ing returned string. Upon | ||
116 | - * out of memory condition function returns NULL. | ||
117 | - */ | ||
118 | |||
119 | -char *sanitize_dos_name(char *file_name) | ||
120 | +/* | ||
121 | +Sanitize *file_name. | ||
122 | +Success: (CURLE_OK) *file_name points to a sanitized version of the original. | ||
123 | + This function takes ownership of the original *file_name and frees it. | ||
124 | +Failure: (!= CURLE_OK) *file_name is unchanged. | ||
125 | +*/ | ||
126 | +CURLcode sanitize_file_name(char **file_name) | ||
127 | { | ||
128 | - char new_name[PATH_MAX]; | ||
129 | + size_t len; | ||
130 | + char *p, *sanitized; | ||
131 | + | ||
132 | + /* Calculate the maximum length of a filename. | ||
133 | + FILENAME_MAX is often the same as PATH_MAX, in other words it does not | ||
134 | + discount the path information. PATH_MAX size is calculated based on: | ||
135 | + <drive-letter><colon><path-sep><max-filename-len><NULL> */ | ||
136 | + const size_t max_filename_len = PATH_MAX - 3 - 1; | ||
137 | + | ||
138 | + if(!file_name || !*file_name) | ||
139 | + return CURLE_BAD_FUNCTION_ARGUMENT; | ||
140 | + | ||
141 | + len = strlen(*file_name); | ||
142 | + | ||
143 | + if(len >= max_filename_len) | ||
144 | + len = max_filename_len - 1; | ||
145 | + | ||
146 | + sanitized = malloc(len + 1); | ||
147 | |||
148 | - if(!file_name) | ||
149 | - return NULL; | ||
150 | + if(!sanitized) | ||
151 | + return CURLE_OUT_OF_MEMORY; | ||
152 | |||
153 | - if(strlen(file_name) >= PATH_MAX) | ||
154 | - file_name[PATH_MAX-1] = '\0'; /* truncate it */ | ||
155 | + strncpy(sanitized, *file_name, len); | ||
156 | + sanitized[len] = '\0'; | ||
157 | |||
158 | - strcpy(new_name, msdosify(file_name)); | ||
159 | + for(p = sanitized; *p; ++p ) { | ||
160 | + const char *banned; | ||
161 | + if(1 <= *p && *p <= 31) { | ||
162 | + *p = '_'; | ||
163 | + continue; | ||
164 | + } | ||
165 | + for(banned = "|<>/\\\":?*"; *banned; ++banned) { | ||
166 | + if(*p == *banned) { | ||
167 | + *p = '_'; | ||
168 | + break; | ||
169 | + } | ||
170 | + } | ||
171 | + } | ||
172 | |||
173 | - Curl_safefree(file_name); | ||
174 | +#ifdef MSDOS | ||
175 | + /* msdosify checks for more banned characters for MSDOS, however it allows | ||
176 | + for some path information to pass through. since we are sanitizing only a | ||
177 | + filename and cannot allow a path it's important this call be done in | ||
178 | + addition to and not instead of the banned character check above. */ | ||
179 | + p = msdosify(sanitized); | ||
180 | + if(!p) { | ||
181 | + free(sanitized); | ||
182 | + return CURLE_BAD_FUNCTION_ARGUMENT; | ||
183 | + } | ||
184 | + sanitized = p; | ||
185 | + len = strlen(sanitized); | ||
186 | +#endif | ||
187 | + | ||
188 | + p = rename_if_dos_device_name(sanitized); | ||
189 | + if(!p) { | ||
190 | + free(sanitized); | ||
191 | + return CURLE_BAD_FUNCTION_ARGUMENT; | ||
192 | + } | ||
193 | + sanitized = p; | ||
194 | + len = strlen(sanitized); | ||
195 | |||
196 | - return strdup(rename_if_dos_device_name(new_name)); | ||
197 | + /* dos_device_name rename will rename a device name, possibly changing the | ||
198 | + length. If the length is too long now we can't truncate it because we | ||
199 | + could end up with a device name. In practice this shouldn't be a problem | ||
200 | + because device names are short, but you never know. */ | ||
201 | + if(len >= max_filename_len) { | ||
202 | + free(sanitized); | ||
203 | + return CURLE_BAD_FUNCTION_ARGUMENT; | ||
204 | + } | ||
205 | + | ||
206 | + *file_name = sanitized; | ||
207 | + return CURLE_OK; | ||
208 | } | ||
209 | |||
210 | -/* The following functions are taken with modification from the DJGPP | ||
211 | - * port of tar 1.12. They use algorithms originally from DJTAR. */ | ||
212 | +/* The functions msdosify, rename_if_dos_device_name and __crt0_glob_function | ||
213 | + * were taken with modification from the DJGPP port of tar 1.12. They use | ||
214 | + * algorithms originally from DJTAR. | ||
215 | + */ | ||
216 | |||
217 | -static const char *msdosify (const char *file_name) | ||
218 | +/* | ||
219 | +Extra sanitization MSDOS for file_name. | ||
220 | +Returns a copy of file_name that is sanitized by MSDOS standards. | ||
221 | +Warning: path information may pass through. For sanitizing a filename use | ||
222 | +sanitize_file_name which calls this function after sanitizing path info. | ||
223 | +*/ | ||
224 | +static char *msdosify(const char *file_name) | ||
225 | { | ||
226 | - static char dos_name[PATH_MAX]; | ||
227 | + char dos_name[PATH_MAX]; | ||
228 | static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */ | ||
229 | "|<>\\\":?*"; /* illegal in DOS & W95 */ | ||
230 | static const char *illegal_chars_w95 = &illegal_chars_dos[8]; | ||
231 | @@ -201,15 +265,20 @@ static const char *msdosify (const char | ||
232 | } | ||
233 | |||
234 | *d = '\0'; | ||
235 | - return dos_name; | ||
236 | + return strdup(dos_name); | ||
237 | } | ||
238 | |||
239 | -static char *rename_if_dos_device_name (char *file_name) | ||
240 | +/* | ||
241 | +Rename file_name if it's a representation of a device name. | ||
242 | +Returns a copy of file_name, and the copy will have contents different from the | ||
243 | +original if a device name was found. | ||
244 | +*/ | ||
245 | +static char *rename_if_dos_device_name(const char *file_name) | ||
246 | { | ||
247 | /* We could have a file whose name is a device on MS-DOS. Trying to | ||
248 | * retrieve such a file would fail at best and wedge us at worst. We need | ||
249 | * to rename such files. */ | ||
250 | - char *base; | ||
251 | + char *p, *base; | ||
252 | struct_stat st_buf; | ||
253 | char fname[PATH_MAX]; | ||
254 | |||
255 | @@ -219,7 +288,7 @@ static char *rename_if_dos_device_name ( | ||
256 | if(((stat(base, &st_buf)) == 0) && (S_ISCHR(st_buf.st_mode))) { | ||
257 | size_t blen = strlen(base); | ||
258 | |||
259 | - if(strlen(fname) >= PATH_MAX-1) { | ||
260 | + if(strlen(fname) == PATH_MAX-1) { | ||
261 | /* Make room for the '_' */ | ||
262 | blen--; | ||
263 | base[blen] = '\0'; | ||
264 | @@ -227,9 +296,54 @@ static char *rename_if_dos_device_name ( | ||
265 | /* Prepend a '_'. */ | ||
266 | memmove(base + 1, base, blen + 1); | ||
267 | base[0] = '_'; | ||
268 | - strcpy(file_name, fname); | ||
269 | } | ||
270 | - return file_name; | ||
271 | + | ||
272 | + /* The above stat check does not identify devices for me in Windows 7. For | ||
273 | + example a stat on COM1 returns a regular file S_IFREG. According to MSDN | ||
274 | + stat doc that is the correct behavior, so I assume the above code is | ||
275 | + legacy, maybe MSDOS or DJGPP specific? */ | ||
276 | + | ||
277 | + /* Rename devices. | ||
278 | + Examples: CON => _CON, CON.EXT => CON_EXT, CON:ADS => CON_ADS */ | ||
279 | + for(p = fname; p; p = (p == fname && fname != base ? base : NULL)) { | ||
280 | + size_t p_len; | ||
281 | + int x = (curl_strnequal(p, "CON", 3) || | ||
282 | + curl_strnequal(p, "PRN", 3) || | ||
283 | + curl_strnequal(p, "AUX", 3) || | ||
284 | + curl_strnequal(p, "NUL", 3)) ? 3 : | ||
285 | + (curl_strnequal(p, "CLOCK$", 6)) ? 6 : | ||
286 | + (curl_strnequal(p, "COM", 3) || curl_strnequal(p, "LPT", 3)) ? | ||
287 | + (('1' <= p[3] && p[3] <= '9') ? 4 : 3) : 0; | ||
288 | + | ||
289 | + if(!x) | ||
290 | + continue; | ||
291 | + | ||
292 | + /* the devices may be accessible with an extension or ADS, for | ||
293 | + example CON.AIR and CON:AIR both access console */ | ||
294 | + if(p[x] == '.' || p[x] == ':') { | ||
295 | + p[x] = '_'; | ||
296 | + continue; | ||
297 | + } | ||
298 | + else if(p[x]) /* no match */ | ||
299 | + continue; | ||
300 | + | ||
301 | + p_len = strlen(p); | ||
302 | + | ||
303 | + if(strlen(fname) == PATH_MAX-1) { | ||
304 | + /* Make room for the '_' */ | ||
305 | + p_len--; | ||
306 | + p[p_len] = '\0'; | ||
307 | + } | ||
308 | + /* Prepend a '_'. */ | ||
309 | + memmove(p + 1, p, p_len + 1); | ||
310 | + p[0] = '_'; | ||
311 | + | ||
312 | + /* if fname was just modified then the basename pointer must be updated */ | ||
313 | + if(p == fname) | ||
314 | + base = basename(fname); | ||
315 | + } | ||
316 | + | ||
317 | + return strdup(fname); | ||
318 | } | ||
319 | |||
320 | #if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) | ||
321 | Index: curl-7.40.0/src/tool_doswin.h | ||
322 | =================================================================== | ||
323 | --- curl-7.40.0.orig/src/tool_doswin.h | ||
324 | +++ curl-7.40.0/src/tool_doswin.h | ||
325 | @@ -25,7 +25,7 @@ | ||
326 | |||
327 | #if defined(MSDOS) || defined(WIN32) | ||
328 | |||
329 | -char *sanitize_dos_name(char *file_name); | ||
330 | +CURLcode sanitize_file_name(char **filename); | ||
331 | |||
332 | #if defined(MSDOS) && (defined(__DJGPP__) || defined(__GO32__)) | ||
333 | |||
334 | Index: curl-7.40.0/src/tool_operate.c | ||
335 | =================================================================== | ||
336 | --- curl-7.40.0.orig/src/tool_operate.c | ||
337 | +++ curl-7.40.0/src/tool_operate.c | ||
338 | @@ -543,26 +543,37 @@ static CURLcode operate_do(struct Global | ||
339 | result = get_url_file_name(&outfile, this_url); | ||
340 | if(result) | ||
341 | goto show_error; | ||
342 | + | ||
343 | +#if defined(MSDOS) || defined(WIN32) | ||
344 | + result = sanitize_file_name(&outfile); | ||
345 | + if(result) { | ||
346 | + Curl_safefree(outfile); | ||
347 | + goto show_error; | ||
348 | + } | ||
349 | +#endif /* MSDOS || WIN32 */ | ||
350 | + | ||
351 | if(!*outfile && !config->content_disposition) { | ||
352 | helpf(global->errors, "Remote file name has no length!\n"); | ||
353 | result = CURLE_WRITE_ERROR; | ||
354 | goto quit_urls; | ||
355 | } | ||
356 | -#if defined(MSDOS) || defined(WIN32) | ||
357 | - /* For DOS and WIN32, we do some major replacing of | ||
358 | - bad characters in the file name before using it */ | ||
359 | - outfile = sanitize_dos_name(outfile); | ||
360 | - if(!outfile) { | ||
361 | - result = CURLE_OUT_OF_MEMORY; | ||
362 | - goto show_error; | ||
363 | - } | ||
364 | -#endif /* MSDOS || WIN32 */ | ||
365 | } | ||
366 | else if(urls) { | ||
367 | /* fill '#1' ... '#9' terms from URL pattern */ | ||
368 | char *storefile = outfile; | ||
369 | result = glob_match_url(&outfile, storefile, urls); | ||
370 | Curl_safefree(storefile); | ||
371 | + | ||
372 | +#if defined(MSDOS) || defined(WIN32) | ||
373 | + if(!result) { | ||
374 | + result = sanitize_file_name(&outfile); | ||
375 | + if(result) { | ||
376 | + Curl_safefree(outfile); | ||
377 | + goto show_error; | ||
378 | + } | ||
379 | + } | ||
380 | +#endif /* MSDOS || WIN32 */ | ||
381 | + | ||
382 | if(result) { | ||
383 | /* bad globbing */ | ||
384 | warnf(config, "bad output glob!\n"); | ||
diff --git a/meta/recipes-support/curl/curl_7.40.0.bb b/meta/recipes-support/curl/curl_7.40.0.bb index e6a6a42ea1..01c201e18a 100644 --- a/meta/recipes-support/curl/curl_7.40.0.bb +++ b/meta/recipes-support/curl/curl_7.40.0.bb | |||
@@ -16,7 +16,8 @@ SRC_URI = "http://curl.haxx.se/download/curl-${PV}.tar.bz2 \ | |||
16 | # curl likes to set -g0 in CFLAGS, so we stop it | 16 | # curl likes to set -g0 in CFLAGS, so we stop it |
17 | # from mucking around with debug options | 17 | # from mucking around with debug options |
18 | # | 18 | # |
19 | SRC_URI += " file://configure_ac.patch" | 19 | SRC_URI += " file://configure_ac.patch \ |
20 | file://CVE-2016-0754.patch" | ||
20 | 21 | ||
21 | SRC_URI[md5sum] = "8d30594212e65657a5c32030f0998fa9" | 22 | SRC_URI[md5sum] = "8d30594212e65657a5c32030f0998fa9" |
22 | SRC_URI[sha256sum] = "899109eb3900fa6b8a2f995df7f449964292776a04763e94fae640700f883fba" | 23 | SRC_URI[sha256sum] = "899109eb3900fa6b8a2f995df7f449964292776a04763e94fae640700f883fba" |