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