|
|
@ -0,0 +1,55 @@ |
|
|
|
From 65a23f5dbee4497064e9bb467f81138a62b0dae1 Mon Sep 17 00:00:00 2001 |
|
|
|
From: Daniel Axtens <dja@axtens.net> |
|
|
|
Date: Tue, 1 Jan 2019 16:01:40 +1100 |
|
|
|
Subject: [PATCH] 7zip: fix crash when parsing certain archives |
|
|
|
|
|
|
|
Fuzzing with CRCs disabled revealed that a call to get_uncompressed_data() |
|
|
|
would sometimes fail to return at least 'minimum' bytes. This can cause |
|
|
|
the crc32() invocation in header_bytes to read off into invalid memory. |
|
|
|
|
|
|
|
A specially crafted archive can use this to cause a crash. |
|
|
|
|
|
|
|
An ASAN trace is below, but ASAN is not required - an uninstrumented |
|
|
|
binary will also crash. |
|
|
|
|
|
|
|
==7719==ERROR: AddressSanitizer: SEGV on unknown address 0x631000040000 (pc 0x7fbdb3b3ec1d bp 0x7ffe77a51310 sp 0x7ffe77a51150 T0)
|
|
|
|
==7719==The signal is caused by a READ memory access.
|
|
|
|
#0 0x7fbdb3b3ec1c in crc32_z (/lib/x86_64-linux-gnu/libz.so.1+0x2c1c) |
|
|
|
#1 0x84f5eb in header_bytes (/tmp/libarchive/bsdtar+0x84f5eb) |
|
|
|
#2 0x856156 in read_Header (/tmp/libarchive/bsdtar+0x856156) |
|
|
|
#3 0x84e134 in slurp_central_directory (/tmp/libarchive/bsdtar+0x84e134) |
|
|
|
#4 0x849690 in archive_read_format_7zip_read_header (/tmp/libarchive/bsdtar+0x849690) |
|
|
|
#5 0x5713b7 in _archive_read_next_header2 (/tmp/libarchive/bsdtar+0x5713b7) |
|
|
|
#6 0x570e63 in _archive_read_next_header (/tmp/libarchive/bsdtar+0x570e63) |
|
|
|
#7 0x6f08bd in archive_read_next_header (/tmp/libarchive/bsdtar+0x6f08bd) |
|
|
|
#8 0x52373f in read_archive (/tmp/libarchive/bsdtar+0x52373f) |
|
|
|
#9 0x5257be in tar_mode_x (/tmp/libarchive/bsdtar+0x5257be) |
|
|
|
#10 0x51daeb in main (/tmp/libarchive/bsdtar+0x51daeb) |
|
|
|
#11 0x7fbdb27cab96 in __libc_start_main /build/glibc-OTsEL5/glibc-2.27/csu/../csu/libc-start.c:310 |
|
|
|
#12 0x41dd09 in _start (/tmp/libarchive/bsdtar+0x41dd09) |
|
|
|
|
|
|
|
This was primarly done with afl and FairFuzz. Some early corpus entries |
|
|
|
may have been generated by qsym. |
|
|
|
---
|
|
|
|
libarchive/archive_read_support_format_7zip.c | 8 +------- |
|
|
|
1 file changed, 1 insertion(+), 7 deletions(-) |
|
|
|
|
|
|
|
diff --git a/libarchive/archive_read_support_format_7zip.c b/libarchive/archive_read_support_format_7zip.c
|
|
|
|
index bccbf8966..b6d1505d3 100644
|
|
|
|
--- a/libarchive/archive_read_support_format_7zip.c
|
|
|
|
+++ b/libarchive/archive_read_support_format_7zip.c
|
|
|
|
@@ -2964,13 +2964,7 @@ get_uncompressed_data(struct archive_read *a, const void **buff, size_t size,
|
|
|
|
if (zip->codec == _7Z_COPY && zip->codec2 == (unsigned long)-1) { |
|
|
|
/* Copy mode. */ |
|
|
|
|
|
|
|
- /*
|
|
|
|
- * Note: '1' here is a performance optimization.
|
|
|
|
- * Recall that the decompression layer returns a count of
|
|
|
|
- * available bytes; asking for more than that forces the
|
|
|
|
- * decompressor to combine reads by copying data.
|
|
|
|
- */
|
|
|
|
- *buff = __archive_read_ahead(a, 1, &bytes_avail);
|
|
|
|
+ *buff = __archive_read_ahead(a, minimum, &bytes_avail);
|
|
|
|
if (bytes_avail <= 0) { |
|
|
|
archive_set_error(&a->archive, |
|
|
|
ARCHIVE_ERRNO_FILE_FORMAT, |