diff options
Diffstat (limited to '')
-rw-r--r-- | archival/Config.src | 11 | ||||
-rw-r--r-- | archival/bbunzip.c | 6 | ||||
-rw-r--r-- | archival/cpio.c | 6 | ||||
-rw-r--r-- | archival/libarchive/data_extract_all.c | 8 | ||||
-rw-r--r-- | archival/libarchive/open_transformer.c | 26 | ||||
-rw-r--r-- | archival/libarchive/unsafe_prefix.c | 6 | ||||
-rw-r--r-- | archival/rpm.c | 9 | ||||
-rw-r--r-- | archival/tar.c | 2 |
8 files changed, 55 insertions, 19 deletions
diff --git a/archival/Config.src b/archival/Config.src index 6f4f30c43..cbcd7217c 100644 --- a/archival/Config.src +++ b/archival/Config.src | |||
@@ -35,4 +35,15 @@ config FEATURE_LZMA_FAST | |||
35 | This option reduces decompression time by about 25% at the cost of | 35 | This option reduces decompression time by about 25% at the cost of |
36 | a 1K bigger binary. | 36 | a 1K bigger binary. |
37 | 37 | ||
38 | config FEATURE_PATH_TRAVERSAL_PROTECTION | ||
39 | bool "Prevent extraction of filenames with /../ path component" | ||
40 | default n | ||
41 | help | ||
42 | busybox tar and unzip remove "PREFIX/../" (if it exists) | ||
43 | from extracted names. | ||
44 | This option enables this behavior for all other unpacking applets, | ||
45 | such as cpio, ar, rpm. | ||
46 | GNU cpio 2.15 has NO such sanity check. | ||
47 | # try other archivers and document their behavior? | ||
48 | |||
38 | endmenu | 49 | endmenu |
diff --git a/archival/bbunzip.c b/archival/bbunzip.c index fb5deb0ce..1f1f28b61 100644 --- a/archival/bbunzip.c +++ b/archival/bbunzip.c | |||
@@ -71,8 +71,8 @@ int FAST_FUNC bbunpack(char **argv, | |||
71 | goto err; | 71 | goto err; |
72 | } else { | 72 | } else { |
73 | /* "clever zcat" with FILE */ | 73 | /* "clever zcat" with FILE */ |
74 | /* fail_if_not_compressed because zcat refuses uncompressed input */ | 74 | /* die_if_not_compressed because zcat refuses uncompressed input */ |
75 | int fd = open_zipped(filename, /*fail_if_not_compressed:*/ 1); | 75 | int fd = open_zipped(filename, /*die_if_not_compressed:*/ 1); |
76 | if (fd < 0) | 76 | if (fd < 0) |
77 | goto err_name; | 77 | goto err_name; |
78 | xmove_fd(fd, STDIN_FILENO); | 78 | xmove_fd(fd, STDIN_FILENO); |
@@ -80,7 +80,7 @@ int FAST_FUNC bbunpack(char **argv, | |||
80 | } else | 80 | } else |
81 | if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) { | 81 | if (option_mask32 & BBUNPK_SEAMLESS_MAGIC) { |
82 | /* "clever zcat" on stdin */ | 82 | /* "clever zcat" on stdin */ |
83 | if (setup_unzip_on_fd(STDIN_FILENO, /*fail_if_not_compressed*/ 1)) | 83 | if (setup_unzip_on_fd(STDIN_FILENO, /*die_if_not_compressed*/ 1)) |
84 | goto err; | 84 | goto err; |
85 | } | 85 | } |
86 | 86 | ||
diff --git a/archival/cpio.c b/archival/cpio.c index 167931bdb..933d520c2 100644 --- a/archival/cpio.c +++ b/archival/cpio.c | |||
@@ -354,6 +354,12 @@ static NOINLINE int cpio_o(void) | |||
354 | #endif | 354 | #endif |
355 | #endif | 355 | #endif |
356 | 356 | ||
357 | if (sizeof(st.st_size) > 4 | ||
358 | && st.st_size > (off_t)0xffffffff | ||
359 | ) { | ||
360 | bb_error_msg_and_die("error: file '%s' is larger than 4GB", name); | ||
361 | } | ||
362 | |||
357 | bytes += printf("070701" | 363 | bytes += printf("070701" |
358 | "%08X%08X%08X%08X%08X%08X%08X" | 364 | "%08X%08X%08X%08X%08X%08X%08X" |
359 | "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ | 365 | "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ |
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index 049c2c156..8a69711c1 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c | |||
@@ -65,6 +65,14 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) | |||
65 | } while (--n != 0); | 65 | } while (--n != 0); |
66 | } | 66 | } |
67 | #endif | 67 | #endif |
68 | #if ENABLE_FEATURE_PATH_TRAVERSAL_PROTECTION | ||
69 | /* Strip leading "/" and up to last "/../" path component */ | ||
70 | dst_name = (char *)strip_unsafe_prefix(dst_name); | ||
71 | #endif | ||
72 | // ^^^ This may be a problem if some applets do need to extract absolute names. | ||
73 | // (Probably will need to invent ARCHIVE_ALLOW_UNSAFE_NAME flag). | ||
74 | // You might think that rpm needs it, but in my tests rpm's internal cpio | ||
75 | // archive has names like "./usr/bin/FOO", not "/usr/bin/FOO". | ||
68 | 76 | ||
69 | if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { | 77 | if (archive_handle->ah_flags & ARCHIVE_CREATE_LEADING_DIRS) { |
70 | char *slash = strrchr(dst_name, '/'); | 78 | char *slash = strrchr(dst_name, '/'); |
diff --git a/archival/libarchive/open_transformer.c b/archival/libarchive/open_transformer.c index 3d202ad26..a949c4509 100644 --- a/archival/libarchive/open_transformer.c +++ b/archival/libarchive/open_transformer.c | |||
@@ -164,7 +164,7 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog) | |||
164 | /* Used by e.g. rpm which gives us a fd without filename, | 164 | /* Used by e.g. rpm which gives us a fd without filename, |
165 | * thus we can't guess the format from filename's extension. | 165 | * thus we can't guess the format from filename's extension. |
166 | */ | 166 | */ |
167 | static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed) | 167 | static transformer_state_t *setup_transformer_on_fd(int fd, int die_if_not_compressed) |
168 | { | 168 | { |
169 | transformer_state_t *xstate; | 169 | transformer_state_t *xstate; |
170 | 170 | ||
@@ -211,7 +211,7 @@ static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_comp | |||
211 | } | 211 | } |
212 | 212 | ||
213 | /* No known magic seen */ | 213 | /* No known magic seen */ |
214 | if (fail_if_not_compressed) | 214 | if (die_if_not_compressed) |
215 | bb_simple_error_msg_and_die("no gzip" | 215 | bb_simple_error_msg_and_die("no gzip" |
216 | IF_FEATURE_SEAMLESS_BZ2("/bzip2") | 216 | IF_FEATURE_SEAMLESS_BZ2("/bzip2") |
217 | IF_FEATURE_SEAMLESS_XZ("/xz") | 217 | IF_FEATURE_SEAMLESS_XZ("/xz") |
@@ -247,13 +247,15 @@ static void fork_transformer_and_free(transformer_state_t *xstate) | |||
247 | /* Used by e.g. rpm which gives us a fd without filename, | 247 | /* Used by e.g. rpm which gives us a fd without filename, |
248 | * thus we can't guess the format from filename's extension. | 248 | * thus we can't guess the format from filename's extension. |
249 | */ | 249 | */ |
250 | int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) | 250 | int FAST_FUNC setup_unzip_on_fd(int fd, int die_if_not_compressed) |
251 | { | 251 | { |
252 | transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); | 252 | transformer_state_t *xstate = setup_transformer_on_fd(fd, die_if_not_compressed); |
253 | 253 | ||
254 | if (!xstate->xformer) { | 254 | if (!xstate->xformer) { |
255 | /* Not compressed */ | ||
256 | int retval = xstate->signature_skipped; /* never zero */ | ||
255 | free(xstate); | 257 | free(xstate); |
256 | return 1; | 258 | return retval; |
257 | } | 259 | } |
258 | 260 | ||
259 | fork_transformer_and_free(xstate); | 261 | fork_transformer_and_free(xstate); |
@@ -271,7 +273,7 @@ void FAST_FUNC setup_lzma_on_fd(int fd) | |||
271 | } | 273 | } |
272 | #endif | 274 | #endif |
273 | 275 | ||
274 | static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) | 276 | static transformer_state_t *open_transformer(const char *fname, int die_if_not_compressed) |
275 | { | 277 | { |
276 | transformer_state_t *xstate; | 278 | transformer_state_t *xstate; |
277 | int fd; | 279 | int fd; |
@@ -291,18 +293,18 @@ static transformer_state_t *open_transformer(const char *fname, int fail_if_not_ | |||
291 | } | 293 | } |
292 | } | 294 | } |
293 | 295 | ||
294 | xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); | 296 | xstate = setup_transformer_on_fd(fd, die_if_not_compressed); |
295 | 297 | ||
296 | return xstate; | 298 | return xstate; |
297 | } | 299 | } |
298 | 300 | ||
299 | int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) | 301 | int FAST_FUNC open_zipped(const char *fname, int die_if_not_compressed) |
300 | { | 302 | { |
301 | int fd; | 303 | int fd; |
302 | transformer_state_t *xstate; | 304 | transformer_state_t *xstate; |
303 | 305 | ||
304 | xstate = open_transformer(fname, fail_if_not_compressed); | 306 | xstate = open_transformer(fname, die_if_not_compressed); |
305 | if (!xstate) | 307 | if (!xstate) /* open error */ |
306 | return -1; | 308 | return -1; |
307 | 309 | ||
308 | fd = xstate->src_fd; | 310 | fd = xstate->src_fd; |
@@ -333,7 +335,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_ | |||
333 | transformer_state_t *xstate; | 335 | transformer_state_t *xstate; |
334 | char *image; | 336 | char *image; |
335 | 337 | ||
336 | xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0); | 338 | xstate = open_transformer(fname, /*die_if_not_compressed:*/ 0); |
337 | if (!xstate) /* file open error */ | 339 | if (!xstate) /* file open error */ |
338 | return NULL; | 340 | return NULL; |
339 | 341 | ||
@@ -378,7 +380,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_ | |||
378 | int fd; | 380 | int fd; |
379 | char *image; | 381 | char *image; |
380 | 382 | ||
381 | fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0); | 383 | fd = open_zipped(fname, /*die_if_not_compressed:*/ 0); |
382 | if (fd < 0) | 384 | if (fd < 0) |
383 | return NULL; | 385 | return NULL; |
384 | 386 | ||
diff --git a/archival/libarchive/unsafe_prefix.c b/archival/libarchive/unsafe_prefix.c index 33e487bf9..667081195 100644 --- a/archival/libarchive/unsafe_prefix.c +++ b/archival/libarchive/unsafe_prefix.c | |||
@@ -14,7 +14,11 @@ const char* FAST_FUNC strip_unsafe_prefix(const char *str) | |||
14 | cp++; | 14 | cp++; |
15 | continue; | 15 | continue; |
16 | } | 16 | } |
17 | if (is_prefixed_with(cp, "/../"+1)) { | 17 | /* We are called lots of times. |
18 | * is_prefixed_with(cp, "../") is slower than open-coding it, | ||
19 | * with minimal code growth (~few bytes). | ||
20 | */ | ||
21 | if (cp[0] == '.' && cp[1] == '.' && cp[2] == '/') { | ||
18 | cp += 3; | 22 | cp += 3; |
19 | continue; | 23 | continue; |
20 | } | 24 | } |
diff --git a/archival/rpm.c b/archival/rpm.c index d83c33137..c2f0550ff 100644 --- a/archival/rpm.c +++ b/archival/rpm.c | |||
@@ -330,7 +330,7 @@ static void extract_cpio(int fd, const char *source_rpm) | |||
330 | archive_handle->src_fd = fd; | 330 | archive_handle->src_fd = fd; |
331 | /*archive_handle->offset = 0; - init_handle() did it */ | 331 | /*archive_handle->offset = 0; - init_handle() did it */ |
332 | 332 | ||
333 | setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1); | 333 | setup_unzip_on_fd(archive_handle->src_fd, /*die_if_not_compressed:*/ 1); |
334 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) | 334 | while (get_header_cpio(archive_handle) == EXIT_SUCCESS) |
335 | continue; | 335 | continue; |
336 | } | 336 | } |
@@ -549,6 +549,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | |||
549 | // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ | 549 | // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ |
550 | // signal(SIGCHLD, check_errors_in_children); | 550 | // signal(SIGCHLD, check_errors_in_children); |
551 | 551 | ||
552 | str = NULL; | ||
552 | if (ENABLE_FEATURE_SEAMLESS_LZMA | 553 | if (ENABLE_FEATURE_SEAMLESS_LZMA |
553 | && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL | 554 | && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL |
554 | && strcmp(str, "lzma") == 0 | 555 | && strcmp(str, "lzma") == 0 |
@@ -557,7 +558,11 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv) | |||
557 | // set up decompressor without detection | 558 | // set up decompressor without detection |
558 | setup_lzma_on_fd(rpm_fd); | 559 | setup_lzma_on_fd(rpm_fd); |
559 | } else { | 560 | } else { |
560 | setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); | 561 | int signature_bytes = setup_unzip_on_fd(rpm_fd, /*die_if_not_compressed:*/ 0); |
562 | if (signature_bytes != 0) { | ||
563 | xlseek(rpm_fd, - signature_bytes, SEEK_CUR); | ||
564 | bb_error_msg("warning, unknown compression '%s'", str); | ||
565 | } | ||
561 | } | 566 | } |
562 | 567 | ||
563 | if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) | 568 | if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) |
diff --git a/archival/tar.c b/archival/tar.c index 23ea02b5d..fd20d6ce7 100644 --- a/archival/tar.c +++ b/archival/tar.c | |||
@@ -1188,7 +1188,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv) | |||
1188 | * on e.g. tarball with 1st file named "BZh5". | 1188 | * on e.g. tarball with 1st file named "BZh5". |
1189 | */ | 1189 | */ |
1190 | ) { | 1190 | ) { |
1191 | tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); | 1191 | tar_handle->src_fd = open_zipped(tar_filename, /*die_if_not_compressed:*/ 0); |
1192 | if (tar_handle->src_fd < 0) | 1192 | if (tar_handle->src_fd < 0) |
1193 | bb_perror_msg_and_die("can't open '%s'", tar_filename); | 1193 | bb_perror_msg_and_die("can't open '%s'", tar_filename); |
1194 | } else { | 1194 | } else { |