From abdb1748ddd420d03928d7d8ddbc13babc893a6d Mon Sep 17 00:00:00 2001 From: Narayan Kamath Date: Wed, 9 Aug 2017 18:32:09 +0100 Subject: zip_archive: reject files that don't start with an LFH signature. Bug: 64211847 Test: zip_archive_test (cherry picked from commit c1a56dcab711a7ee238c0af865920ca51b1408a6) Merged-In: I275e7c4da05ceeb20401b560c72294f29ef63642 Change-Id: Ib89f0def696206ff427be27764c158fab88e4b5d CVE-2017-13156 --- libziparchive/zip_archive.cc | 18 ++++++++++++++ libziparchive/zip_archive_test.cc | 49 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc index 8c2c559b1..b93d192fe 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc @@ -552,6 +552,8 @@ static int32_t MapCentralDirectory(int fd, const char* debug_file_name, return result; } +static inline ssize_t ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off); + /* * Parses the Zip archive's Central Directory. Allocates and populates the * hash table. @@ -630,6 +632,22 @@ static int32_t ParseZipArchive(ZipArchive* archive) { return -1; } } + + uint32_t lfh_start_bytes; + if (!ReadAtOffset(archive->fd, reinterpret_cast(&lfh_start_bytes), + sizeof(uint32_t), 0)) { + ALOGW("Zip: Unable to read header for entry at offset == 0."); + return -1; + } + + if (lfh_start_bytes != LocalFileHeader::kSignature) { + ALOGW("Zip: Entry at offset zero has invalid LFH signature %" PRIx32, lfh_start_bytes); +#if defined(__ANDROID__) + android_errorWriteLog(0x534e4554, "64211847"); +#endif + return -1; + } + ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries); return 0; diff --git a/libziparchive/zip_archive_test.cc b/libziparchive/zip_archive_test.cc index c79986957..89eb496cc 100644 --- a/libziparchive/zip_archive_test.cc +++ b/libziparchive/zip_archive_test.cc @@ -530,6 +530,55 @@ TEST(ziparchive, ExtractToFile) { close(fd); } +// A zip file whose local file header at offset zero is corrupted. +// +// --------------- +// cat foo > a.txt +// zip a.zip a.txt +// cat a.zip | xxd -i +// +// Manual changes : +// [2] = 0xff // Corrupt the LFH signature of entry 0. +// [3] = 0xff // Corrupt the LFH signature of entry 0. +static const std::vector kZipFileWithBrokenLfhSignature{ + //[lfh-sig-----------], [lfh contents--------------------------------- + 0x50, 0x4b, 0xff, 0xff, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80, + //-------------------------------------------------------------------- + 0x09, 0x4b, 0xa8, 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, + //-------------------------------] [file-name-----------------], [--- + 0x00, 0x00, 0x05, 0x00, 0x1c, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, + // entry-contents------------------------------------------------------ + 0x54, 0x09, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x51, 0x24, 0x8b, 0x59, + //-------------------------------------------------------------------- + 0x75, 0x78, 0x0b, 0x00, 0x01, 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88, + //-------------------------------------], [cd-record-sig-------], [--- + 0x13, 0x00, 0x00, 0x66, 0x6f, 0x6f, 0x0a, 0x50, 0x4b, 0x01, 0x02, 0x1e, + // cd-record----------------------------------------------------------- + 0x03, 0x0a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x77, 0x80, 0x09, 0x4b, 0xa8, + //-------------------------------------------------------------------- + 0x65, 0x32, 0x7e, 0x04, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x05, + //-------------------------------------------------------------------- + 0x00, 0x18, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0xa0, + //-] [lfh-file-header-off-], [file-name-----------------], [extra---- + 0x81, 0x00, 0x00, 0x00, 0x00, 0x61, 0x2e, 0x74, 0x78, 0x74, 0x55, 0x54, + //-------------------------------------------------------------------- + 0x05, 0x00, 0x03, 0x51, 0x24, 0x8b, 0x59, 0x75, 0x78, 0x0b, 0x00, 0x01, + //-------------------------------------------------------], [eocd-sig- + 0x04, 0x89, 0x42, 0x00, 0x00, 0x04, 0x88, 0x13, 0x00, 0x00, 0x50, 0x4b, + //-------], [--------------------------------------------------------- + 0x05, 0x06, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x01, 0x00, 0x4b, 0x00, + //-------------------------------------------] + 0x00, 0x00, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00}; + +TEST(ziparchive, BrokenLfhSignature) { + TemporaryFile tmp_file; + ASSERT_NE(-1, tmp_file.fd); + ASSERT_TRUE(android::base::WriteFully(tmp_file.fd, &kZipFileWithBrokenLfhSignature[0], + kZipFileWithBrokenLfhSignature.size())); + ZipArchiveHandle handle; + ASSERT_EQ(-1, OpenArchiveFd(tmp_file.fd, "LeadingNonZipBytes", &handle)); +} + int main(int argc, char** argv) { ::testing::InitGoogleTest(&argc, argv); -- cgit v1.2.3