commit acd34575a09ed4a0aa57525a799f3cbe0f2b0061 Author: Jacob Welsh AuthorDate: Tue Apr 23 18:09:56 2024 +0000 Commit: Jacob Welsh CommitDate: Tue Apr 23 18:09:56 2024 +0000 busybox/archival: bring the unlink logic for the ARCHIVE_EXTRACT_NEWER case into agreement with the ARCHIVE_UNLINK_OLD one; in particular, don't ignore EISDIR if we're not in fact creating a directory. diff --git a/base/busybox/archival/libarchive/data_extract_all.c b/base/busybox/archival/libarchive/data_extract_all.c index a44bcc1..065c35c 100644 --- a/base/busybox/archival/libarchive/data_extract_all.c +++ b/base/busybox/archival/libarchive/data_extract_all.c @@ -120,7 +120,13 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) data_skip(archive_handle); goto ret; } - else if ((unlink(file_header->name) == -1) && (errno != EISDIR)) { + /* As above. + * Note: we could skip the ENOENT case this time, since we just determined that the file exists. But why leave a race condition when it's easily prevented? In general though we're not bothering about such conditions, because we can't e.g. atomically open or chdir with check for symlink, so security will have to depend on only one process creating entries based on untrusted data in the same directory at the same time. + */ + if (unlink(file_header->name) == -1 + && errno != ENOENT + && !(errno == EISDIR && S_ISDIR(file_header->mode)) + ) { bb_perror_msg_and_die("can't remove old file %s", file_header->name); }