From d987c9dd9eff02ce2a49ee413f08218e9090ad4a Mon Sep 17 00:00:00 2001 From: Adam Lesinski Date: Thu, 6 Apr 2017 18:55:47 -0700 Subject: [PATCH] ZipWriter: Keep LFH and CFH in sync We change the GPB in the LocalFileHeader if the entry can not have a trailing DataDescriptor. Make sure to patch the CentralFileHeader to have the same bits set. Modify ZipArchive to check that the data descriptor bit is consistent between Central and Local file headers. (cherry-pick of commit e0eca55fe6e36a8ae975be6cbb5a7932b30ba0c1) Test: make ziparchive-tests Bug: 36686974 Change-Id: Ied167570abcf6426b1c678cd40123e5ad65909db --- libziparchive/zip_archive.cc | 11 +++++++++++ libziparchive/zip_writer.cc | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/libziparchive/zip_archive.cc b/libziparchive/zip_archive.cc index 0ac6f2c0c..246575f81 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc @@ -563,6 +563,17 @@ static int32_t FindEntry(const ZipArchive* archive, const int ent, // Paranoia: Match the values specified in the local file header // to those specified in the central directory. + + // Verify that the central directory and local file header agree on the use of a trailing + // Data Descriptor. + if ((lfh->gpb_flags & kGPBDDFlagMask) != (cdr->gpb_flags & kGPBDDFlagMask)) { + ALOGW("Zip: gpb flag mismatch. expected {%04" PRIx16 "}, was {%04" PRIx16 "}", + cdr->gpb_flags, lfh->gpb_flags); + return kInconsistentInformation; + } + + // If there is no trailing data descriptor, verify that the central directory and local file + // header agree on the crc, compressed, and uncompressed sizes of the entry. if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) { data->has_data_descriptor = 0; if (data->compressed_length != lfh->compressed_size diff --git a/libziparchive/zip_writer.cc b/libziparchive/zip_writer.cc index 2edf224b4..6d28bdb5e 100644 --- a/libziparchive/zip_writer.cc +++ b/libziparchive/zip_writer.cc @@ -479,7 +479,9 @@ int32_t ZipWriter::Finish() { for (FileEntry& file : files_) { CentralDirectoryRecord cdr = {}; cdr.record_signature = CentralDirectoryRecord::kSignature; - cdr.gpb_flags |= kGPBDDFlagMask; + if ((file.compression_method & kCompressDeflated) || !seekable_) { + cdr.gpb_flags |= kGPBDDFlagMask; + } cdr.compression_method = file.compression_method; cdr.last_mod_time = file.last_mod_time; cdr.last_mod_date = file.last_mod_date;