aboutsummaryrefslogtreecommitdiff
path: root/archival
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--archival/Config.src11
-rw-r--r--archival/bbunzip.c6
-rw-r--r--archival/cpio.c6
-rw-r--r--archival/libarchive/data_extract_all.c8
-rw-r--r--archival/libarchive/open_transformer.c26
-rw-r--r--archival/libarchive/unsafe_prefix.c6
-rw-r--r--archival/rpm.c9
-rw-r--r--archival/tar.c2
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
38config 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
38endmenu 49endmenu
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 */
167static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed) 167static 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 */
250int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) 250int 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
274static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) 276static 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
299int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) 301int 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 {