aboutsummaryrefslogtreecommitdiff
path: root/arch
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.c7
-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, 56 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 b7944a62a..42b4baf88 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 f0d990048..b033b3733 100644
--- a/archival/cpio.c
+++ b/archival/cpio.c
@@ -350,6 +350,12 @@ static NOINLINE int cpio_o(void)
350 st.st_dev = st.st_rdev = 0; 350 st.st_dev = st.st_rdev = 0;
351#endif 351#endif
352 352
353 if (sizeof(st.st_size) > 4
354 && st.st_size > (off_t)0xffffffff
355 ) {
356 bb_error_msg_and_die("error: file '%s' is larger than 4GB", name);
357 }
358
353 bytes += printf("070701" 359 bytes += printf("070701"
354 "%08X%08X%08X%08X%08X%08X%08X" 360 "%08X%08X%08X%08X%08X%08X%08X"
355 "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */ 361 "%08X%08X%08X%08X" /* GNU cpio uses uppercase hex */
@@ -421,6 +427,7 @@ int cpio_main(int argc UNUSED_PARAM, char **argv)
421#endif 427#endif
422#endif 428#endif
423 "owner\0" Required_argument "R" 429 "owner\0" Required_argument "R"
430 "file\0" Required_argument "F"
424 "verbose\0" No_argument "v" 431 "verbose\0" No_argument "v"
425 "null\0" No_argument "0" 432 "null\0" No_argument "0"
426 "quiet\0" No_argument "\xff" 433 "quiet\0" No_argument "\xff"
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 44715ef25..353f68217 100644
--- a/archival/libarchive/open_transformer.c
+++ b/archival/libarchive/open_transformer.c
@@ -157,7 +157,7 @@ void FAST_FUNC fork_transformer(int fd, const char *transform_prog)
157/* Used by e.g. rpm which gives us a fd without filename, 157/* Used by e.g. rpm which gives us a fd without filename,
158 * thus we can't guess the format from filename's extension. 158 * thus we can't guess the format from filename's extension.
159 */ 159 */
160static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_compressed) 160static transformer_state_t *setup_transformer_on_fd(int fd, int die_if_not_compressed)
161{ 161{
162 transformer_state_t *xstate; 162 transformer_state_t *xstate;
163 163
@@ -204,7 +204,7 @@ static transformer_state_t *setup_transformer_on_fd(int fd, int fail_if_not_comp
204 } 204 }
205 205
206 /* No known magic seen */ 206 /* No known magic seen */
207 if (fail_if_not_compressed) 207 if (die_if_not_compressed)
208 bb_simple_error_msg_and_die("no gzip" 208 bb_simple_error_msg_and_die("no gzip"
209 IF_FEATURE_SEAMLESS_BZ2("/bzip2") 209 IF_FEATURE_SEAMLESS_BZ2("/bzip2")
210 IF_FEATURE_SEAMLESS_XZ("/xz") 210 IF_FEATURE_SEAMLESS_XZ("/xz")
@@ -240,13 +240,15 @@ static void fork_transformer_and_free(transformer_state_t *xstate)
240/* Used by e.g. rpm which gives us a fd without filename, 240/* Used by e.g. rpm which gives us a fd without filename,
241 * thus we can't guess the format from filename's extension. 241 * thus we can't guess the format from filename's extension.
242 */ 242 */
243int FAST_FUNC setup_unzip_on_fd(int fd, int fail_if_not_compressed) 243int FAST_FUNC setup_unzip_on_fd(int fd, int die_if_not_compressed)
244{ 244{
245 transformer_state_t *xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); 245 transformer_state_t *xstate = setup_transformer_on_fd(fd, die_if_not_compressed);
246 246
247 if (!xstate->xformer) { 247 if (!xstate->xformer) {
248 /* Not compressed */
249 int retval = xstate->signature_skipped; /* never zero */
248 free(xstate); 250 free(xstate);
249 return 1; 251 return retval;
250 } 252 }
251 253
252 fork_transformer_and_free(xstate); 254 fork_transformer_and_free(xstate);
@@ -264,7 +266,7 @@ void FAST_FUNC setup_lzma_on_fd(int fd)
264} 266}
265#endif 267#endif
266 268
267static transformer_state_t *open_transformer(const char *fname, int fail_if_not_compressed) 269static transformer_state_t *open_transformer(const char *fname, int die_if_not_compressed)
268{ 270{
269 transformer_state_t *xstate; 271 transformer_state_t *xstate;
270 int fd; 272 int fd;
@@ -284,18 +286,18 @@ static transformer_state_t *open_transformer(const char *fname, int fail_if_not_
284 } 286 }
285 } 287 }
286 288
287 xstate = setup_transformer_on_fd(fd, fail_if_not_compressed); 289 xstate = setup_transformer_on_fd(fd, die_if_not_compressed);
288 290
289 return xstate; 291 return xstate;
290} 292}
291 293
292int FAST_FUNC open_zipped(const char *fname, int fail_if_not_compressed) 294int FAST_FUNC open_zipped(const char *fname, int die_if_not_compressed)
293{ 295{
294 int fd; 296 int fd;
295 transformer_state_t *xstate; 297 transformer_state_t *xstate;
296 298
297 xstate = open_transformer(fname, fail_if_not_compressed); 299 xstate = open_transformer(fname, die_if_not_compressed);
298 if (!xstate) 300 if (!xstate) /* open error */
299 return -1; 301 return -1;
300 302
301 fd = xstate->src_fd; 303 fd = xstate->src_fd;
@@ -326,7 +328,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_
326 transformer_state_t *xstate; 328 transformer_state_t *xstate;
327 char *image; 329 char *image;
328 330
329 xstate = open_transformer(fname, /*fail_if_not_compressed:*/ 0); 331 xstate = open_transformer(fname, /*die_if_not_compressed:*/ 0);
330 if (!xstate) /* file open error */ 332 if (!xstate) /* file open error */
331 return NULL; 333 return NULL;
332 334
@@ -371,7 +373,7 @@ void* FAST_FUNC xmalloc_open_zipped_read_close(const char *fname, size_t *maxsz_
371 int fd; 373 int fd;
372 char *image; 374 char *image;
373 375
374 fd = open_zipped(fname, /*fail_if_not_compressed:*/ 0); 376 fd = open_zipped(fname, /*die_if_not_compressed:*/ 0);
375 if (fd < 0) 377 if (fd < 0)
376 return NULL; 378 return NULL;
377 379
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 af8db99a6..95a8c79b6 100644
--- a/archival/rpm.c
+++ b/archival/rpm.c
@@ -316,7 +316,7 @@ static void extract_cpio(int fd, const char *source_rpm)
316 archive_handle->src_fd = fd; 316 archive_handle->src_fd = fd;
317 /*archive_handle->offset = 0; - init_handle() did it */ 317 /*archive_handle->offset = 0; - init_handle() did it */
318 318
319 setup_unzip_on_fd(archive_handle->src_fd, /*fail_if_not_compressed:*/ 1); 319 setup_unzip_on_fd(archive_handle->src_fd, /*die_if_not_compressed:*/ 1);
320 while (get_header_cpio(archive_handle) == EXIT_SUCCESS) 320 while (get_header_cpio(archive_handle) == EXIT_SUCCESS)
321 continue; 321 continue;
322} 322}
@@ -533,6 +533,7 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
533 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */ 533 // /* We need to know whether child (gzip/bzip/etc) exits abnormally */
534 // signal(SIGCHLD, check_errors_in_children); 534 // signal(SIGCHLD, check_errors_in_children);
535 535
536 str = NULL;
536 if (ENABLE_FEATURE_SEAMLESS_LZMA 537 if (ENABLE_FEATURE_SEAMLESS_LZMA
537 && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL 538 && (str = rpm_getstr0(TAG_PAYLOADCOMPRESSOR)) != NULL
538 && strcmp(str, "lzma") == 0 539 && strcmp(str, "lzma") == 0
@@ -541,7 +542,11 @@ int rpm2cpio_main(int argc UNUSED_PARAM, char **argv)
541 // set up decompressor without detection 542 // set up decompressor without detection
542 setup_lzma_on_fd(rpm_fd); 543 setup_lzma_on_fd(rpm_fd);
543 } else { 544 } else {
544 setup_unzip_on_fd(rpm_fd, /*fail_if_not_compressed:*/ 1); 545 int signature_bytes = setup_unzip_on_fd(rpm_fd, /*die_if_not_compressed:*/ 0);
546 if (signature_bytes != 0) {
547 xlseek(rpm_fd, - signature_bytes, SEEK_CUR);
548 bb_error_msg("warning, unknown compression '%s'", str);
549 }
545 } 550 }
546 551
547 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0) 552 if (bb_copyfd_eof(rpm_fd, STDOUT_FILENO) < 0)
diff --git a/archival/tar.c b/archival/tar.c
index d6ca6c1e0..38906ba02 100644
--- a/archival/tar.c
+++ b/archival/tar.c
@@ -1164,7 +1164,7 @@ int tar_main(int argc UNUSED_PARAM, char **argv)
1164 * on e.g. tarball with 1st file named "BZh5". 1164 * on e.g. tarball with 1st file named "BZh5".
1165 */ 1165 */
1166 ) { 1166 ) {
1167 tar_handle->src_fd = open_zipped(tar_filename, /*fail_if_not_compressed:*/ 0); 1167 tar_handle->src_fd = open_zipped(tar_filename, /*die_if_not_compressed:*/ 0);
1168 if (tar_handle->src_fd < 0) 1168 if (tar_handle->src_fd < 0)
1169 bb_perror_msg_and_die("can't open '%s'", tar_filename); 1169 bb_perror_msg_and_die("can't open '%s'", tar_filename);
1170 } else { 1170 } else {