diff options
Diffstat (limited to 'archival/libarchive')
-rw-r--r-- | archival/libarchive/data_extract_all.c | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/archival/libarchive/data_extract_all.c b/archival/libarchive/data_extract_all.c index 1830ffb..1ce927c 100644 --- a/archival/libarchive/data_extract_all.c +++ b/archival/libarchive/data_extract_all.c @@ -128,10 +128,11 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) res = link(hard_link, dst_name); if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { /* shared message */ - bb_perror_msg("can't create %slink " - "%s to %s", "hard", + bb_perror_msg("can't create %slink '%s' to '%s'", + "hard", dst_name, - hard_link); + hard_link + ); } /* Hardlinks have no separate mode/ownership, skip chown/chmod */ goto ret; @@ -178,15 +179,44 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) case S_IFLNK: /* Symlink */ //TODO: what if file_header->link_target == NULL (say, corrupted tarball?) + + /* To avoid a directory traversal attack via symlinks, + * for certain link targets postpone creation of symlinks. + * + * For example, consider a .tar created via: + * $ tar cvf bug.tar anything.txt + * $ ln -s /tmp symlink + * $ tar --append -f bug.tar symlink + * $ rm symlink + * $ mkdir symlink + * $ tar --append -f bug.tar symlink/evil.py + * + * This will result in an archive that contains: + * $ tar --list -f bug.tar + * anything.txt + * symlink [-> /tmp] + * symlink/evil.py + * + * Untarring bug.tar would otherwise place evil.py in '/tmp'. + */ + if (file_header->link_target[0] == '/' + || strstr(file_header->link_target, "..") + ) { + llist_add_to(&archive_handle->symlink_placeholders, + xasprintf("%s%c%s", file_header->name, '\0', file_header->link_target) + ); + break; + } res = symlink(file_header->link_target, dst_name); if (res != 0 && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET) ) { /* shared message */ - bb_perror_msg("can't create %slink " - "%s to %s", "sym", + bb_perror_msg("can't create %slink '%s' to '%s'", + "sym", dst_name, - file_header->link_target); + file_header->link_target + ); } break; case S_IFSOCK: |