From e0eca55fe6e36a8ae975be6cbb5a7932b30ba0c1 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. 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 c2055b7f5..779ef2fb9 100644 --- a/libziparchive/zip_archive.cc +++ b/libziparchive/zip_archive.cc @@ -573,6 +573,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;