commit 63bf3f58ed56937ebcfbac2c906f681a7cc01d21 Author: Jacob Welsh AuthorDate: Fri Apr 19 22:32:36 2024 +0000 Commit: Jacob Welsh CommitDate: Fri Apr 19 22:33:27 2024 +0000 busybox/archival: refactor: hard link creation doesn't need separate pre-checking diff --git a/base/busybox/archival/libarchive/data_extract_all.c b/base/busybox/archival/libarchive/data_extract_all.c index f8904f3..63fa155 100644 --- a/base/busybox/archival/libarchive/data_extract_all.c +++ b/base/busybox/archival/libarchive/data_extract_all.c @@ -122,33 +122,31 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) } } - /* Handle hard links separately - * We encode hard links as regular files of size 0 with a symlink */ - if (S_ISREG(file_header->mode) - && file_header->link_target - && file_header->size == 0 - ) { - /* hard link */ - res = link(file_header->link_target, file_header->name); - if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { - bb_perror_msg("can't create %slink " - "from %s to %s", "hard", - file_header->name, - file_header->link_target); - } - /* Hardlinks have no separate mode/ownership, skip chown/chmod */ - goto ret; - } - /* Create the filesystem entry */ switch (file_header->mode & S_IFMT) { case S_IFREG: { /* Regular file */ char *dst_name; - int flags = O_WRONLY | O_CREAT | O_EXCL; + int flags; + + /* We encode hard links as regular files of size 0 with a symlink */ + if (file_header->link_target && file_header->size == 0) { + res = link(file_header->link_target, file_header->name); + if ((res == -1) && !(archive_handle->ah_flags & ARCHIVE_EXTRACT_QUIET)) { + bb_perror_msg("can't create %slink " + "from %s to %s", "hard", + file_header->name, + file_header->link_target); + } + /* Hardlinks have no separate mode/ownership, skip chown/chmod */ + goto ret; + } + if (archive_handle->ah_flags & ARCHIVE_O_TRUNC) /* TODO symlink attack safety (eg tar file first lists a symlink, then a regular file of the same name, causing us to truncate & overwrite an arbitrary file) */ flags = O_WRONLY | O_CREAT | O_TRUNC; + else + flags = O_WRONLY | O_CREAT | O_EXCL; dst_name = file_header->name; #ifdef ARCHIVE_REPLACE_VIA_RENAME if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME)