diff --git a/archival/libarchive/get_header_tar.c b/archival/libarchive/get_header_tar.c index 2e0332792..6a1532c86 100644 --- a/archival/libarchive/get_header_tar.c +++ b/archival/libarchive/get_header_tar.c @@ -422,11 +422,28 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) p_linkname = NULL; } #endif - if (strncmp(file_header->name, "/../"+1, 3) == 0 - || strstr(file_header->name, "/../") - ) { - bb_error_msg_and_die("name with '..' encountered: '%s'", - file_header->name); + + /* Everything up to and including last ".." component is stripped */ + cp = file_header->name; + while (1) { + char *cp2; + if (strncmp(cp, "/../"+1, 3) == 0) { + cp += 3; + continue; + } + cp2 = strstr(cp, "/../"); + if (cp2) { + cp = cp2 + 4; + continue; + } + break; + } + if (cp != file_header->name) { + if (!(archive_handle->ah_flags & ARCHIVE_TAR__TRUNC_WARNED)) { + archive_handle->ah_flags |= ARCHIVE_TAR__TRUNC_WARNED; + bb_error_msg("removing leading '%.*s'", (int)(cp - file_header->name), file_header->name); + } + overlapping_strcpy(file_header->name, cp); } /* Strip trailing '/' in directories */ diff --git a/include/archive.h b/include/archive.h index 49c478728..9fc77e542 100644 --- a/include/archive.h +++ b/include/archive.h @@ -118,6 +118,8 @@ typedef struct archive_handle_t { #define ARCHIVE_DONT_RESTORE_PERM (1 << 6) #define ARCHIVE_NUMERIC_OWNER (1 << 7) #define ARCHIVE_O_TRUNC (1 << 8) +/* Archiver specific. */ +#define ARCHIVE_TAR__TRUNC_WARNED (1 << 9) /* POSIX tar Header Block, from POSIX 1003.1-1990 */ diff --git a/testsuite/tar.tests b/testsuite/tar.tests index 472064f7f..d41d10d57 100755 --- a/testsuite/tar.tests +++ b/testsuite/tar.tests @@ -168,6 +168,23 @@ Ok " \ "" "" +# On extract, everything up to and including last ".." component is stripped +testing "tar strips /../ on extract" "\ +rm -rf input_* test.tar 2>/dev/null +mkdir input_dir +echo Ok >input_dir/file +tar cf test.tar ./../tar.tempdir/input_dir/../input_dir 2>&1 +rm -rf input_* 2>/dev/null +tar -vxf test.tar 2>&1 +cat input_dir/file 2>&1 +" "\ +tar: removing leading './../tar.tempdir/input_dir/../' +input_dir/ +input_dir/file +Ok +" \ +"" "" + cd .. && rm -rf tar.tempdir || exit 1