commit b0b5e93606dc52fce909788a7d52dfdc11fe7d29 Author: Jacob Welsh AuthorDate: Thu Apr 25 04:12:08 2024 +0000 Commit: Jacob Welsh CommitDate: Thu Apr 25 05:09:00 2024 +0000 busybox/archival: range check file_header->size and correct my earlier addition of bb_perror_msg for a similar internal error diff --git a/base/busybox/archival/libarchive/data_extract_all.c b/base/busybox/archival/libarchive/data_extract_all.c index 32baa22..cf8da99 100644 --- a/base/busybox/archival/libarchive/data_extract_all.c +++ b/base/busybox/archival/libarchive/data_extract_all.c @@ -10,7 +10,7 @@ static int copyfd_exact_size(int src, int dst, off_t size) { off_t sz = bb_copyfd_size(src, dst, size); - if (sz == (size >= 0 ? size : -size)) { + if (sz == size) { return 0; } if (sz != -1) { @@ -80,7 +80,6 @@ static void atomic_replace_file(archive_handle_t *archive_handle) goto fail; } - /* XXX are we sure size > 0? */ if (copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size) == -1) { close(dst_fd); @@ -160,6 +159,18 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) sctx = archive_handle->tar__sctx[PAX_GLOBAL]; #endif + if (file_header->size < 0) { + /* XXX currently it IS possible to hit this, eg with a crafted tar file encoding a size header > 2^63. Seems like an upstream failing of get_header_tar.c. */ + bb_error_msg("invalid file header: negative size for %s", + file_header->name); + goto abort; + } + if (S_ISLNK(file_header->mode) && !file_header->link_target) { + bb_error_msg("inconsistent file header: symlink without target %s", + file_header->name); + goto abort; + } + /* Walk the path, validating and creating dirs as needed. */ for (slash = strchr(file_header->name, '/'); slash; slash = strchr(slash+1, '/')) { @@ -325,7 +336,6 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) goto abort; } - /* XXX are we sure size > 0? */ if (copyfd_exact_size(archive_handle->src_fd, dst_fd, file_header->size) == -1) { close(dst_fd); @@ -347,12 +357,6 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) break; case S_IFLNK: /* Symlink */ - if (!file_header->link_target) { - bb_perror_msg("inconsistent file header: " - "symlink without target %s", - file_header->name); - goto abort; - } #ifdef ARCHIVE_REPLACE_VIA_RENAME if (archive_handle->ah_flags & ARCHIVE_REPLACE_VIA_RENAME) { atomic_replace_file(archive_handle);