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 46using 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. 55static const uint32_t kMaxEOCDSearch = kMaxCommentLen + sizeof(EocdRecord); 56 57static 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 73static const int32_t kErrorMessageUpperBound = 0; 74 75static const int32_t kIterationEnd = -1; 76 77// We encountered a Zlib error when inflating a stream from this file. 78// Usually indicates file corruption. 79static 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. 83static const int32_t kInvalidFile = -3; 84 85// An invalid iteration / ziparchive handle was passed in as an input 86// argument. 87static const int32_t kInvalidHandle = -4; 88 89// The zip archive contained two (or possibly more) entries with the same 90// name. 91static const int32_t kDuplicateEntry = -5; 92 93// The zip archive contains no entries. 94static const int32_t kEmptyArchive = -6; 95 96// The specified entry was not found in the archive. 97static const int32_t kEntryNotFound = -7; 98 99// The zip archive contained an invalid local file header pointer. 100static 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. 106static const int32_t kInconsistentInformation = -9; 107 108// An invalid entry name was encountered. 109static const int32_t kInvalidEntryName = -10; 110 111// An I/O related system call (read, lseek, ftruncate, map) failed. 112static const int32_t kIoError = -11; 113 114// We were not able to mmap the central directory or entry contents. 115static const int32_t kMmapFailed = -12; 116 117static 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 */ 144static 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 156static 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 */ 172static 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 */ 194static 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 217static 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 */ 314static 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 361static inline bool ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off); 362 363/* 364 * Parses the Zip archive's Central Directory. Allocates and populates the 365 * hash table. 366 * 367 * Returns 0 on success. 368 */ 369static int32_t ParseZipArchive(ZipArchive* archive) { 370 const uint8_t* const cd_ptr = 371 reinterpret_cast<const uint8_t*>(archive->directory_map.getDataPtr()); 372 const size_t cd_length = archive->directory_map.getDataLength(); 373 const uint16_t num_entries = archive->num_entries; 374 375 /* 376 * Create hash table. We have a minimum 75% load factor, possibly as 377 * low as 50% after we round off to a power of 2. There must be at 378 * least one unused entry to avoid an infinite loop during creation. 379 */ 380 archive->hash_table_size = RoundUpPower2(1 + (num_entries * 4) / 3); 381 archive->hash_table = reinterpret_cast<ZipString*>(calloc(archive->hash_table_size, 382 sizeof(ZipString))); 383 384 /* 385 * Walk through the central directory, adding entries to the hash 386 * table and verifying values. 387 */ 388 const uint8_t* const cd_end = cd_ptr + cd_length; 389 const uint8_t* ptr = cd_ptr; 390 for (uint16_t i = 0; i < num_entries; i++) { 391 if (ptr > cd_end - sizeof(CentralDirectoryRecord)) { 392 ALOGW("Zip: ran off the end (at %" PRIu16 ")", i); 393#if defined(__ANDROID__) 394 android_errorWriteLog(0x534e4554, "36392138"); 395#endif 396 return -1; 397 } 398 399 const CentralDirectoryRecord* cdr = 400 reinterpret_cast<const CentralDirectoryRecord*>(ptr); 401 if (cdr->record_signature != CentralDirectoryRecord::kSignature) { 402 ALOGW("Zip: missed a central dir sig (at %" PRIu16 ")", i); 403 return -1; 404 } 405 406 const off64_t local_header_offset = cdr->local_file_header_offset; 407 if (local_header_offset >= archive->directory_offset) { 408 ALOGW("Zip: bad LFH offset %" PRId64 " at entry %" PRIu16, 409 static_cast<int64_t>(local_header_offset), i); 410 return -1; 411 } 412 413 const uint16_t file_name_length = cdr->file_name_length; 414 const uint16_t extra_length = cdr->extra_field_length; 415 const uint16_t comment_length = cdr->comment_length; 416 const uint8_t* file_name = ptr + sizeof(CentralDirectoryRecord); 417 418 /* check that file name is valid UTF-8 and doesn't contain NUL (U+0000) characters */ 419 if (!IsValidEntryName(file_name, file_name_length)) { 420 return -1; 421 } 422 423 /* add the CDE filename to the hash table */ 424 ZipString entry_name; 425 entry_name.name = file_name; 426 entry_name.name_length = file_name_length; 427 const int add_result = AddToHash(archive->hash_table, 428 archive->hash_table_size, entry_name); 429 if (add_result != 0) { 430 ALOGW("Zip: Error adding entry to hash table %d", add_result); 431 return add_result; 432 } 433 434 ptr += sizeof(CentralDirectoryRecord) + file_name_length + extra_length + comment_length; 435 if ((ptr - cd_ptr) > static_cast<int64_t>(cd_length)) { 436 ALOGW("Zip: bad CD advance (%tu vs %zu) at entry %" PRIu16, 437 ptr - cd_ptr, cd_length, i); 438 return -1; 439 } 440 } 441 442 uint32_t lfh_start_bytes; 443 if (!ReadAtOffset(archive->fd, reinterpret_cast<uint8_t*>(&lfh_start_bytes), 444 sizeof(uint32_t), 0)) { 445 ALOGW("Zip: Unable to read header for entry at offset == 0."); 446 return -1; 447 } 448 449 if (lfh_start_bytes != LocalFileHeader::kSignature) { 450 ALOGW("Zip: Entry at offset zero has invalid LFH signature %" PRIx32, lfh_start_bytes); 451#if defined(__ANDROID__) 452 android_errorWriteLog(0x534e4554, "64211847"); 453#endif 454 return -1; 455 } 456 457 ALOGV("+++ zip good scan %" PRIu16 " entries", num_entries); 458 459 return 0; 460} 461 462static int32_t OpenArchiveInternal(ZipArchive* archive, 463 const char* debug_file_name) { 464 int32_t result = -1; 465 if ((result = MapCentralDirectory(archive->fd, debug_file_name, archive))) { 466 return result; 467 } 468 469 if ((result = ParseZipArchive(archive))) { 470 return result; 471 } 472 473 return 0; 474} 475 476int32_t OpenArchiveFd(int fd, const char* debug_file_name, 477 ZipArchiveHandle* handle, bool assume_ownership) { 478 ZipArchive* archive = new ZipArchive(fd, assume_ownership); 479 *handle = archive; 480 return OpenArchiveInternal(archive, debug_file_name); 481} 482 483int32_t OpenArchive(const char* fileName, ZipArchiveHandle* handle) { 484 const int fd = open(fileName, O_RDONLY | O_BINARY, 0); 485 ZipArchive* archive = new ZipArchive(fd, true); 486 *handle = archive; 487 488 if (fd < 0) { 489 ALOGW("Unable to open '%s': %s", fileName, strerror(errno)); 490 return kIoError; 491 } 492 493 return OpenArchiveInternal(archive, fileName); 494} 495 496/* 497 * Close a ZipArchive, closing the file and freeing the contents. 498 */ 499void CloseArchive(ZipArchiveHandle handle) { 500 ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); 501 ALOGV("Closing archive %p", archive); 502 delete archive; 503} 504 505static int32_t UpdateEntryFromDataDescriptor(int fd, 506 ZipEntry *entry) { 507 uint8_t ddBuf[sizeof(DataDescriptor) + sizeof(DataDescriptor::kOptSignature)]; 508 if (!android::base::ReadFully(fd, ddBuf, sizeof(ddBuf))) { 509 return kIoError; 510 } 511 512 const uint32_t ddSignature = *(reinterpret_cast<const uint32_t*>(ddBuf)); 513 const uint16_t offset = (ddSignature == DataDescriptor::kOptSignature) ? 4 : 0; 514 const DataDescriptor* descriptor = reinterpret_cast<const DataDescriptor*>(ddBuf + offset); 515 516 entry->crc32 = descriptor->crc32; 517 entry->compressed_length = descriptor->compressed_size; 518 entry->uncompressed_length = descriptor->uncompressed_size; 519 520 return 0; 521} 522 523// Attempts to read |len| bytes into |buf| at offset |off|. 524// On non-Windows platforms, callers are guaranteed that the |fd| 525// offset is unchanged and there is no side effect to this call. 526// 527// On Windows platforms this is not thread-safe. 528static inline bool ReadAtOffset(int fd, uint8_t* buf, size_t len, off64_t off) { 529#if !defined(_WIN32) 530 return TEMP_FAILURE_RETRY(pread64(fd, buf, len, off)); 531#else 532 if (lseek64(fd, off, SEEK_SET) != off) { 533 ALOGW("Zip: failed seek to offset %" PRId64, off); 534 return false; 535 } 536 return android::base::ReadFully(fd, buf, len); 537#endif 538} 539 540static int32_t FindEntry(const ZipArchive* archive, const int ent, 541 ZipEntry* data) { 542 const uint16_t nameLen = archive->hash_table[ent].name_length; 543 544 // Recover the start of the central directory entry from the filename 545 // pointer. The filename is the first entry past the fixed-size data, 546 // so we can just subtract back from that. 547 const uint8_t* ptr = archive->hash_table[ent].name; 548 ptr -= sizeof(CentralDirectoryRecord); 549 550 // This is the base of our mmapped region, we have to sanity check that 551 // the name that's in the hash table is a pointer to a location within 552 // this mapped region. 553 const uint8_t* base_ptr = reinterpret_cast<const uint8_t*>( 554 archive->directory_map.getDataPtr()); 555 if (ptr < base_ptr || ptr > base_ptr + archive->directory_map.getDataLength()) { 556 ALOGW("Zip: Invalid entry pointer"); 557 return kInvalidOffset; 558 } 559 560 const CentralDirectoryRecord *cdr = 561 reinterpret_cast<const CentralDirectoryRecord*>(ptr); 562 563 // The offset of the start of the central directory in the zipfile. 564 // We keep this lying around so that we can sanity check all our lengths 565 // and our per-file structures. 566 const off64_t cd_offset = archive->directory_offset; 567 568 // Fill out the compression method, modification time, crc32 569 // and other interesting attributes from the central directory. These 570 // will later be compared against values from the local file header. 571 data->method = cdr->compression_method; 572 data->mod_time = cdr->last_mod_date << 16 | cdr->last_mod_time; 573 data->crc32 = cdr->crc32; 574 data->compressed_length = cdr->compressed_size; 575 data->uncompressed_length = cdr->uncompressed_size; 576 577 // Figure out the local header offset from the central directory. The 578 // actual file data will begin after the local header and the name / 579 // extra comments. 580 const off64_t local_header_offset = cdr->local_file_header_offset; 581 if (local_header_offset + static_cast<off64_t>(sizeof(LocalFileHeader)) >= cd_offset) { 582 ALOGW("Zip: bad local hdr offset in zip"); 583 return kInvalidOffset; 584 } 585 586 uint8_t lfh_buf[sizeof(LocalFileHeader)]; 587 if (!ReadAtOffset(archive->fd, lfh_buf, sizeof(lfh_buf), local_header_offset)) { 588 ALOGW("Zip: failed reading lfh name from offset %" PRId64, 589 static_cast<int64_t>(local_header_offset)); 590 return kIoError; 591 } 592 593 const LocalFileHeader *lfh = reinterpret_cast<const LocalFileHeader*>(lfh_buf); 594 595 if (lfh->lfh_signature != LocalFileHeader::kSignature) { 596 ALOGW("Zip: didn't find signature at start of lfh, offset=%" PRId64, 597 static_cast<int64_t>(local_header_offset)); 598 return kInvalidOffset; 599 } 600 601 // Paranoia: Match the values specified in the local file header 602 // to those specified in the central directory. 603 if ((lfh->gpb_flags & kGPBDDFlagMask) == 0) { 604 data->has_data_descriptor = 0; 605 if (data->compressed_length != lfh->compressed_size 606 || data->uncompressed_length != lfh->uncompressed_size 607 || data->crc32 != lfh->crc32) { 608 ALOGW("Zip: size/crc32 mismatch. expected {%" PRIu32 ", %" PRIu32 609 ", %" PRIx32 "}, was {%" PRIu32 ", %" PRIu32 ", %" PRIx32 "}", 610 data->compressed_length, data->uncompressed_length, data->crc32, 611 lfh->compressed_size, lfh->uncompressed_size, lfh->crc32); 612 return kInconsistentInformation; 613 } 614 } else { 615 data->has_data_descriptor = 1; 616 } 617 618 // Check that the local file header name matches the declared 619 // name in the central directory. 620 if (lfh->file_name_length == nameLen) { 621 const off64_t name_offset = local_header_offset + sizeof(LocalFileHeader); 622 if (name_offset + lfh->file_name_length > cd_offset) { 623 ALOGW("Zip: Invalid declared length"); 624 return kInvalidOffset; 625 } 626 627 uint8_t* name_buf = reinterpret_cast<uint8_t*>(malloc(nameLen)); 628 if (!ReadAtOffset(archive->fd, name_buf, nameLen, name_offset)) { 629 ALOGW("Zip: failed reading lfh name from offset %" PRId64, static_cast<int64_t>(name_offset)); 630 free(name_buf); 631 return kIoError; 632 } 633 634 if (memcmp(archive->hash_table[ent].name, name_buf, nameLen)) { 635 free(name_buf); 636 return kInconsistentInformation; 637 } 638 639 free(name_buf); 640 } else { 641 ALOGW("Zip: lfh name did not match central directory."); 642 return kInconsistentInformation; 643 } 644 645 const off64_t data_offset = local_header_offset + sizeof(LocalFileHeader) 646 + lfh->file_name_length + lfh->extra_field_length; 647 if (data_offset > cd_offset) { 648 ALOGW("Zip: bad data offset %" PRId64 " in zip", static_cast<int64_t>(data_offset)); 649 return kInvalidOffset; 650 } 651 652 if (static_cast<off64_t>(data_offset + data->compressed_length) > cd_offset) { 653 ALOGW("Zip: bad compressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")", 654 static_cast<int64_t>(data_offset), data->compressed_length, static_cast<int64_t>(cd_offset)); 655 return kInvalidOffset; 656 } 657 658 if (data->method == kCompressStored && 659 static_cast<off64_t>(data_offset + data->uncompressed_length) > cd_offset) { 660 ALOGW("Zip: bad uncompressed length in zip (%" PRId64 " + %" PRIu32 " > %" PRId64 ")", 661 static_cast<int64_t>(data_offset), data->uncompressed_length, 662 static_cast<int64_t>(cd_offset)); 663 return kInvalidOffset; 664 } 665 666 data->offset = data_offset; 667 return 0; 668} 669 670struct IterationHandle { 671 uint32_t position; 672 // We're not using vector here because this code is used in the Windows SDK 673 // where the STL is not available. 674 ZipString prefix; 675 ZipString suffix; 676 ZipArchive* archive; 677 678 IterationHandle(const ZipString* in_prefix, 679 const ZipString* in_suffix) { 680 if (in_prefix) { 681 uint8_t* name_copy = new uint8_t[in_prefix->name_length]; 682 memcpy(name_copy, in_prefix->name, in_prefix->name_length); 683 prefix.name = name_copy; 684 prefix.name_length = in_prefix->name_length; 685 } else { 686 prefix.name = NULL; 687 prefix.name_length = 0; 688 } 689 if (in_suffix) { 690 uint8_t* name_copy = new uint8_t[in_suffix->name_length]; 691 memcpy(name_copy, in_suffix->name, in_suffix->name_length); 692 suffix.name = name_copy; 693 suffix.name_length = in_suffix->name_length; 694 } else { 695 suffix.name = NULL; 696 suffix.name_length = 0; 697 } 698 } 699 700 ~IterationHandle() { 701 delete[] prefix.name; 702 delete[] suffix.name; 703 } 704}; 705 706int32_t StartIteration(ZipArchiveHandle handle, void** cookie_ptr, 707 const ZipString* optional_prefix, 708 const ZipString* optional_suffix) { 709 ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); 710 711 if (archive == NULL || archive->hash_table == NULL) { 712 ALOGW("Zip: Invalid ZipArchiveHandle"); 713 return kInvalidHandle; 714 } 715 716 IterationHandle* cookie = new IterationHandle(optional_prefix, optional_suffix); 717 cookie->position = 0; 718 cookie->archive = archive; 719 720 *cookie_ptr = cookie ; 721 return 0; 722} 723 724void EndIteration(void* cookie) { 725 delete reinterpret_cast<IterationHandle*>(cookie); 726} 727 728int32_t FindEntry(const ZipArchiveHandle handle, const ZipString& entryName, 729 ZipEntry* data) { 730 const ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); 731 if (entryName.name_length == 0) { 732 ALOGW("Zip: Invalid filename %.*s", entryName.name_length, entryName.name); 733 return kInvalidEntryName; 734 } 735 736 const int64_t ent = EntryToIndex(archive->hash_table, 737 archive->hash_table_size, entryName); 738 739 if (ent < 0) { 740 ALOGV("Zip: Could not find entry %.*s", entryName.name_length, entryName.name); 741 return ent; 742 } 743 744 return FindEntry(archive, ent, data); 745} 746 747int32_t Next(void* cookie, ZipEntry* data, ZipString* name) { 748 IterationHandle* handle = reinterpret_cast<IterationHandle*>(cookie); 749 if (handle == NULL) { 750 return kInvalidHandle; 751 } 752 753 ZipArchive* archive = handle->archive; 754 if (archive == NULL || archive->hash_table == NULL) { 755 ALOGW("Zip: Invalid ZipArchiveHandle"); 756 return kInvalidHandle; 757 } 758 759 const uint32_t currentOffset = handle->position; 760 const uint32_t hash_table_length = archive->hash_table_size; 761 const ZipString* hash_table = archive->hash_table; 762 763 for (uint32_t i = currentOffset; i < hash_table_length; ++i) { 764 if (hash_table[i].name != NULL && 765 (handle->prefix.name_length == 0 || 766 hash_table[i].StartsWith(handle->prefix)) && 767 (handle->suffix.name_length == 0 || 768 hash_table[i].EndsWith(handle->suffix))) { 769 handle->position = (i + 1); 770 const int error = FindEntry(archive, i, data); 771 if (!error) { 772 name->name = hash_table[i].name; 773 name->name_length = hash_table[i].name_length; 774 } 775 776 return error; 777 } 778 } 779 780 handle->position = 0; 781 return kIterationEnd; 782} 783 784class Writer { 785 public: 786 virtual bool Append(uint8_t* buf, size_t buf_size) = 0; 787 virtual ~Writer() {} 788 protected: 789 Writer() = default; 790 private: 791 DISALLOW_COPY_AND_ASSIGN(Writer); 792}; 793 794// A Writer that writes data to a fixed size memory region. 795// The size of the memory region must be equal to the total size of 796// the data appended to it. 797class MemoryWriter : public Writer { 798 public: 799 MemoryWriter(uint8_t* buf, size_t size) : Writer(), 800 buf_(buf), size_(size), bytes_written_(0) { 801 } 802 803 virtual bool Append(uint8_t* buf, size_t buf_size) override { 804 if (bytes_written_ + buf_size > size_) { 805 ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)", 806 size_, bytes_written_ + buf_size); 807 return false; 808 } 809 810 memcpy(buf_ + bytes_written_, buf, buf_size); 811 bytes_written_ += buf_size; 812 return true; 813 } 814 815 private: 816 uint8_t* const buf_; 817 const size_t size_; 818 size_t bytes_written_; 819}; 820 821// A Writer that appends data to a file |fd| at its current position. 822// The file will be truncated to the end of the written data. 823class FileWriter : public Writer { 824 public: 825 826 // Creates a FileWriter for |fd| and prepare to write |entry| to it, 827 // guaranteeing that the file descriptor is valid and that there's enough 828 // space on the volume to write out the entry completely and that the file 829 // is truncated to the correct length. 830 // 831 // Returns a valid FileWriter on success, |nullptr| if an error occurred. 832 static std::unique_ptr<FileWriter> Create(int fd, const ZipEntry* entry) { 833 const uint32_t declared_length = entry->uncompressed_length; 834 const off64_t current_offset = lseek64(fd, 0, SEEK_CUR); 835 if (current_offset == -1) { 836 ALOGW("Zip: unable to seek to current location on fd %d: %s", fd, strerror(errno)); 837 return nullptr; 838 } 839 840 int result = 0; 841#if defined(__linux__) 842 if (declared_length > 0) { 843 // Make sure we have enough space on the volume to extract the compressed 844 // entry. Note that the call to ftruncate below will change the file size but 845 // will not allocate space on disk and this call to fallocate will not 846 // change the file size. 847 // Note: fallocate is only supported by the following filesystems - 848 // btrfs, ext4, ocfs2, and xfs. Therefore fallocate might fail with 849 // EOPNOTSUPP error when issued in other filesystems. 850 // Hence, check for the return error code before concluding that the 851 // disk does not have enough space. 852 result = TEMP_FAILURE_RETRY(fallocate(fd, 0, current_offset, declared_length)); 853 if (result == -1 && errno == ENOSPC) { 854 ALOGW("Zip: unable to allocate space for file to %" PRId64 ": %s", 855 static_cast<int64_t>(declared_length + current_offset), strerror(errno)); 856 return std::unique_ptr<FileWriter>(nullptr); 857 } 858 } 859#endif // __linux__ 860 861 result = TEMP_FAILURE_RETRY(ftruncate(fd, declared_length + current_offset)); 862 if (result == -1) { 863 ALOGW("Zip: unable to truncate file to %" PRId64 ": %s", 864 static_cast<int64_t>(declared_length + current_offset), strerror(errno)); 865 return std::unique_ptr<FileWriter>(nullptr); 866 } 867 868 return std::unique_ptr<FileWriter>(new FileWriter(fd, declared_length)); 869 } 870 871 virtual bool Append(uint8_t* buf, size_t buf_size) override { 872 if (total_bytes_written_ + buf_size > declared_length_) { 873 ALOGW("Zip: Unexpected size " ZD " (declared) vs " ZD " (actual)", 874 declared_length_, total_bytes_written_ + buf_size); 875 return false; 876 } 877 878 const bool result = android::base::WriteFully(fd_, buf, buf_size); 879 if (result) { 880 total_bytes_written_ += buf_size; 881 } else { 882 ALOGW("Zip: unable to write " ZD " bytes to file; %s", buf_size, strerror(errno)); 883 } 884 885 return result; 886 } 887 private: 888 FileWriter(const int fd, const size_t declared_length) : 889 Writer(), 890 fd_(fd), 891 declared_length_(declared_length), 892 total_bytes_written_(0) { 893 } 894 895 const int fd_; 896 const size_t declared_length_; 897 size_t total_bytes_written_; 898}; 899 900// This method is using libz macros with old-style-casts 901#pragma GCC diagnostic push 902#pragma GCC diagnostic ignored "-Wold-style-cast" 903static inline int zlib_inflateInit2(z_stream* stream, int window_bits) { 904 return inflateInit2(stream, window_bits); 905} 906#pragma GCC diagnostic pop 907 908static int32_t InflateEntryToWriter(int fd, const ZipEntry* entry, 909 Writer* writer, uint64_t* crc_out) { 910 const size_t kBufSize = 32768; 911 std::vector<uint8_t> read_buf(kBufSize); 912 std::vector<uint8_t> write_buf(kBufSize); 913 z_stream zstream; 914 int zerr; 915 916 /* 917 * Initialize the zlib stream struct. 918 */ 919 memset(&zstream, 0, sizeof(zstream)); 920 zstream.zalloc = Z_NULL; 921 zstream.zfree = Z_NULL; 922 zstream.opaque = Z_NULL; 923 zstream.next_in = NULL; 924 zstream.avail_in = 0; 925 zstream.next_out = &write_buf[0]; 926 zstream.avail_out = kBufSize; 927 zstream.data_type = Z_UNKNOWN; 928 929 /* 930 * Use the undocumented "negative window bits" feature to tell zlib 931 * that there's no zlib header waiting for it. 932 */ 933 zerr = zlib_inflateInit2(&zstream, -MAX_WBITS); 934 if (zerr != Z_OK) { 935 if (zerr == Z_VERSION_ERROR) { 936 ALOGE("Installed zlib is not compatible with linked version (%s)", 937 ZLIB_VERSION); 938 } else { 939 ALOGW("Call to inflateInit2 failed (zerr=%d)", zerr); 940 } 941 942 return kZlibError; 943 } 944 945 auto zstream_deleter = [](z_stream* stream) { 946 inflateEnd(stream); /* free up any allocated structures */ 947 }; 948 949 std::unique_ptr<z_stream, decltype(zstream_deleter)> zstream_guard(&zstream, zstream_deleter); 950 951 const uint32_t uncompressed_length = entry->uncompressed_length; 952 953 uint32_t compressed_length = entry->compressed_length; 954 do { 955 /* read as much as we can */ 956 if (zstream.avail_in == 0) { 957 const size_t getSize = (compressed_length > kBufSize) ? kBufSize : compressed_length; 958 if (!android::base::ReadFully(fd, read_buf.data(), getSize)) { 959 ALOGW("Zip: inflate read failed, getSize = %zu: %s", getSize, strerror(errno)); 960 return kIoError; 961 } 962 963 compressed_length -= getSize; 964 965 zstream.next_in = &read_buf[0]; 966 zstream.avail_in = getSize; 967 } 968 969 /* uncompress the data */ 970 zerr = inflate(&zstream, Z_NO_FLUSH); 971 if (zerr != Z_OK && zerr != Z_STREAM_END) { 972 ALOGW("Zip: inflate zerr=%d (nIn=%p aIn=%u nOut=%p aOut=%u)", 973 zerr, zstream.next_in, zstream.avail_in, 974 zstream.next_out, zstream.avail_out); 975 return kZlibError; 976 } 977 978 /* write when we're full or when we're done */ 979 if (zstream.avail_out == 0 || 980 (zerr == Z_STREAM_END && zstream.avail_out != kBufSize)) { 981 const size_t write_size = zstream.next_out - &write_buf[0]; 982 if (!writer->Append(&write_buf[0], write_size)) { 983 // The file might have declared a bogus length. 984 return kInconsistentInformation; 985 } 986 987 zstream.next_out = &write_buf[0]; 988 zstream.avail_out = kBufSize; 989 } 990 } while (zerr == Z_OK); 991 992 assert(zerr == Z_STREAM_END); /* other errors should've been caught */ 993 994 // stream.adler holds the crc32 value for such streams. 995 *crc_out = zstream.adler; 996 997 if (zstream.total_out != uncompressed_length || compressed_length != 0) { 998 ALOGW("Zip: size mismatch on inflated file (%lu vs %" PRIu32 ")", 999 zstream.total_out, uncompressed_length); 1000 return kInconsistentInformation; 1001 } 1002 1003 return 0; 1004} 1005 1006static int32_t CopyEntryToWriter(int fd, const ZipEntry* entry, Writer* writer, 1007 uint64_t *crc_out) { 1008 static const uint32_t kBufSize = 32768; 1009 std::vector<uint8_t> buf(kBufSize); 1010 1011 const uint32_t length = entry->uncompressed_length; 1012 uint32_t count = 0; 1013 uint64_t crc = 0; 1014 while (count < length) { 1015 uint32_t remaining = length - count; 1016 1017 // Safe conversion because kBufSize is narrow enough for a 32 bit signed 1018 // value. 1019 const size_t block_size = (remaining > kBufSize) ? kBufSize : remaining; 1020 if (!android::base::ReadFully(fd, buf.data(), block_size)) { 1021 ALOGW("CopyFileToFile: copy read failed, block_size = %zu: %s", block_size, strerror(errno)); 1022 return kIoError; 1023 } 1024 1025 if (!writer->Append(&buf[0], block_size)) { 1026 return kIoError; 1027 } 1028 crc = crc32(crc, &buf[0], block_size); 1029 count += block_size; 1030 } 1031 1032 *crc_out = crc; 1033 1034 return 0; 1035} 1036 1037int32_t ExtractToWriter(ZipArchiveHandle handle, 1038 ZipEntry* entry, Writer* writer) { 1039 ZipArchive* archive = reinterpret_cast<ZipArchive*>(handle); 1040 const uint16_t method = entry->method; 1041 off64_t data_offset = entry->offset; 1042 1043 if (lseek64(archive->fd, data_offset, SEEK_SET) != data_offset) { 1044 ALOGW("Zip: lseek to data at %" PRId64 " failed", static_cast<int64_t>(data_offset)); 1045 return kIoError; 1046 } 1047 1048 // this should default to kUnknownCompressionMethod. 1049 int32_t return_value = -1; 1050 uint64_t crc = 0; 1051 if (method == kCompressStored) { 1052 return_value = CopyEntryToWriter(archive->fd, entry, writer, &crc); 1053 } else if (method == kCompressDeflated) { 1054 return_value = InflateEntryToWriter(archive->fd, entry, writer, &crc); 1055 } 1056 1057 if (!return_value && entry->has_data_descriptor) { 1058 return_value = UpdateEntryFromDataDescriptor(archive->fd, entry); 1059 if (return_value) { 1060 return return_value; 1061 } 1062 } 1063 1064 // TODO: Fix this check by passing the right flags to inflate2 so that 1065 // it calculates the CRC for us. 1066 if (entry->crc32 != crc && false) { 1067 ALOGW("Zip: crc mismatch: expected %" PRIu32 ", was %" PRIu64, entry->crc32, crc); 1068 return kInconsistentInformation; 1069 } 1070 1071 return return_value; 1072} 1073 1074int32_t ExtractToMemory(ZipArchiveHandle handle, ZipEntry* entry, 1075 uint8_t* begin, uint32_t size) { 1076 std::unique_ptr<Writer> writer(new MemoryWriter(begin, size)); 1077 return ExtractToWriter(handle, entry, writer.get()); 1078} 1079 1080int32_t ExtractEntryToFile(ZipArchiveHandle handle, 1081 ZipEntry* entry, int fd) { 1082 std::unique_ptr<Writer> writer(FileWriter::Create(fd, entry)); 1083 if (writer.get() == nullptr) { 1084 return kIoError; 1085 } 1086 1087 return ExtractToWriter(handle, entry, writer.get()); 1088} 1089 1090const char* ErrorCodeString(int32_t error_code) { 1091 if (error_code > kErrorMessageLowerBound && error_code < kErrorMessageUpperBound) { 1092 return kErrorMessages[error_code * -1]; 1093 } 1094 1095 return kErrorMessages[0]; 1096} 1097 1098int GetFileDescriptor(const ZipArchiveHandle handle) { 1099 return reinterpret_cast<ZipArchive*>(handle)->fd; 1100} 1101