aboutsummaryrefslogtreecommitdiff
path: root/archival
diff options
context:
space:
mode:
Diffstat (limited to 'archival')
-rw-r--r--archival/dpkg.c11
-rw-r--r--archival/dpkg_deb.c6
-rw-r--r--archival/gzip.c61
-rw-r--r--archival/libarchive/Kbuild.src6
-rw-r--r--archival/libarchive/filter_accept_list_reassign.c10
-rw-r--r--archival/libarchive/get_header_cpio.c2
-rw-r--r--archival/libarchive/get_header_tar.c36
-rw-r--r--archival/libarchive/get_header_tar_xz.c21
-rw-r--r--archival/libarchive/unpack_ar_archive.c2
-rw-r--r--archival/libarchive/unsafe_prefix.c36
-rw-r--r--archival/unzip.c35
11 files changed, 167 insertions, 59 deletions
diff --git a/archival/dpkg.c b/archival/dpkg.c
index 2893cfc2d..151f0ca43 100644
--- a/archival/dpkg.c
+++ b/archival/dpkg.c
@@ -1472,12 +1472,16 @@ static void init_archive_deb_control(archive_handle_t *ar_handle)
1472 tar_handle->src_fd = ar_handle->src_fd; 1472 tar_handle->src_fd = ar_handle->src_fd;
1473 1473
1474 /* We don't care about data.tar.* or debian-binary, just control.tar.* */ 1474 /* We don't care about data.tar.* or debian-binary, just control.tar.* */
1475 llist_add_to(&(ar_handle->accept), (char*)"control.tar");
1475#if ENABLE_FEATURE_SEAMLESS_GZ 1476#if ENABLE_FEATURE_SEAMLESS_GZ
1476 llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz"); 1477 llist_add_to(&(ar_handle->accept), (char*)"control.tar.gz");
1477#endif 1478#endif
1478#if ENABLE_FEATURE_SEAMLESS_BZ2 1479#if ENABLE_FEATURE_SEAMLESS_BZ2
1479 llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2"); 1480 llist_add_to(&(ar_handle->accept), (char*)"control.tar.bz2");
1480#endif 1481#endif
1482#if ENABLE_FEATURE_SEAMLESS_XZ
1483 llist_add_to(&(ar_handle->accept), (char*)"control.tar.xz");
1484#endif
1481 1485
1482 /* Assign the tar handle as a subarchive of the ar handle */ 1486 /* Assign the tar handle as a subarchive of the ar handle */
1483 ar_handle->dpkg__sub_archive = tar_handle; 1487 ar_handle->dpkg__sub_archive = tar_handle;
@@ -1492,12 +1496,19 @@ static void init_archive_deb_data(archive_handle_t *ar_handle)
1492 tar_handle->src_fd = ar_handle->src_fd; 1496 tar_handle->src_fd = ar_handle->src_fd;
1493 1497
1494 /* We don't care about control.tar.* or debian-binary, just data.tar.* */ 1498 /* We don't care about control.tar.* or debian-binary, just data.tar.* */
1499 llist_add_to(&(ar_handle->accept), (char*)"data.tar");
1495#if ENABLE_FEATURE_SEAMLESS_GZ 1500#if ENABLE_FEATURE_SEAMLESS_GZ
1496 llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz"); 1501 llist_add_to(&(ar_handle->accept), (char*)"data.tar.gz");
1497#endif 1502#endif
1498#if ENABLE_FEATURE_SEAMLESS_BZ2 1503#if ENABLE_FEATURE_SEAMLESS_BZ2
1499 llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2"); 1504 llist_add_to(&(ar_handle->accept), (char*)"data.tar.bz2");
1500#endif 1505#endif
1506#if ENABLE_FEATURE_SEAMLESS_LZMA
1507 llist_add_to(&(ar_handle->accept), (char*)"data.tar.lzma");
1508#endif
1509#if ENABLE_FEATURE_SEAMLESS_XZ
1510 llist_add_to(&(ar_handle->accept), (char*)"data.tar.xz");
1511#endif
1501 1512
1502 /* Assign the tar handle as a subarchive of the ar handle */ 1513 /* Assign the tar handle as a subarchive of the ar handle */
1503 ar_handle->dpkg__sub_archive = tar_handle; 1514 ar_handle->dpkg__sub_archive = tar_handle;
diff --git a/archival/dpkg_deb.c b/archival/dpkg_deb.c
index 13f9db991..0285273fe 100644
--- a/archival/dpkg_deb.c
+++ b/archival/dpkg_deb.c
@@ -70,6 +70,8 @@ int dpkg_deb_main(int argc, char **argv)
70 ar_archive->dpkg__sub_archive = tar_archive; 70 ar_archive->dpkg__sub_archive = tar_archive;
71 ar_archive->filter = filter_accept_list_reassign; 71 ar_archive->filter = filter_accept_list_reassign;
72 72
73 llist_add_to(&ar_archive->accept, (char*)"data.tar");
74 llist_add_to(&control_tar_llist, (char*)"control.tar");
73#if ENABLE_FEATURE_SEAMLESS_GZ 75#if ENABLE_FEATURE_SEAMLESS_GZ
74 llist_add_to(&ar_archive->accept, (char*)"data.tar.gz"); 76 llist_add_to(&ar_archive->accept, (char*)"data.tar.gz");
75 llist_add_to(&control_tar_llist, (char*)"control.tar.gz"); 77 llist_add_to(&control_tar_llist, (char*)"control.tar.gz");
@@ -82,6 +84,10 @@ int dpkg_deb_main(int argc, char **argv)
82 llist_add_to(&ar_archive->accept, (char*)"data.tar.lzma"); 84 llist_add_to(&ar_archive->accept, (char*)"data.tar.lzma");
83 llist_add_to(&control_tar_llist, (char*)"control.tar.lzma"); 85 llist_add_to(&control_tar_llist, (char*)"control.tar.lzma");
84#endif 86#endif
87#if ENABLE_FEATURE_SEAMLESS_XZ
88 llist_add_to(&ar_archive->accept, (char*)"data.tar.xz");
89 llist_add_to(&control_tar_llist, (char*)"control.tar.xz");
90#endif
85 91
86 opt_complementary = "c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX"; 92 opt_complementary = "c--efXx:e--cfXx:f--ceXx:X--cefx:x--cefX";
87 opt = getopt32(argv, "cefXx"); 93 opt = getopt32(argv, "cefXx");
diff --git a/archival/gzip.c b/archival/gzip.c
index a93d2175a..bc1f9c60b 100644
--- a/archival/gzip.c
+++ b/archival/gzip.c
@@ -417,19 +417,46 @@ static void flush_outbuf(void)
417#define put_8bit(c) \ 417#define put_8bit(c) \
418do { \ 418do { \
419 G1.outbuf[G1.outcnt++] = (c); \ 419 G1.outbuf[G1.outcnt++] = (c); \
420 if (G1.outcnt == OUTBUFSIZ) flush_outbuf(); \ 420 if (G1.outcnt == OUTBUFSIZ) \
421 flush_outbuf(); \
421} while (0) 422} while (0)
422 423
423/* Output a 16 bit value, lsb first */ 424/* Output a 16 bit value, lsb first */
424static void put_16bit(ush w) 425static void put_16bit(ush w)
425{ 426{
426 if (G1.outcnt < OUTBUFSIZ - 2) { 427 /* GCC 4.2.1 won't optimize out redundant loads of G1.outcnt
427 G1.outbuf[G1.outcnt++] = w; 428 * (probably because of fear of aliasing with G1.outbuf[]
428 G1.outbuf[G1.outcnt++] = w >> 8; 429 * stores), do it explicitly:
429 } else { 430 */
430 put_8bit(w); 431 unsigned outcnt = G1.outcnt;
431 put_8bit(w >> 8); 432 uch *dst = &G1.outbuf[outcnt];
433
434#if BB_UNALIGNED_MEMACCESS_OK && BB_LITTLE_ENDIAN
435 if (outcnt < OUTBUFSIZ-2) {
436 /* Common case */
437 ush *dst16 = (void*) dst;
438 *dst16 = w; /* unalinged LSB 16-bit store */
439 G1.outcnt = outcnt + 2;
440 return;
432 } 441 }
442 *dst = (uch)w;
443 w >>= 8;
444#else
445 *dst = (uch)w;
446 w >>= 8;
447 if (outcnt < OUTBUFSIZ-2) {
448 /* Common case */
449 dst[1] = w;
450 G1.outcnt = outcnt + 2;
451 return;
452 }
453#endif
454
455 /* Slowpath: we will need to do flush_outbuf() */
456 G1.outcnt = ++outcnt;
457 if (outcnt == OUTBUFSIZ)
458 flush_outbuf();
459 put_8bit(w);
433} 460}
434 461
435static void put_32bit(ulg n) 462static void put_32bit(ulg n)
@@ -2007,7 +2034,7 @@ static void ct_init(void)
2007 * IN assertions: the input and output buffers are cleared. 2034 * IN assertions: the input and output buffers are cleared.
2008 */ 2035 */
2009 2036
2010static void zip(ulg time_stamp) 2037static void zip(void)
2011{ 2038{
2012 ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */ 2039 ush deflate_flags = 0; /* pkzip -es, -en or -ex equivalent */
2013 2040
@@ -2018,7 +2045,7 @@ static void zip(ulg time_stamp)
2018 /* compression method: 8 (DEFLATED) */ 2045 /* compression method: 8 (DEFLATED) */
2019 /* general flags: 0 */ 2046 /* general flags: 0 */
2020 put_32bit(0x00088b1f); 2047 put_32bit(0x00088b1f);
2021 put_32bit(time_stamp); 2048 put_32bit(0); /* Unix timestamp */
2022 2049
2023 /* Write deflated file to zip file */ 2050 /* Write deflated file to zip file */
2024 G1.crc = ~0; 2051 G1.crc = ~0;
@@ -2044,8 +2071,6 @@ static void zip(ulg time_stamp)
2044static 2071static
2045IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_state_t *xstate UNUSED_PARAM) 2072IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_state_t *xstate UNUSED_PARAM)
2046{ 2073{
2047 struct stat s;
2048
2049 /* Clear input and output buffers */ 2074 /* Clear input and output buffers */
2050 G1.outcnt = 0; 2075 G1.outcnt = 0;
2051#ifdef DEBUG 2076#ifdef DEBUG
@@ -2077,9 +2102,23 @@ IF_DESKTOP(long long) int FAST_FUNC pack_gzip(transformer_state_t *xstate UNUSED
2077 G2.bl_desc.max_length = MAX_BL_BITS; 2102 G2.bl_desc.max_length = MAX_BL_BITS;
2078 //G2.bl_desc.max_code = 0; 2103 //G2.bl_desc.max_code = 0;
2079 2104
2105#if 0
2106 /* Saving of timestamp is disabled. Why?
2107 * - it is not Y2038-safe.
2108 * - some people want deterministic results
2109 * (normally they'd use -n, but our -n is a nop).
2110 * - it's bloat.
2111 * Per RFC 1952, gzfile.time=0 is "no timestamp".
2112 * If users will demand this to be reinstated,
2113 * implement -n "don't save timestamp".
2114 */
2115 struct stat s;
2080 s.st_ctime = 0; 2116 s.st_ctime = 0;
2081 fstat(STDIN_FILENO, &s); 2117 fstat(STDIN_FILENO, &s);
2082 zip(s.st_ctime); 2118 zip(s.st_ctime);
2119#else
2120 zip();
2121#endif
2083 return 0; 2122 return 0;
2084} 2123}
2085 2124
diff --git a/archival/libarchive/Kbuild.src b/archival/libarchive/Kbuild.src
index 968fdf8ab..b7faaf77f 100644
--- a/archival/libarchive/Kbuild.src
+++ b/archival/libarchive/Kbuild.src
@@ -30,11 +30,13 @@ COMMON_FILES:= \
30DPKG_FILES:= \ 30DPKG_FILES:= \
31 unpack_ar_archive.o \ 31 unpack_ar_archive.o \
32 filter_accept_list_reassign.o \ 32 filter_accept_list_reassign.o \
33 unsafe_prefix.o \
33 get_header_ar.o \ 34 get_header_ar.o \
34 get_header_tar.o \ 35 get_header_tar.o \
35 get_header_tar_gz.o \ 36 get_header_tar_gz.o \
36 get_header_tar_bz2.o \ 37 get_header_tar_bz2.o \
37 get_header_tar_lzma.o \ 38 get_header_tar_lzma.o \
39 get_header_tar_xz.o \
38 40
39INSERT 41INSERT
40 42
@@ -43,7 +45,7 @@ lib-$(CONFIG_DPKG_DEB) += $(DPKG_FILES)
43 45
44lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o 46lib-$(CONFIG_AR) += get_header_ar.o unpack_ar_archive.o
45lib-$(CONFIG_CPIO) += get_header_cpio.o 47lib-$(CONFIG_CPIO) += get_header_cpio.o
46lib-$(CONFIG_TAR) += get_header_tar.o 48lib-$(CONFIG_TAR) += get_header_tar.o unsafe_prefix.o
47lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o 49lib-$(CONFIG_FEATURE_TAR_TO_COMMAND) += data_extract_to_command.o
48lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o 50lib-$(CONFIG_LZOP) += lzo1x_1.o lzo1x_1o.o lzo1x_d.o
49lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o 51lib-$(CONFIG_LZOP_COMPR_HIGH) += lzo1x_9x.o
@@ -52,7 +54,7 @@ lib-$(CONFIG_UNLZMA) += open_transformer.o decompress_unlzma.
52lib-$(CONFIG_UNXZ) += open_transformer.o decompress_unxz.o 54lib-$(CONFIG_UNXZ) += open_transformer.o decompress_unxz.o
53lib-$(CONFIG_GUNZIP) += open_transformer.o decompress_gunzip.o 55lib-$(CONFIG_GUNZIP) += open_transformer.o decompress_gunzip.o
54lib-$(CONFIG_UNCOMPRESS) += open_transformer.o decompress_uncompress.o 56lib-$(CONFIG_UNCOMPRESS) += open_transformer.o decompress_uncompress.o
55lib-$(CONFIG_UNZIP) += open_transformer.o decompress_gunzip.o 57lib-$(CONFIG_UNZIP) += open_transformer.o decompress_gunzip.o unsafe_prefix.o
56lib-$(CONFIG_RPM2CPIO) += open_transformer.o decompress_gunzip.o get_header_cpio.o 58lib-$(CONFIG_RPM2CPIO) += open_transformer.o decompress_gunzip.o get_header_cpio.o
57lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o 59lib-$(CONFIG_RPM) += open_transformer.o decompress_gunzip.o get_header_cpio.o
58 60
diff --git a/archival/libarchive/filter_accept_list_reassign.c b/archival/libarchive/filter_accept_list_reassign.c
index 3d19abe44..b9acfbc05 100644
--- a/archival/libarchive/filter_accept_list_reassign.c
+++ b/archival/libarchive/filter_accept_list_reassign.c
@@ -28,6 +28,10 @@ char FAST_FUNC filter_accept_list_reassign(archive_handle_t *archive_handle)
28 name_ptr++; 28 name_ptr++;
29 29
30 /* Modify the subarchive handler based on the extension */ 30 /* Modify the subarchive handler based on the extension */
31 if (strcmp(name_ptr, "tar") == 0) {
32 archive_handle->dpkg__action_data_subarchive = get_header_tar;
33 return EXIT_SUCCESS;
34 }
31 if (ENABLE_FEATURE_SEAMLESS_GZ 35 if (ENABLE_FEATURE_SEAMLESS_GZ
32 && strcmp(name_ptr, "gz") == 0 36 && strcmp(name_ptr, "gz") == 0
33 ) { 37 ) {
@@ -46,6 +50,12 @@ char FAST_FUNC filter_accept_list_reassign(archive_handle_t *archive_handle)
46 archive_handle->dpkg__action_data_subarchive = get_header_tar_lzma; 50 archive_handle->dpkg__action_data_subarchive = get_header_tar_lzma;
47 return EXIT_SUCCESS; 51 return EXIT_SUCCESS;
48 } 52 }
53 if (ENABLE_FEATURE_SEAMLESS_XZ
54 && strcmp(name_ptr, "xz") == 0
55 ) {
56 archive_handle->dpkg__action_data_subarchive = get_header_tar_xz;
57 return EXIT_SUCCESS;
58 }
49 } 59 }
50 return EXIT_FAILURE; 60 return EXIT_FAILURE;
51} 61}
diff --git a/archival/libarchive/get_header_cpio.c b/archival/libarchive/get_header_cpio.c
index 1a0058b63..7861d1f6f 100644
--- a/archival/libarchive/get_header_cpio.c
+++ b/archival/libarchive/get_header_cpio.c
@@ -37,7 +37,7 @@ char FAST_FUNC get_header_cpio(archive_handle_t *archive_handle)
37 } 37 }
38 archive_handle->offset += 110; 38 archive_handle->offset += 110;
39 39
40 if (strncmp(&cpio_header[0], "07070", 5) != 0 40 if (!is_prefixed_with(&cpio_header[0], "07070")
41 || (cpio_header[5] != '1' && cpio_header[5] != '2') 41 || (cpio_header[5] != '1' && cpio_header[5] != '2')
42 ) { 42 ) {
43 bb_error_msg_and_die("unsupported cpio format, use newc or crc"); 43 bb_error_msg_and_die("unsupported cpio format, use newc or crc");
diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c
index ba43bb073..2dbcdb50c 100644
--- a/archival/libarchive/get_header_tar.c
+++ b/archival/libarchive/get_header_tar.c
@@ -17,36 +17,6 @@
17typedef uint32_t aliased_uint32_t FIX_ALIASING; 17typedef uint32_t aliased_uint32_t FIX_ALIASING;
18typedef off_t aliased_off_t FIX_ALIASING; 18typedef off_t aliased_off_t FIX_ALIASING;
19 19
20
21const char* FAST_FUNC strip_unsafe_prefix(const char *str)
22{
23 const char *cp = str;
24 while (1) {
25 char *cp2;
26 if (*cp == '/') {
27 cp++;
28 continue;
29 }
30 if (strncmp(cp, "/../"+1, 3) == 0) {
31 cp += 3;
32 continue;
33 }
34 cp2 = strstr(cp, "/../");
35 if (!cp2)
36 break;
37 cp = cp2 + 4;
38 }
39 if (cp != str) {
40 static smallint warned = 0;
41 if (!warned) {
42 warned = 1;
43 bb_error_msg("removing leading '%.*s' from member names",
44 (int)(cp - str), str);
45 }
46 }
47 return cp;
48}
49
50/* NB: _DESTROYS_ str[len] character! */ 20/* NB: _DESTROYS_ str[len] character! */
51static unsigned long long getOctal(char *str, int len) 21static unsigned long long getOctal(char *str, int len)
52{ 22{
@@ -135,7 +105,7 @@ static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int g
135 value = end + 1; 105 value = end + 1;
136 106
137#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS 107#if ENABLE_FEATURE_TAR_GNU_EXTENSIONS
138 if (!global && strncmp(value, "path=", sizeof("path=") - 1) == 0) { 108 if (!global && is_prefixed_with(value, "path=")) {
139 value += sizeof("path=") - 1; 109 value += sizeof("path=") - 1;
140 free(archive_handle->tar__longname); 110 free(archive_handle->tar__longname);
141 archive_handle->tar__longname = xstrdup(value); 111 archive_handle->tar__longname = xstrdup(value);
@@ -148,7 +118,7 @@ static void process_pax_hdr(archive_handle_t *archive_handle, unsigned sz, int g
148 * This is what Red Hat's patched version of tar uses. 118 * This is what Red Hat's patched version of tar uses.
149 */ 119 */
150# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux" 120# define SELINUX_CONTEXT_KEYWORD "RHT.security.selinux"
151 if (strncmp(value, SELINUX_CONTEXT_KEYWORD"=", sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1) == 0) { 121 if (is_prefixed_with(value, SELINUX_CONTEXT_KEYWORD"=")) {
152 value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1; 122 value += sizeof(SELINUX_CONTEXT_KEYWORD"=") - 1;
153 free(archive_handle->tar__sctx[global]); 123 free(archive_handle->tar__sctx[global]);
154 archive_handle->tar__sctx[global] = xstrdup(value); 124 archive_handle->tar__sctx[global] = xstrdup(value);
@@ -232,7 +202,7 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle)
232 202
233 /* Check header has valid magic, "ustar" is for the proper tar, 203 /* Check header has valid magic, "ustar" is for the proper tar,
234 * five NULs are for the old tar format */ 204 * five NULs are for the old tar format */
235 if (strncmp(tar.magic, "ustar", 5) != 0 205 if (!is_prefixed_with(tar.magic, "ustar")
236 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY 206 && (!ENABLE_FEATURE_TAR_OLDGNU_COMPATIBILITY
237 || memcmp(tar.magic, "\0\0\0\0", 5) != 0) 207 || memcmp(tar.magic, "\0\0\0\0", 5) != 0)
238 ) { 208 ) {
diff --git a/archival/libarchive/get_header_tar_xz.c b/archival/libarchive/get_header_tar_xz.c
new file mode 100644
index 000000000..7bf3b3b56
--- /dev/null
+++ b/archival/libarchive/get_header_tar_xz.c
@@ -0,0 +1,21 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */
5
6#include "libbb.h"
7#include "bb_archive.h"
8
9char FAST_FUNC get_header_tar_xz(archive_handle_t *archive_handle)
10{
11 /* Can't lseek over pipes */
12 archive_handle->seek = seek_by_read;
13
14 fork_transformer_with_sig(archive_handle->src_fd, unpack_xz_stream, "unxz");
15 archive_handle->offset = 0;
16 while (get_header_tar(archive_handle) == EXIT_SUCCESS)
17 continue;
18
19 /* Can only do one file at a time */
20 return EXIT_FAILURE;
21}
diff --git a/archival/libarchive/unpack_ar_archive.c b/archival/libarchive/unpack_ar_archive.c
index 214d17e23..0bc030349 100644
--- a/archival/libarchive/unpack_ar_archive.c
+++ b/archival/libarchive/unpack_ar_archive.c
@@ -12,7 +12,7 @@ void FAST_FUNC unpack_ar_archive(archive_handle_t *ar_archive)
12 char magic[7]; 12 char magic[7];
13 13
14 xread(ar_archive->src_fd, magic, AR_MAGIC_LEN); 14 xread(ar_archive->src_fd, magic, AR_MAGIC_LEN);
15 if (strncmp(magic, AR_MAGIC, AR_MAGIC_LEN) != 0) { 15 if (!is_prefixed_with(magic, AR_MAGIC)) {
16 bb_error_msg_and_die("invalid ar magic"); 16 bb_error_msg_and_die("invalid ar magic");
17 } 17 }
18 ar_archive->offset += AR_MAGIC_LEN; 18 ar_archive->offset += AR_MAGIC_LEN;
diff --git a/archival/libarchive/unsafe_prefix.c b/archival/libarchive/unsafe_prefix.c
new file mode 100644
index 000000000..9994f4d94
--- /dev/null
+++ b/archival/libarchive/unsafe_prefix.c
@@ -0,0 +1,36 @@
1/* vi: set sw=4 ts=4: */
2/*
3 * Licensed under GPLv2 or later, see file LICENSE in this source tree.
4 */
5
6#include "libbb.h"
7#include "bb_archive.h"
8
9const char* FAST_FUNC strip_unsafe_prefix(const char *str)
10{
11 const char *cp = str;
12 while (1) {
13 char *cp2;
14 if (*cp == '/') {
15 cp++;
16 continue;
17 }
18 if (is_prefixed_with(cp, "/../"+1)) {
19 cp += 3;
20 continue;
21 }
22 cp2 = strstr(cp, "/../");
23 if (!cp2)
24 break;
25 cp = cp2 + 4;
26 }
27 if (cp != str) {
28 static smallint warned = 0;
29 if (!warned) {
30 warned = 1;
31 bb_error_msg("removing leading '%.*s' from member names",
32 (int)(cp - str), str);
33 }
34 }
35 return cp;
36}
diff --git a/archival/unzip.c b/archival/unzip.c
index 1ef026a9f..d370203e8 100644
--- a/archival/unzip.c
+++ b/archival/unzip.c
@@ -599,14 +599,18 @@ int unzip_main(int argc, char **argv)
599 /* Skip extra header bytes */ 599 /* Skip extra header bytes */
600 unzip_skip(zip_header.formatted.extra_len); 600 unzip_skip(zip_header.formatted.extra_len);
601 601
602 /* Guard against "/abspath", "/../" and similar attacks */
603 overlapping_strcpy(dst_fn, strip_unsafe_prefix(dst_fn));
604
602 /* Filter zip entries */ 605 /* Filter zip entries */
603 if (find_list_entry(zreject, dst_fn) 606 if (find_list_entry(zreject, dst_fn)
604 || (zaccept && !find_list_entry(zaccept, dst_fn)) 607 || (zaccept && !find_list_entry(zaccept, dst_fn))
605 ) { /* Skip entry */ 608 ) { /* Skip entry */
606 i = 'n'; 609 i = 'n';
607 610
608 } else { /* Extract entry */ 611 } else {
609 if (listing) { /* List entry */ 612 if (listing) {
613 /* List entry */
610 unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16); 614 unsigned dostime = zip_header.formatted.modtime | (zip_header.formatted.moddate << 16);
611 if (!verbose) { 615 if (!verbose) {
612 // " Length Date Time Name\n" 616 // " Length Date Time Name\n"
@@ -642,9 +646,11 @@ int unzip_main(int argc, char **argv)
642 total_size += zip_header.formatted.cmpsize; 646 total_size += zip_header.formatted.cmpsize;
643 } 647 }
644 i = 'n'; 648 i = 'n';
645 } else if (dst_fd == STDOUT_FILENO) { /* Extracting to STDOUT */ 649 } else if (dst_fd == STDOUT_FILENO) {
650 /* Extracting to STDOUT */
646 i = -1; 651 i = -1;
647 } else if (last_char_is(dst_fn, '/')) { /* Extract directory */ 652 } else if (last_char_is(dst_fn, '/')) {
653 /* Extract directory */
648 if (stat(dst_fn, &stat_buf) == -1) { 654 if (stat(dst_fn, &stat_buf) == -1) {
649 if (errno != ENOENT) { 655 if (errno != ENOENT) {
650 bb_perror_msg_and_die("can't stat '%s'", dst_fn); 656 bb_perror_msg_and_die("can't stat '%s'", dst_fn);
@@ -658,22 +664,27 @@ int unzip_main(int argc, char **argv)
658 } 664 }
659 } else { 665 } else {
660 if (!S_ISDIR(stat_buf.st_mode)) { 666 if (!S_ISDIR(stat_buf.st_mode)) {
661 bb_error_msg_and_die("'%s' exists but is not directory", dst_fn); 667 bb_error_msg_and_die("'%s' exists but is not a %s",
668 dst_fn, "directory");
662 } 669 }
663 } 670 }
664 i = 'n'; 671 i = 'n';
665 672
666 } else { /* Extract file */ 673 } else {
674 /* Extract file */
667 check_file: 675 check_file:
668 if (stat(dst_fn, &stat_buf) == -1) { /* File does not exist */ 676 if (stat(dst_fn, &stat_buf) == -1) {
677 /* File does not exist */
669 if (errno != ENOENT) { 678 if (errno != ENOENT) {
670 bb_perror_msg_and_die("can't stat '%s'", dst_fn); 679 bb_perror_msg_and_die("can't stat '%s'", dst_fn);
671 } 680 }
672 i = 'y'; 681 i = 'y';
673 } else { /* File already exists */ 682 } else {
683 /* File already exists */
674 if (overwrite == O_NEVER) { 684 if (overwrite == O_NEVER) {
675 i = 'n'; 685 i = 'n';
676 } else if (S_ISREG(stat_buf.st_mode)) { /* File is regular file */ 686 } else if (S_ISREG(stat_buf.st_mode)) {
687 /* File is regular file */
677 if (overwrite == O_ALWAYS) { 688 if (overwrite == O_ALWAYS) {
678 i = 'y'; 689 i = 'y';
679 } else { 690 } else {
@@ -681,8 +692,10 @@ int unzip_main(int argc, char **argv)
681 my_fgets80(key_buf); 692 my_fgets80(key_buf);
682 i = key_buf[0]; 693 i = key_buf[0];
683 } 694 }
684 } else { /* File is not regular file */ 695 } else {
685 bb_error_msg_and_die("'%s' exists but is not regular file", dst_fn); 696 /* File is not regular file */
697 bb_error_msg_and_die("'%s' exists but is not a %s",
698 dst_fn, "regular file");
686 } 699 }
687 } 700 }
688 } 701 }