commit 0c4ce4acd47006e47b0877dfd03cac45542ea06b Author: Jacob Welsh AuthorDate: Sat Apr 27 02:44:26 2024 +0000 Commit: Jacob Welsh CommitDate: Sat Apr 27 02:44:26 2024 +0000 busybox/archival: fix integer overflows leading to possible heap buffer overflow in reading tar headers diff --git a/base/busybox/archival/libarchive/data_extract_all.c b/base/busybox/archival/libarchive/data_extract_all.c index 4c401b2..80bc0b2 100644 --- a/base/busybox/archival/libarchive/data_extract_all.c +++ b/base/busybox/archival/libarchive/data_extract_all.c @@ -177,8 +177,7 @@ void FAST_FUNC data_extract_all(archive_handle_t *archive_handle) #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", + bb_error_msg("BUG: bad header: negative size for %s", file_header->name); goto abort; } diff --git a/base/busybox/archival/libarchive/get_header_tar.c b/base/busybox/archival/libarchive/get_header_tar.c index 8db1718..eb72113 100644 --- a/base/busybox/archival/libarchive/get_header_tar.c +++ b/base/busybox/archival/libarchive/get_header_tar.c @@ -287,6 +287,8 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) #endif file_header->mtime = GET_OCTAL(tar.mtime); file_header->size = GET_OCTAL(tar.size); + if (file_header->size < 0) + bb_error_msg_and_die("bad header: size out of range"); file_header->gid = GET_OCTAL(tar.gid); file_header->uid = GET_OCTAL(tar.uid); /* Set bits 0-11 of the files mode */ @@ -364,6 +366,9 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) case 'L': /* free: paranoia: tar with several consecutive longnames */ free(p_longname); + /* off_t may overflow size_t (eg 32-bit archs), or +1 overflows if it's the max */ + if ((uoff_t)file_header->size >= SIZE_MAX) + bb_error_msg_and_die("bad header: size out of range for longname"); /* For paranoia reasons we allocate extra NUL char */ p_longname = xzalloc(file_header->size + 1); /* We read ASCIZ string, including NUL */ @@ -375,6 +380,9 @@ char FAST_FUNC get_header_tar(archive_handle_t *archive_handle) goto again; case 'K': free(p_linkname); + /* off_t may overflow size_t (eg 32-bit archs), or +1 overflows if it's the max */ + if ((uoff_t)file_header->size >= SIZE_MAX) + bb_error_msg_and_die("bad header: size out of range for linkname"); p_linkname = xzalloc(file_header->size + 1); xread(archive_handle->src_fd, p_linkname, file_header->size); archive_handle->offset += file_header->size;