• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2008 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *    http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 /*
18  * Read-only access to Zip archives, with minimal heap allocation.
19  */
20 
21 #include <assert.h>
22 #include <errno.h>
23 #include <fcntl.h>
24 #include <inttypes.h>
25 #include <limits.h>
26 #include <stdlib.h>
27 #include <string.h>
28 #include <unistd.h>
29 
30 #include <memory>
31 #include <vector>
32 
33 #include "android-base/file.h"
34 #include "android-base/macros.h"  // TEMP_FAILURE_RETRY may or may not be in unistd
35 #include "android-base/memory.h"
36 #include "log/log.h"
37 #include "utils/Compat.h"
38 #include "utils/FileMap.h"
39 #include "ziparchive/zip_archive.h"
40 #include "zlib.h"
41 
42 #include "entry_name_utils-inl.h"
43 #include "zip_archive_common.h"
44 #include "zip_archive_private.h"
45 
46 using android::base::get_unaligned;
47 
48 // This is for windows. If we don't open a file in binary mode, weird
49 // things will happen.
50 #ifndef O_BINARY
51 #define O_BINARY 0
52 #endif
53 
54 // The maximum number of bytes to scan backwards for the EOCD start.
55 static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord);
56 
57 static const char* kErrorMessages[] = {
58   "Unknown return code.",
59   "Iteration ended",
60   "Zlib error",
61   "Invalid file",
62   "Invalid handle",
63   "Duplicate entries in archive",
64   "Empty archive",
65   "Entry not found",
66   "Invalid offset",
67   "Inconsistent information",
68   "Invalid entry name",
69   "I/O Error",
70   "File mapping failed"
71 };
72 
73 static const int32_t kErrorMessageUpperBound = 0;
74 
75 static const int32_t kIterationEnd = -1;
76 
77 // We encountered a Zlib error when inflating a stream from this file.
78 // Usually indicates file corruption.
79 static const int32_t kZlibError = -2;
80 
81 // The input file cannot be processed as a zip archive. Usually because
82 // it's too small, too large or does not have a valid signature.
83 static const int32_t kInvalidFile = -3;
84 
85 // An invalid iteration / ziparchive handle was passed in as an input
86 // argument.
87 static const int32_t kInvalidHandle = -4;
88 
89 // The zip archive contained two (or possibly more) entries with the same
90 // name.
91 static const int32_t kDuplicateEntry = -5;
92 
93 // The zip archive contains no entries.
94 static const int32_t kEmptyArchive = -6;
95 
96 // The specified entry was not found in the archive.
97 static const int32_t kEntryNotFound = -7;
98 
99 // The zip archive contained an invalid local file header pointer.
100 static const int32_t kInvalidOffset = -8;
101 
102 // The zip archive contained inconsistent entry information. This could
103 // be because the central directory & local file header did not agree, or
104 // if the actual uncompressed length or crc32 do not match their declared
105 // values.
106 static const int32_t kInconsistentInformation = -9;
107 
108 // An invalid entry name was encountered.
109 static const int32_t kInvalidEntryName = -10;
110 
111 // An I/O related system call (read, lseek, ftruncate, map) failed.
112 static const int32_t kIoError = -11;
113 
114 // We were not able to mmap the central directory or entry contents.
115 static const int32_t kMmapFailed = -12;
116 
117 static const int32_t kErrorMessageLowerBound = -13;
118 
119 /*
120  * A Read-only Zip archive.
121  *
122  * We want "open" and "find entry by name" to be fast operations, and
123  * we want to use as little memory as possible.  We memory-map the zip
124  * central directory, and load a hash table with pointers to the filenames
125  * (which aren't null-terminated).  The other fields are at a fixed offset
126  * from the filename, so we don't need to extract those (but we do need
127  * to byte-read and endian-swap them every time we want them).
128  *
129  * It's possible that somebody has handed us a massive (~1GB) zip archive,
130  * so we can't expect to mmap the entire file.
131  *
132  * To speed comparisons when doing a lookup by name, we could make the mapping
133  * "private" (copy-on-write) and null-terminate the filenames after verifying
134  * the record structure.  However, this requires a private mapping of
135  * every page that the Central Directory touches.  Easier to tuck a copy
136  * of the string length into the hash table entry.
137  */
138 
139 /*
140  * Round up to the next highest power of 2.
141  *
142  * Found on http://graphics.stanford.edu/~seander/bithacks.html.
143  */
RoundUpPower2(uint32_t val)144 static uint32_t RoundUpPower2(uint32_t val) {
145   val--;
146   val |= val >> 1;
147   val |= val >> 2;
148   val |= val >> 4;
149   val |= val >> 8;
150   val |= val >> 16;
151   val++;
152 
153   return val;
154 }
155 
ComputeHash(const ZipString & name)156 static uint32_t ComputeHash(const ZipString& name) {
157   uint32_t hash = 0;
158   uint16_t len = name.name_length;
159   const uint8_t* str = name.name;
160 
161   while (len--) {
162     hash = hash * 31 + *str++;
163   }
164 
165   return hash;
166 }
167 
168 /*
169  * Convert a ZipEntry to a hash table index, verifying that it's in a
170  * valid range.
171  */
EntryToIndex(const ZipString * hash_table,const uint32_t hash_table_size,const ZipString & name)172 static int64_t EntryToIndex(const ZipString* hash_table,
173                             const uint32_t hash_table_size,
174                             const ZipString& name) {
175   const uint32_t hash = ComputeHash(name);
176 
177   // NOTE: (hash_table_size - 1) is guaranteed to be non-negative.
178   uint32_t ent = hash & (hash_table_size - 1);
179   while (hash_table[ent].name != NULL) {
180     if (hash_table[ent] == name) {
181       return ent;
182     }
183 
184     ent = (ent + 1) & (hash_table_size - 1);
185   }
186 
187   ALOGV("Zip: Unable to find entry %.*s", name.name_length, name.name);
188   return kEntryNotFound;
189 }
190 
191 /*
192  * Add a new entry to the hash table.
193  */
AddToHash(ZipString * hash_table,const uint64_t hash_table_size,const ZipString & name)194 static int32_t AddToHash(ZipString *hash_table, const uint64_t hash_table_size,
195                          const ZipString& name) {
196   const uint64_t hash = ComputeHash(name);
197   uint32_t ent = hash & (hash_table_size - 1);
198 
199   /*
200    * We over-allocated the table, so we're guaranteed to find an empty slot.
201    * Further, we guarantee that the hashtable size is not 0.
202    */
203   while (hash_table[ent].name != NULL) {
204     if (hash_table[ent] == name) {
205       // We've found a duplicate entry. We don't accept it
206       ALOGW("Zip: Found duplicate entry %.*s", name.name_length, name.name);
207       return kDuplicateEntry;
208     }
209     ent = (ent + 1) & (hash_table_size - 1);
210   }
211 
212   hash_table[ent].name = name.name;
213   hash_table[ent].name_length = name.name_length;
214   return 0;
215 }
216 
MapCentralDirectory0(int fd,const char * debug_file_name,ZipArchive * archive,off64_t file_length,off64_t read_amount,uint8_t * scan_buffer)217 static int32_t MapCentralDirectory0(int fd, const char* debug_file_name,
218                                     ZipArchive* archive, off64_t file_length,
219                                     off64_t read_amount, uint8_t* scan_buffer) {
220   const off64_t search_start = file_length - read_amount;
221 
222   if (lseek64(fd, search_start, SEEK_SET) != search_start) {
223     ALOGW("Zip: seek %" PRId64 " failed: %s", static_cast<int64_t>(search_start),
224           strerror(errno));
225     return kIoError;
226   }
227   if (!android::base::ReadFully(fd, scan_buffer, static_cast<size_t>(read_amount))) {
228     ALOGW("Zip: read %" PRId64 " failed: %s", static_cast<int64_t>(read_amount),
229           strerror(errno));
230     return kIoError;
231   }
232 
233   /*
234    * Scan backward for the EOCD magic.  In an archive without a trailing
235    * comment, we'll find it on the first try.  (We may want to consider
236    * doing an initial minimal read; if we don't find it, retry with a
237    * second read as above.)
238    */
239   int i = read_amount - sizeof(EocdRecord);
240   for (; i >= 0; i--) {
241     if (scan_buffer[i] == 0x50) {
242       uint32_t* sig_addr = reinterpret_cast<uint32_t*>(&scan_buffer[i]);
243       if (get_unaligned<uint32_t>(sig_addr) == EocdRecord::kSignature) {
244         ALOGV("+++ Found EOCD at buf+%d", i);
245         break;
246       }
247     }
248   }
249   if (i < 0) {
250     ALOGD("Zip: EOCD not found, %s is not zip", debug_file_name);
251     return kInvalidFile;
252   }
253 
254   const off64_t eocd_offset = search_start + i;
255   const EocdRecord* eocd = reinterpret_cast<const EocdRecord*>(scan_buffer + i);
256   /*
257    * Verify that there's no trailing space at the end of the central directory
258    * and its comment.
259    */
260   const off64_t calculated_length = eocd_offset + sizeof(EocdRecord)
261       + eocd->comment_length;
262   if (calculated_length != file_length) {
263     ALOGW("Zip: %" PRId64 " extraneous bytes at the end of the central directory",
264           static_cast<int64_t>(file_length - calculated_length));
265     return kInvalidFile;
266   }
267 
268   /*
269    * Grab the CD offset and size, and the number of entries in the
270    * archive and verify that they look reasonable.
271    */
272   if (static_cast<off64_t>(eocd->cd_start_offset) + eocd->cd_size > eocd_offset) {
273     ALOGW("Zip: bad offsets (dir %" PRIu32 ", size %" PRIu32 ", eocd %" PRId64 ")",
274         eocd->cd_start_offset, eocd->cd_size, static_cast<int64_t>(eocd_offset));
275 #if defined(__ANDROID__)
276     if (eocd->cd_start_offset + eocd->cd_size <= eocd_offset) {
277       android_errorWriteLog(0x534e4554, "31251826");
278     }
279 #endif
280     return kInvalidOffset;
281   }
282   if (eocd->num_records == 0) {
283     ALOGW("Zip: empty archive?");
284     return kEmptyArchive;
285   }
286 
287   ALOGV("+++ num_entries=%" PRIu32 " dir_size=%" PRIu32 " dir_offset=%" PRIu32,
288         eocd->num_records, eocd->cd_size, eocd->cd_start_offset);
289 
290   /*
291    * It all looks good.  Create a mapping for the CD, and set the fields
292    * in archive.
293    */
294   if (!archive->directory_map.create(debug_file_name, fd,
295           static_cast<off64_t>(eocd->cd_start_offset),
296           static_cast<size_t>(eocd->cd_size), true /* read only */) ) {
297     return kMmapFailed;
298   }
299 
300   archive->num_entries = eocd->num_records;
301   archive->directory_offset = eocd->cd_start_offset;
302 
303   return 0;
304 }
305 
306 /*
307  * Find the zip Central Directory and memory-map it.
308  *
309  * On success, returns 0 after populating fields from the EOCD area:
310  *   directory_offset
311  *   directory_map
312  *   num_entries
313  */
MapCentralDirectory(int fd,const char * debug_file_name,ZipArchive * archive)314 static int32_t MapCentralDirectory(int fd, const char* debug_file_name,
315                                    ZipArchive* archive) {
316 
317   // Test file length. We use lseek64 to make sure the file
318   // is small enough to be a zip file (Its size must be less than
319   // 0xffffffff bytes).
320   off64_t file_length = lseek64(fd, 0, SEEK_END);
321   if (file_length == -1) {
322     ALOGV("Zip: lseek on fd %d failed", fd);
323     return kInvalidFile;
324   }
325 
326   if (file_length > static_cast<off64_t>(0xffffffff)) {
327     ALOGV("Zip: zip file too long %" PRId64, static_cast<int64_t>(file_length));
328     return kInvalidFile;
329   }
330 
331   if (file_length < static_cast<off64_t>(sizeof(EocdRecord))) {
332     ALOGV("Zip: length %" PRId64 " is too small to be zip", static_cast<int64_t>(file_length));
333     return kInvalidFile;
334   }
335 
336   /*
337    * Perform the traditional EOCD snipe hunt.
338    *
339    * We're searching for the End of Central Directory magic number,
340    * which appears at the start of the EOCD block.  It's followed by
341    * 18 bytes of EOCD stuff and up to 64KB of archive comment.  We
342    * need to read the last part of the file into a buffer, dig through
343    * it to find the magic number, parse some values out, and use those
344    * to determine the extent of the CD.
345    *
346    * We start by pulling in the last part of the file.
347    */
348   off64_t read_amount = kMaxEOCDSearch;
349   if (file_length < read_amount) {
350     read_amount = file_length;
351   }
352 
353   uint8_t* scan_buffer = reinterpret_cast<uint8_t*>(malloc(read_amount));
354   int32_t result = MapCentralDirectory0(fd, debug_file_name, archive,
355                                         file_length, read_amount, scan_buffer);
356 
357   free(scan_buffer);
358   return result;
359 }
360 
361 /*
362  * Parses the Zip archive's Central Directory.  Allocates and populates the
363  * hash table.
364  *
365  * Returns 0 on success.
366  */
ParseZipArchive(ZipArchive * archive)367 static int32_t ParseZipArchive(ZipArchive* archive) {
368   const uint8_t* const cd_ptr =
369       reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr());
370   const size_t cd_length = archive->directory_map.getDataLength();
371   const uint16_t num_entries = archive->num_entries;
372 
373   /*
374    * Create hash table.  We have a minimum 75% load factor, possibly as
375    * low as 50% after we round off to a power of 2.  There must be at
376    * least one unused entry to avoid an infinite loop during creation.
377    */
378   archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3);
379   archive->hash_table = reinterpret_cast<ZipString*>(calloc(archive->hash_table_size,
380       sizeof(ZipString)));
381 
382   /*
383    * Walk through the central directory, adding entries to the hash
384    * table and verifying values.
385    */
386   const uint8_t* const cd_end = cd_ptr + cd_length;
387   const uint8_t* ptr = cd_ptr;
388   for (uint16_t i = 0; i < num_entries; i++) {
389     if (ptr > cd_end - sizeof(CentralDirectoryRecord)) {
390       ALOGW("Zip: ran off the end (at %" PRIu16 ")", i);
391 #if defined(__ANDROID__)
392       android_errorWriteLog(0x534e4554, "36392138");
393 #endif
394       return -1;
395     }
396 
397     const CentralDirectoryRecord* cdr =
398         reinterpret_cast<const CentralDirectoryRecord*>(ptr);
399     if (cdr->record_signature != CentralDirectoryRecord::kSignature) {
400       ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i);
401       return -1;
402     }
403 
404     const off64_t local_header_offset = cdr->local_file_header_offset;
405     if (local_header_offset >= archive->directory_offset) {
406       ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16,
407           static_cast<int64_t>(local_header_offset), i);
408       return -1;
409     }
410 
411     const uint16_t file_name_length = cdr->file_name_length;
412     const uint16_t extra_length = cdr->extra_field_length;
413     const uint16_t comment_length = cdr->comment_length;
414     const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord);
415 
416     /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */
417     if (!IsValidEntryName(file_name, file_name_length)) {
418       return -1;
419     }
420 
421     /* add the CDE filename to the hash table */
422     ZipString entry_name;
423     entry_name.name = file_name;
424     entry_name.name_length = file_name_length;
425     const int add_result = AddToHash(archive->hash_table,
426         archive->hash_table_size, entry_name);
427     if (add_result != 0) {
428       ALOGW("Zip: Error adding entry to hash table %d", add_result);
429       return add_result;
430     }
431 
432     ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length;
433     if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) {
434       ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16,
435           ptr - cd_ptr, cd_length, i);
436       return -1;
437     }
438   }
439   ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries);
440 
441   return 0;
442 }
443 
OpenArchiveInternal(ZipArchive * archive,const char * debug_file_name)444 static int32_t OpenArchiveInternal(ZipArchive* archive,
445                                    const char* debug_file_name) {
446   int32_t result = -1;
447   if ((result = MapCentralDirectory(archive->fd, debug_file_name, archive))) {
448     return result;
449   }
450 
451   if ((result = ParseZipArchive(archive))) {
452     return result;
453   }
454 
455   return 0;
456 }
457 
OpenArchiveFd(int fd,const char * debug_file_name,ZipArchiveHandle * handle,bool assume_ownership)458 int32_t OpenArchiveFd(int fd, const char* debug_file_name,
459                       ZipArchiveHandle* handle, bool assume_ownership) {
460   ZipArchive* archive = new ZipArchive(fd, assume_ownership);
461   *handle = archive;
462   return OpenArchiveInternal(archive, debug_file_name);
463 }
464 
OpenArchive(const char * fileName,ZipArchiveHandle * handle)465 int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) {
466   const int fd = open(fileName, O_RDONLY | O_BINARY, 0);
467   ZipArchive* archive = new ZipArchive(fd, true);
468   *handle = archive;
469 
470   if (fd < 0) {
471     ALOGW("Unable to open '%s': %s", fileName, strerror(errno));
472     return kIoError;
473   }
474 
475   return OpenArchiveInternal(archive, fileName);
476 }
477 
478 /*
479  * Close a ZipArchive, closing the file and freeing the contents.
480  */
CloseArchive(ZipArchiveHandle handle)481 void CloseArchive(ZipArchiveHandle handle) {
482   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
483   ALOGV("Closing archive %p", archive);
484   delete archive;
485 }
486 
UpdateEntryFromDataDescriptor(int fd,ZipEntry * entry)487 static int32_t UpdateEntryFromDataDescriptor(int fd,
488                                              ZipEntry *entry) {
489   uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)];
490   if (!android::base::ReadFully(fd, ddBuf, sizeof(ddBuf))) {
491     return kIoError;
492   }
493 
494   const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf));
495   const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0;
496   const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset);
497 
498   entry->crc32 = descriptor->crc32;
499   entry->compressed_length = descriptor->compressed_size;
500   entry->uncompressed_length = descriptor->uncompressed_size;
501 
502   return 0;
503 }
504 
505 // Attempts to read |len| bytes into |buf| at offset |off|.
506 // On non-Windows platforms, callers are guaranteed that the |fd|
507 // offset is unchanged and there is no side effect to this call.
508 //
509 // On Windows platforms this is not thread-safe.
ReadAtOffset(int fd,uint8_t * buf,size_t len,off64_t off)510 static inline bool ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off) {
511 #if !defined(_WIN32)
512   return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off));
513 #else
514   if (lseek64(fd, off, SEEK_SET) != off) {
515     ALOGW("Zip: failed seek to offset %" PRId64, off);
516     return false;
517   }
518   return android::base::ReadFully(fd, buf, len);
519 #endif
520 }
521 
FindEntry(const ZipArchive * archive,const int ent,ZipEntry * data)522 static int32_t FindEntry(const ZipArchive* archive, const int ent,
523                          ZipEntry* data) {
524   const uint16_t nameLen = archive->hash_table[ent].name_length;
525 
526   // Recover the start of the central directory entry from the filename
527   // pointer.  The filename is the first entry past the fixed-size data,
528   // so we can just subtract back from that.
529   const uint8_t* ptr = archive->hash_table[ent].name;
530   ptr -= sizeof(CentralDirectoryRecord);
531 
532   // This is the base of our mmapped region, we have to sanity check that
533   // the name that's in the hash table is a pointer to a location within
534   // this mapped region.
535   const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>(
536     archive->directory_map.getDataPtr());
537   if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) {
538     ALOGW("Zip: Invalid entry pointer");
539     return kInvalidOffset;
540   }
541 
542   const CentralDirectoryRecord *cdr =
543       reinterpret_cast<const CentralDirectoryRecord*>(ptr);
544 
545   // The offset of the start of the central directory in the zipfile.
546   // We keep this lying around so that we can sanity check all our lengths
547   // and our per-file structures.
548   const off64_t cd_offset = archive->directory_offset;
549 
550   // Fill out the compression method, modification time, crc32
551   // and other interesting attributes from the central directory. These
552   // will later be compared against values from the local file header.
553   data->method = cdr->compression_method;
554   data->mod_time = cdr->last_mod_date << 16 | cdr->last_mod_time;
555   data->crc32 = cdr->crc32;
556   data->compressed_length = cdr->compressed_size;
557   data->uncompressed_length = cdr->uncompressed_size;
558 
559   // Figure out the local header offset from the central directory. The
560   // actual file data will begin after the local header and the name /
561   // extra comments.
562   const off64_t local_header_offset = cdr->local_file_header_offset;
563   if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) {
564     ALOGW("Zip: bad local hdr offset in zip");
565     return kInvalidOffset;
566   }
567 
568   uint8_t lfh_buf[sizeof(LocalFileHeader)];
569   if (!ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf), local_header_offset)) {
570     ALOGW("Zip: failed reading lfh name from offset %" PRId64,
571         static_cast<int64_t>(local_header_offset));
572     return kIoError;
573   }
574 
575   const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf);
576 
577   if (lfh->lfh_signature != LocalFileHeader::kSignature) {
578     ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64,
579         static_cast<int64_t>(local_header_offset));
580     return kInvalidOffset;
581   }
582 
583   // Paranoia: Match the values specified in the local file header
584   // to those specified in the central directory.
585   if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) {
586     data->has_data_descriptor = 0;
587     if (data->compressed_length != lfh->compressed_size
588         || data->uncompressed_length != lfh->uncompressed_size
589         || data->crc32 != lfh->crc32) {
590       ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32
591         ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}",
592         data->compressed_length, data->uncompressed_length, data->crc32,
593         lfh->compressed_size, lfh->uncompressed_size, lfh->crc32);
594       return kInconsistentInformation;
595     }
596   } else {
597     data->has_data_descriptor = 1;
598   }
599 
600   // Check that the local file header name matches the declared
601   // name in the central directory.
602   if (lfh->file_name_length == nameLen) {
603     const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader);
604     if (name_offset + lfh->file_name_length > cd_offset) {
605       ALOGW("Zip: Invalid declared length");
606       return kInvalidOffset;
607     }
608 
609     uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen));
610     if (!ReadAtOffset(archive->fd, name_buf, nameLen, name_offset)) {
611       ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset));
612       free(name_buf);
613       return kIoError;
614     }
615 
616     if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) {
617       free(name_buf);
618       return kInconsistentInformation;
619     }
620 
621     free(name_buf);
622   } else {
623     ALOGW("Zip: lfh name did not match central directory.");
624     return kInconsistentInformation;
625   }
626 
627   const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader)
628       + lfh->file_name_length + lfh->extra_field_length;
629   if (data_offset > cd_offset) {
630     ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset));
631     return kInvalidOffset;
632   }
633 
634   if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) {
635     ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
636       static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset));
637     return kInvalidOffset;
638   }
639 
640   if (data->method == kCompressStored &&
641     static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) {
642      ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")",
643        static_cast<int64_t>(data_offset), data->uncompressed_length,
644        static_cast<int64_t>(cd_offset));
645      return kInvalidOffset;
646   }
647 
648   data->offset = data_offset;
649   return 0;
650 }
651 
652 struct IterationHandle {
653   uint32_t position;
654   // We're not using vector here because this code is used in the Windows SDK
655   // where the STL is not available.
656   ZipString prefix;
657   ZipString suffix;
658   ZipArchive* archive;
659 
IterationHandleIterationHandle660   IterationHandle(const ZipString* in_prefix,
661                   const ZipString* in_suffix) {
662     if (in_prefix) {
663       uint8_t* name_copy = new uint8_t[in_prefix->name_length];
664       memcpy(name_copy, in_prefix->name, in_prefix->name_length);
665       prefix.name = name_copy;
666       prefix.name_length = in_prefix->name_length;
667     } else {
668       prefix.name = NULL;
669       prefix.name_length = 0;
670     }
671     if (in_suffix) {
672       uint8_t* name_copy = new uint8_t[in_suffix->name_length];
673       memcpy(name_copy, in_suffix->name, in_suffix->name_length);
674       suffix.name = name_copy;
675       suffix.name_length = in_suffix->name_length;
676     } else {
677       suffix.name = NULL;
678       suffix.name_length = 0;
679     }
680   }
681 
~IterationHandleIterationHandle682   ~IterationHandle() {
683     delete[] prefix.name;
684     delete[] suffix.name;
685   }
686 };
687 
StartIteration(ZipArchiveHandle handle,void ** cookie_ptr,const ZipString * optional_prefix,const ZipString * optional_suffix)688 int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr,
689                        const ZipString* optional_prefix,
690                        const ZipString* optional_suffix) {
691   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
692 
693   if (archive == NULL || archive->hash_table == NULL) {
694     ALOGW("Zip: Invalid ZipArchiveHandle");
695     return kInvalidHandle;
696   }
697 
698   IterationHandle* cookie = new IterationHandle(optional_prefix, optional_suffix);
699   cookie->position = 0;
700   cookie->archive = archive;
701 
702   *cookie_ptr = cookie ;
703   return 0;
704 }
705 
EndIteration(void * cookie)706 void EndIteration(void* cookie) {
707   delete reinterpret_cast<IterationHandle*>(cookie);
708 }
709 
FindEntry(const ZipArchiveHandle handle,const ZipString & entryName,ZipEntry * data)710 int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName,
711                   ZipEntry* data) {
712   const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
713   if (entryName.name_length == 0) {
714     ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name);
715     return kInvalidEntryName;
716   }
717 
718   const int64_t ent = EntryToIndex(archive->hash_table,
719     archive->hash_table_size, entryName);
720 
721   if (ent < 0) {
722     ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name);
723     return ent;
724   }
725 
726   return FindEntry(archive, ent, data);
727 }
728 
Next(void * cookie,ZipEntry * data,ZipString * name)729 int32_t Next(void* cookie, ZipEntry* data, ZipString* name) {
730   IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie);
731   if (handle == NULL) {
732     return kInvalidHandle;
733   }
734 
735   ZipArchive* archive = handle->archive;
736   if (archive == NULL || archive->hash_table == NULL) {
737     ALOGW("Zip: Invalid ZipArchiveHandle");
738     return kInvalidHandle;
739   }
740 
741   const uint32_t currentOffset = handle->position;
742   const uint32_t hash_table_length = archive->hash_table_size;
743   const ZipString* hash_table = archive->hash_table;
744 
745   for (uint32_t i = currentOffset; i < hash_table_length; ++i) {
746     if (hash_table[i].name != NULL &&
747         (handle->prefix.name_length == 0 ||
748          hash_table[i].StartsWith(handle->prefix)) &&
749         (handle->suffix.name_length == 0 ||
750          hash_table[i].EndsWith(handle->suffix))) {
751       handle->position = (i + 1);
752       const int error = FindEntry(archive, i, data);
753       if (!error) {
754         name->name = hash_table[i].name;
755         name->name_length = hash_table[i].name_length;
756       }
757 
758       return error;
759     }
760   }
761 
762   handle->position = 0;
763   return kIterationEnd;
764 }
765 
766 class Writer {
767  public:
768   virtual bool Append(uint8_t* buf, size_t buf_size) = 0;
~Writer()769   virtual ~Writer() {}
770  protected:
771   Writer() = default;
772  private:
773   DISALLOW_COPY_AND_ASSIGN(Writer);
774 };
775 
776 // A Writer that writes data to a fixed size memory region.
777 // The size of the memory region must be equal to the total size of
778 // the data appended to it.
779 class MemoryWriter : public Writer {
780  public:
MemoryWriter(uint8_t * buf,size_t size)781   MemoryWriter(uint8_t* buf, size_t size) : Writer(),
782       buf_(buf), size_(size), bytes_written_(0) {
783   }
784 
Append(uint8_t * buf,size_t buf_size)785   virtual bool Append(uint8_t* buf, size_t buf_size) override {
786     if (bytes_written_ + buf_size > size_) {
787       ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
788             size_, bytes_written_ + buf_size);
789       return false;
790     }
791 
792     memcpy(buf_ + bytes_written_, buf, buf_size);
793     bytes_written_ += buf_size;
794     return true;
795   }
796 
797  private:
798   uint8_t* const buf_;
799   const size_t size_;
800   size_t bytes_written_;
801 };
802 
803 // A Writer that appends data to a file |fd| at its current position.
804 // The file will be truncated to the end of the written data.
805 class FileWriter : public Writer {
806  public:
807 
808   // Creates a FileWriter for |fd| and prepare to write |entry| to it,
809   // guaranteeing that the file descriptor is valid and that there's enough
810   // space on the volume to write out the entry completely and that the file
811   // is truncated to the correct length.
812   //
813   // Returns a valid FileWriter on success, |nullptr| if an error occurred.
Create(int fd,const ZipEntry * entry)814   static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) {
815     const uint32_t declared_length = entry->uncompressed_length;
816     const off64_t current_offset = lseek64(fd, 0, SEEK_CUR);
817     if (current_offset == -1) {
818       ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno));
819       return nullptr;
820     }
821 
822     int result = 0;
823 #if defined(__linux__)
824     if (declared_length > 0) {
825       // Make sure we have enough space on the volume to extract the compressed
826       // entry. Note that the call to ftruncate below will change the file size but
827       // will not allocate space on disk and this call to fallocate will not
828       // change the file size.
829       // Note: fallocate is only supported by the following filesystems -
830       // btrfs, ext4, ocfs2, and xfs. Therefore fallocate might fail with
831       // EOPNOTSUPP error when issued in other filesystems.
832       // Hence, check for the return error code before concluding that the
833       // disk does not have enough space.
834       result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length));
835       if (result == -1 && errno == ENOSPC) {
836         ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s",
837               static_cast<int64_t>(declared_length + current_offset), strerror(errno));
838         return std::unique_ptr<FileWriter>(nullptr);
839       }
840     }
841 #endif  // __linux__
842 
843     result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset));
844     if (result == -1) {
845       ALOGW("Zip: unable to truncate file to %" PRId64 ": %s",
846             static_cast<int64_t>(declared_length + current_offset), strerror(errno));
847       return std::unique_ptr<FileWriter>(nullptr);
848     }
849 
850     return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length));
851   }
852 
Append(uint8_t * buf,size_t buf_size)853   virtual bool Append(uint8_t* buf, size_t buf_size) override {
854     if (total_bytes_written_ + buf_size > declared_length_) {
855       ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)",
856             declared_length_, total_bytes_written_ + buf_size);
857       return false;
858     }
859 
860     const bool result = android::base::WriteFully(fd_, buf, buf_size);
861     if (result) {
862       total_bytes_written_ += buf_size;
863     } else {
864       ALOGW("Zip: unable to write " ZD " bytes to file; %s", buf_size, strerror(errno));
865     }
866 
867     return result;
868   }
869  private:
FileWriter(const int fd,const size_t declared_length)870   FileWriter(const int fd, const size_t declared_length) :
871       Writer(),
872       fd_(fd),
873       declared_length_(declared_length),
874       total_bytes_written_(0) {
875   }
876 
877   const int fd_;
878   const size_t declared_length_;
879   size_t total_bytes_written_;
880 };
881 
882 // This method is using libz macros with old-style-casts
883 #pragma GCC diagnostic push
884 #pragma GCC diagnostic ignored "-Wold-style-cast"
zlib_inflateInit2(z_stream * stream,int window_bits)885 static inline int zlib_inflateInit2(z_stream* stream, int window_bits) {
886   return inflateInit2(stream, window_bits);
887 }
888 #pragma GCC diagnostic pop
889 
InflateEntryToWriter(int fd,const ZipEntry * entry,Writer * writer,uint64_t * crc_out)890 static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry,
891                                     Writer* writer, uint64_t* crc_out) {
892   const size_t kBufSize = 32768;
893   std::vector<uint8_t> read_buf(kBufSize);
894   std::vector<uint8_t> write_buf(kBufSize);
895   z_stream zstream;
896   int zerr;
897 
898   /*
899    * Initialize the zlib stream struct.
900    */
901   memset(&zstream, 0, sizeof(zstream));
902   zstream.zalloc = Z_NULL;
903   zstream.zfree = Z_NULL;
904   zstream.opaque = Z_NULL;
905   zstream.next_in = NULL;
906   zstream.avail_in = 0;
907   zstream.next_out = &write_buf[0];
908   zstream.avail_out = kBufSize;
909   zstream.data_type = Z_UNKNOWN;
910 
911   /*
912    * Use the undocumented "negative window bits" feature to tell zlib
913    * that there's no zlib header waiting for it.
914    */
915   zerr = zlib_inflateInit2(&zstream, -MAX_WBITS);
916   if (zerr != Z_OK) {
917     if (zerr == Z_VERSION_ERROR) {
918       ALOGE("Installed zlib is not compatible with linked version (%s)",
919         ZLIB_VERSION);
920     } else {
921       ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr);
922     }
923 
924     return kZlibError;
925   }
926 
927   auto zstream_deleter = [](z_stream* stream) {
928     inflateEnd(stream);  /* free up any allocated structures */
929   };
930 
931   std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter);
932 
933   const uint32_t uncompressed_length = entry->uncompressed_length;
934 
935   uint32_t compressed_length = entry->compressed_length;
936   do {
937     /* read as much as we can */
938     if (zstream.avail_in == 0) {
939       const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length;
940       if (!android::base::ReadFully(fd, read_buf.data(), getSize)) {
941         ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno));
942         return kIoError;
943       }
944 
945       compressed_length -= getSize;
946 
947       zstream.next_in = &read_buf[0];
948       zstream.avail_in = getSize;
949     }
950 
951     /* uncompress the data */
952     zerr = inflate(&zstream, Z_NO_FLUSH);
953     if (zerr != Z_OK && zerr != Z_STREAM_END) {
954       ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)",
955           zerr, zstream.next_in, zstream.avail_in,
956           zstream.next_out, zstream.avail_out);
957       return kZlibError;
958     }
959 
960     /* write when we're full or when we're done */
961     if (zstream.avail_out == 0 ||
962       (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) {
963       const size_t write_size = zstream.next_out - &write_buf[0];
964       if (!writer->Append(&write_buf[0], write_size)) {
965         // The file might have declared a bogus length.
966         return kInconsistentInformation;
967       }
968 
969       zstream.next_out = &write_buf[0];
970       zstream.avail_out = kBufSize;
971     }
972   } while (zerr == Z_OK);
973 
974   assert(zerr == Z_STREAM_END);     /* other errors should've been caught */
975 
976   // stream.adler holds the crc32 value for such streams.
977   *crc_out = zstream.adler;
978 
979   if (zstream.total_out != uncompressed_length || compressed_length != 0) {
980     ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")",
981         zstream.total_out, uncompressed_length);
982     return kInconsistentInformation;
983   }
984 
985   return 0;
986 }
987 
CopyEntryToWriter(int fd,const ZipEntry * entry,Writer * writer,uint64_t * crc_out)988 static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer,
989                                  uint64_t *crc_out) {
990   static const uint32_t kBufSize = 32768;
991   std::vector<uint8_t> buf(kBufSize);
992 
993   const uint32_t length = entry->uncompressed_length;
994   uint32_t count = 0;
995   uint64_t crc = 0;
996   while (count < length) {
997     uint32_t remaining = length - count;
998 
999     // Safe conversion because kBufSize is narrow enough for a 32 bit signed
1000     // value.
1001     const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining;
1002     if (!android::base::ReadFully(fd, buf.data(), block_size)) {
1003       ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno));
1004       return kIoError;
1005     }
1006 
1007     if (!writer->Append(&buf[0], block_size)) {
1008       return kIoError;
1009     }
1010     crc = crc32(crc, &buf[0], block_size);
1011     count += block_size;
1012   }
1013 
1014   *crc_out = crc;
1015 
1016   return 0;
1017 }
1018 
ExtractToWriter(ZipArchiveHandle handle,ZipEntry * entry,Writer * writer)1019 int32_t ExtractToWriter(ZipArchiveHandle handle,
1020                         ZipEntry* entry, Writer* writer) {
1021   ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle);
1022   const uint16_t method = entry->method;
1023   off64_t data_offset = entry->offset;
1024 
1025   if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) {
1026     ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset));
1027     return kIoError;
1028   }
1029 
1030   // this should default to kUnknownCompressionMethod.
1031   int32_t return_value = -1;
1032   uint64_t crc = 0;
1033   if (method == kCompressStored) {
1034     return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc);
1035   } else if (method == kCompressDeflated) {
1036     return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc);
1037   }
1038 
1039   if (!return_value && entry->has_data_descriptor) {
1040     return_value = UpdateEntryFromDataDescriptor(archive->fd, entry);
1041     if (return_value) {
1042       return return_value;
1043     }
1044   }
1045 
1046   // TODO: Fix this check by passing the right flags to inflate2 so that
1047   // it calculates the CRC for us.
1048   if (entry->crc32 != crc && false) {
1049     ALOGW("Zip: crc mismatch: expected %" PRIu32 ", was %" PRIu64, entry->crc32, crc);
1050     return kInconsistentInformation;
1051   }
1052 
1053   return return_value;
1054 }
1055 
ExtractToMemory(ZipArchiveHandle handle,ZipEntry * entry,uint8_t * begin,uint32_t size)1056 int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry,
1057                         uint8_t* begin, uint32_t size) {
1058   std::unique_ptr<Writer> writer(new MemoryWriter(begin, size));
1059   return ExtractToWriter(handle, entry, writer.get());
1060 }
1061 
ExtractEntryToFile(ZipArchiveHandle handle,ZipEntry * entry,int fd)1062 int32_t ExtractEntryToFile(ZipArchiveHandle handle,
1063                            ZipEntry* entry, int fd) {
1064   std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry));
1065   if (writer.get() == nullptr) {
1066     return kIoError;
1067   }
1068 
1069   return ExtractToWriter(handle, entry, writer.get());
1070 }
1071 
ErrorCodeString(int32_t error_code)1072 const char* ErrorCodeString(int32_t error_code) {
1073   if (error_code > kErrorMessageLowerBound && error_code < kErrorMessageUpperBound) {
1074     return kErrorMessages[error_code * -1];
1075   }
1076 
1077   return kErrorMessages[0];
1078 }
1079 
GetFileDescriptor(const ZipArchiveHandle handle)1080 int GetFileDescriptor(const ZipArchiveHandle handle) {
1081   return reinterpret_cast<ZipArchive*>(handle)->fd;
1082 }
1083