Merge pull request #2934 from ElhananHaenel/fix/zisofs-validate-log2bs
FIX - iso9660: validate pz_log2_bs, add test for 32-bit heap overflow
(cherry picked from commit f76218f309)
This commit is contained in:
1 parent
58a4f7c43b
commit
420a7d60fb
4 files changed
+1203
No files matched your search
@@ -513,6 +513,7 @@ libarchive_test_SOURCES= \
|
||||
libarchive/test/test_read_format_isorr_new_bz2.c \
|
||||
libarchive/test/test_read_format_isorr_rr_moved.c \
|
||||
libarchive/test/test_read_format_isozisofs_bz2.c \
|
||||
libarchive/test/test_read_format_iso_zisofs_overflow.c \
|
||||
libarchive/test/test_read_format_lha.c \
|
||||
libarchive/test/test_read_format_lha_bugfix_0.c \
|
||||
libarchive/test/test_read_format_lha_filename.c \
|
||||
@@ -890,6 +891,7 @@ libarchive_test_EXTRA_DIST=\
|
||||
libarchive/test/test_read_format_iso_rockridge_rr_moved.iso.Z.uu \
|
||||
libarchive/test/test_read_format_iso_xorriso.iso.Z.uu \
|
||||
libarchive/test/test_read_format_iso_zisofs.iso.Z.uu \
|
||||
libarchive/test/test_read_format_iso_zisofs_overflow.iso.uu \
|
||||
libarchive/test/test_read_format_lha_bugfix_0.lzh.uu \
|
||||
libarchive/test/test_read_format_lha_filename_cp932.lzh.uu \
|
||||
libarchive/test/test_read_format_lha_filename_utf16.lzh.uu \
|
||||
|
||||
@@ -153,6 +153,7 @@ IF(ENABLE_TEST)
|
||||
test_read_format_isorr_new_bz2.c
|
||||
test_read_format_isorr_rr_moved.c
|
||||
test_read_format_isozisofs_bz2.c
|
||||
test_read_format_iso_zisofs_overflow.c
|
||||
test_read_format_lha.c
|
||||
test_read_format_lha_bugfix_0.c
|
||||
test_read_format_lha_filename.c
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
/*-
|
||||
* Copyright (c) 2025
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without
|
||||
* modification, are permitted provided that the following conditions
|
||||
* are met:
|
||||
* 1. Redistributions of source code must retain the above copyright
|
||||
* notice, this list of conditions and the following disclaimer.
|
||||
* 2. Redistributions in binary form must reproduce the above copyright
|
||||
* notice, this list of conditions and the following disclaimer in the
|
||||
* documentation and/or other materials provided with the distribution.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE AUTHOR(S) ``AS IS'' AND ANY EXPRESS OR
|
||||
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
|
||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
|
||||
* IN NO EVENT SHALL THE AUTHOR(S) BE LIABLE FOR ANY DIRECT, INDIRECT,
|
||||
* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
|
||||
* NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
|
||||
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
|
||||
* THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#include "test.h"
|
||||
|
||||
/*
|
||||
* Verify that a crafted ISO9660 image with an invalid zisofs block-size
|
||||
* exponent (pz_log2_bs) is handled gracefully.
|
||||
*
|
||||
* The ZF extension in the Rock Ridge entry stores pz_log2_bs as a raw
|
||||
* byte from the image. The zisofs spec only permits values 15-17.
|
||||
* Values outside that range can cause:
|
||||
* - Undefined behavior via oversized bit shifts (any platform)
|
||||
* - Integer overflow in block pointer allocation on 32-bit platforms,
|
||||
* leading to a heap buffer overflow write
|
||||
*
|
||||
* The test image has pz_log2_bs=2 (out of spec) combined with
|
||||
* pz_uncompressed_size=0xFFFFFFF9. On 32-bit, (ceil+1)*4 overflows
|
||||
* size_t to 0, malloc(0) returns a tiny buffer, and the code attempts
|
||||
* to write ~4GB into it. On 64-bit the allocation is huge and safely
|
||||
* fails.
|
||||
*
|
||||
* We verify the fix by checking archive_entry_size() after reading the
|
||||
* header. When pz_log2_bs validation rejects the bad value (pz=0),
|
||||
* the entry keeps its raw on-disk size (small). Without the fix,
|
||||
* the reader sets the entry size to pz_uncompressed_size (0xFFFFFFF9).
|
||||
*
|
||||
* We intentionally do NOT call archive_read_data() here. Without the
|
||||
* fix, the data-read path triggers a heap buffer overflow on 32-bit
|
||||
* that silently corrupts the process heap, causing later tests to
|
||||
* crash rather than this one.
|
||||
*/
|
||||
DEFINE_TEST(test_read_format_iso_zisofs_overflow)
|
||||
{
|
||||
const char reffile[] = "test_read_format_iso_zisofs_overflow.iso";
|
||||
struct archive *a;
|
||||
struct archive_entry *ae;
|
||||
int r = ARCHIVE_OK;
|
||||
int found_regular_file = 0;
|
||||
|
||||
extract_reference_file(reffile);
|
||||
assert((a = archive_read_new()) != NULL);
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_filter_all(a));
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_support_format_all(a));
|
||||
assertEqualIntA(a, ARCHIVE_OK,
|
||||
archive_read_open_filename(a, reffile, 10240));
|
||||
|
||||
while ((r = archive_read_next_header(a, &ae)) == ARCHIVE_OK ||
|
||||
r == ARCHIVE_WARN) {
|
||||
/*
|
||||
* With the fix, pz_log2_bs=2 is rejected and pz is set
|
||||
* to 0, so the entry keeps its small raw size from the
|
||||
* ISO directory record. Without the fix, zisofs sets
|
||||
* the entry size to pz_uncompressed_size (0xFFFFFFF9).
|
||||
*
|
||||
* We intentionally do NOT call archive_read_data().
|
||||
* Without the fix, the data-read path triggers a heap
|
||||
* buffer overflow on 32-bit that silently corrupts the
|
||||
* process heap, causing later tests to crash rather
|
||||
* than this one.
|
||||
*/
|
||||
if (archive_entry_filetype(ae) == AE_IFREG) {
|
||||
la_int64_t sz = archive_entry_size(ae);
|
||||
failure("entry \"%s\" has size %jd"
|
||||
"; expected < 1 MiB"
|
||||
" (if size is 4294966265 = 0xFFFFFFF9, the"
|
||||
" pz_log2_bs validation is missing)",
|
||||
archive_entry_pathname(ae), (intmax_t)sz);
|
||||
assert(sz < 1024 * 1024);
|
||||
found_regular_file = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Iteration must have completed normally. */
|
||||
assertEqualInt(ARCHIVE_EOF, r);
|
||||
|
||||
/* The PoC image contains a regular file; if we never saw one,
|
||||
* something is wrong with the test image. */
|
||||
assert(found_regular_file);
|
||||
|
||||
assertEqualIntA(a, ARCHIVE_OK, archive_read_close(a));
|
||||
assertEqualInt(ARCHIVE_OK, archive_read_free(a));
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
Reference in new issue
Block a user