1 /* 2 * Copyright (C) 2017 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 #include "dex_file_loader.h" 18 19 #include "android-base/stringprintf.h" 20 21 #include "base/stl_util.h" 22 #include "compact_dex_file.h" 23 #include "dex_file.h" 24 #include "dex_file_verifier.h" 25 #include "standard_dex_file.h" 26 #include "ziparchive/zip_archive.h" 27 28 namespace art { 29 30 namespace { 31 32 class VectorContainer : public DexFileContainer { 33 public: 34 explicit VectorContainer(std::vector<uint8_t>&& vector) : vector_(std::move(vector)) { } 35 ~VectorContainer() override { } 36 37 int GetPermissions() override { 38 return 0; 39 } 40 41 bool IsReadOnly() override { 42 return true; 43 } 44 45 bool EnableWrite() override { 46 return false; 47 } 48 49 bool DisableWrite() override { 50 return false; 51 } 52 53 private: 54 std::vector<uint8_t> vector_; 55 DISALLOW_COPY_AND_ASSIGN(VectorContainer); 56 }; 57 58 } // namespace 59 60 using android::base::StringPrintf; 61 62 class DexZipArchive; 63 64 class DexZipEntry { 65 public: 66 // Extract this entry to memory. 67 // Returns null on failure and sets error_msg. 68 const std::vector<uint8_t> Extract(std::string* error_msg) { 69 std::vector<uint8_t> map(GetUncompressedLength()); 70 if (map.size() == 0) { 71 DCHECK(!error_msg->empty()); 72 return map; 73 } 74 const int32_t error = ExtractToMemory(handle_, zip_entry_, map.data(), map.size()); 75 if (error) { 76 *error_msg = std::string(ErrorCodeString(error)); 77 } 78 return map; 79 } 80 81 virtual ~DexZipEntry() { 82 delete zip_entry_; 83 } 84 85 uint32_t GetUncompressedLength() { 86 return zip_entry_->uncompressed_length; 87 } 88 89 uint32_t GetCrc32() { 90 return zip_entry_->crc32; 91 } 92 93 private: 94 DexZipEntry(ZipArchiveHandle handle, 95 ::ZipEntry* zip_entry, 96 const std::string& entry_name) 97 : handle_(handle), zip_entry_(zip_entry), entry_name_(entry_name) {} 98 99 ZipArchiveHandle handle_; 100 ::ZipEntry* const zip_entry_; 101 std::string const entry_name_; 102 103 friend class DexZipArchive; 104 DISALLOW_COPY_AND_ASSIGN(DexZipEntry); 105 }; 106 107 class DexZipArchive { 108 public: 109 // return new DexZipArchive instance on success, null on error. 110 static DexZipArchive* Open(const uint8_t* base, size_t size, std::string* error_msg) { 111 ZipArchiveHandle handle; 112 uint8_t* nonconst_base = const_cast<uint8_t*>(base); 113 const int32_t error = OpenArchiveFromMemory(nonconst_base, size, "ZipArchiveMemory", &handle); 114 if (error) { 115 *error_msg = std::string(ErrorCodeString(error)); 116 CloseArchive(handle); 117 return nullptr; 118 } 119 return new DexZipArchive(handle); 120 } 121 122 DexZipEntry* Find(const char* name, std::string* error_msg) const { 123 DCHECK(name != nullptr); 124 // Resist the urge to delete the space. <: is a bigraph sequence. 125 std::unique_ptr< ::ZipEntry> zip_entry(new ::ZipEntry); 126 const int32_t error = FindEntry(handle_, ZipString(name), zip_entry.get()); 127 if (error) { 128 *error_msg = std::string(ErrorCodeString(error)); 129 return nullptr; 130 } 131 return new DexZipEntry(handle_, zip_entry.release(), name); 132 } 133 134 ~DexZipArchive() { 135 CloseArchive(handle_); 136 } 137 138 139 private: 140 explicit DexZipArchive(ZipArchiveHandle handle) : handle_(handle) {} 141 ZipArchiveHandle handle_; 142 143 friend class DexZipEntry; 144 DISALLOW_COPY_AND_ASSIGN(DexZipArchive); 145 }; 146 147 static bool IsZipMagic(uint32_t magic) { 148 return (('P' == ((magic >> 0) & 0xff)) && 149 ('K' == ((magic >> 8) & 0xff))); 150 } 151 152 bool DexFileLoader::IsMagicValid(uint32_t magic) { 153 return IsMagicValid(reinterpret_cast<uint8_t*>(&magic)); 154 } 155 156 bool DexFileLoader::IsMagicValid(const uint8_t* magic) { 157 return StandardDexFile::IsMagicValid(magic) || 158 CompactDexFile::IsMagicValid(magic); 159 } 160 161 bool DexFileLoader::IsVersionAndMagicValid(const uint8_t* magic) { 162 if (StandardDexFile::IsMagicValid(magic)) { 163 return StandardDexFile::IsVersionValid(magic); 164 } 165 if (CompactDexFile::IsMagicValid(magic)) { 166 return CompactDexFile::IsVersionValid(magic); 167 } 168 return false; 169 } 170 171 bool DexFileLoader::IsMultiDexLocation(const char* location) { 172 return strrchr(location, kMultiDexSeparator) != nullptr; 173 } 174 175 std::string DexFileLoader::GetMultiDexClassesDexName(size_t index) { 176 return (index == 0) ? "classes.dex" : StringPrintf("classes%zu.dex", index + 1); 177 } 178 179 std::string DexFileLoader::GetMultiDexLocation(size_t index, const char* dex_location) { 180 return (index == 0) 181 ? dex_location 182 : StringPrintf("%s%cclasses%zu.dex", dex_location, kMultiDexSeparator, index + 1); 183 } 184 185 std::string DexFileLoader::GetDexCanonicalLocation(const char* dex_location) { 186 CHECK_NE(dex_location, static_cast<const char*>(nullptr)); 187 std::string base_location = GetBaseLocation(dex_location); 188 const char* suffix = dex_location + base_location.size(); 189 DCHECK(suffix[0] == 0 || suffix[0] == kMultiDexSeparator); 190 #ifdef _WIN32 191 // Warning: No symbolic link processing here. 192 PLOG(WARNING) << "realpath is unsupported on Windows."; 193 #else 194 // Warning: Bionic implementation of realpath() allocates > 12KB on the stack. 195 // Do not run this code on a small stack, e.g. in signal handler. 196 UniqueCPtr<const char[]> path(realpath(base_location.c_str(), nullptr)); 197 if (path != nullptr && path.get() != base_location) { 198 return std::string(path.get()) + suffix; 199 } 200 #endif 201 if (suffix[0] == 0) { 202 return base_location; 203 } else { 204 return dex_location; 205 } 206 } 207 208 // All of the implementations here should be independent of the runtime. 209 // TODO: implement all the virtual methods. 210 211 bool DexFileLoader::GetMultiDexChecksums( 212 const char* filename ATTRIBUTE_UNUSED, 213 std::vector<uint32_t>* checksums ATTRIBUTE_UNUSED, 214 std::string* error_msg, 215 int zip_fd ATTRIBUTE_UNUSED, 216 bool* zip_file_only_contains_uncompress_dex ATTRIBUTE_UNUSED) const { 217 *error_msg = "UNIMPLEMENTED"; 218 return false; 219 } 220 221 std::unique_ptr<const DexFile> DexFileLoader::Open( 222 const uint8_t* base, 223 size_t size, 224 const std::string& location, 225 uint32_t location_checksum, 226 const OatDexFile* oat_dex_file, 227 bool verify, 228 bool verify_checksum, 229 std::string* error_msg, 230 std::unique_ptr<DexFileContainer> container) const { 231 return OpenCommon(base, 232 size, 233 /*data_base=*/ nullptr, 234 /*data_size=*/ 0, 235 location, 236 location_checksum, 237 oat_dex_file, 238 verify, 239 verify_checksum, 240 error_msg, 241 std::move(container), 242 /*verify_result=*/ nullptr); 243 } 244 245 std::unique_ptr<const DexFile> DexFileLoader::OpenWithDataSection( 246 const uint8_t* base, 247 size_t size, 248 const uint8_t* data_base, 249 size_t data_size, 250 const std::string& location, 251 uint32_t location_checksum, 252 const OatDexFile* oat_dex_file, 253 bool verify, 254 bool verify_checksum, 255 std::string* error_msg) const { 256 return OpenCommon(base, 257 size, 258 data_base, 259 data_size, 260 location, 261 location_checksum, 262 oat_dex_file, 263 verify, 264 verify_checksum, 265 error_msg, 266 /*container=*/ nullptr, 267 /*verify_result=*/ nullptr); 268 } 269 270 bool DexFileLoader::OpenAll( 271 const uint8_t* base, 272 size_t size, 273 const std::string& location, 274 bool verify, 275 bool verify_checksum, 276 DexFileLoaderErrorCode* error_code, 277 std::string* error_msg, 278 std::vector<std::unique_ptr<const DexFile>>* dex_files) const { 279 DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr"; 280 uint32_t magic = *reinterpret_cast<const uint32_t*>(base); 281 if (IsZipMagic(magic)) { 282 std::unique_ptr<DexZipArchive> zip_archive(DexZipArchive::Open(base, size, error_msg)); 283 if (zip_archive.get() == nullptr) { 284 DCHECK(!error_msg->empty()); 285 return false; 286 } 287 return OpenAllDexFilesFromZip(*zip_archive.get(), 288 location, 289 verify, 290 verify_checksum, 291 error_code, 292 error_msg, 293 dex_files); 294 } 295 if (IsMagicValid(magic)) { 296 const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(base); 297 std::unique_ptr<const DexFile> dex_file(Open(base, 298 size, 299 location, 300 dex_header->checksum_, 301 /*oat_dex_file=*/ nullptr, 302 verify, 303 verify_checksum, 304 error_msg)); 305 if (dex_file.get() != nullptr) { 306 dex_files->push_back(std::move(dex_file)); 307 return true; 308 } else { 309 return false; 310 } 311 } 312 *error_msg = StringPrintf("Expected valid zip or dex file"); 313 return false; 314 } 315 316 std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base, 317 size_t size, 318 const uint8_t* data_base, 319 size_t data_size, 320 const std::string& location, 321 uint32_t location_checksum, 322 const OatDexFile* oat_dex_file, 323 bool verify, 324 bool verify_checksum, 325 std::string* error_msg, 326 std::unique_ptr<DexFileContainer> container, 327 VerifyResult* verify_result) { 328 if (verify_result != nullptr) { 329 *verify_result = VerifyResult::kVerifyNotAttempted; 330 } 331 std::unique_ptr<DexFile> dex_file; 332 if (size >= sizeof(StandardDexFile::Header) && StandardDexFile::IsMagicValid(base)) { 333 if (data_size != 0) { 334 CHECK_EQ(base, data_base) << "Unsupported for standard dex"; 335 } 336 dex_file.reset(new StandardDexFile(base, 337 size, 338 location, 339 location_checksum, 340 oat_dex_file, 341 std::move(container))); 342 } else if (size >= sizeof(CompactDexFile::Header) && CompactDexFile::IsMagicValid(base)) { 343 if (data_base == nullptr) { 344 // TODO: Is there a clean way to support both an explicit data section and reading the one 345 // from the header. 346 CHECK_EQ(data_size, 0u); 347 const CompactDexFile::Header* const header = CompactDexFile::Header::At(base); 348 data_base = base + header->data_off_; 349 data_size = header->data_size_; 350 } 351 dex_file.reset(new CompactDexFile(base, 352 size, 353 data_base, 354 data_size, 355 location, 356 location_checksum, 357 oat_dex_file, 358 std::move(container))); 359 // Disable verification for CompactDex input. 360 verify = false; 361 } else { 362 *error_msg = "Invalid or truncated dex file"; 363 } 364 if (dex_file == nullptr) { 365 *error_msg = StringPrintf("Failed to open dex file '%s' from memory: %s", location.c_str(), 366 error_msg->c_str()); 367 return nullptr; 368 } 369 if (!dex_file->Init(error_msg)) { 370 dex_file.reset(); 371 return nullptr; 372 } 373 if (verify && !DexFileVerifier::Verify(dex_file.get(), 374 dex_file->Begin(), 375 dex_file->Size(), 376 location.c_str(), 377 verify_checksum, 378 error_msg)) { 379 if (verify_result != nullptr) { 380 *verify_result = VerifyResult::kVerifyFailed; 381 } 382 return nullptr; 383 } 384 if (verify_result != nullptr) { 385 *verify_result = VerifyResult::kVerifySucceeded; 386 } 387 return dex_file; 388 } 389 390 std::unique_ptr<const DexFile> DexFileLoader::OpenOneDexFileFromZip( 391 const DexZipArchive& zip_archive, 392 const char* entry_name, 393 const std::string& location, 394 bool verify, 395 bool verify_checksum, 396 DexFileLoaderErrorCode* error_code, 397 std::string* error_msg) const { 398 CHECK(!location.empty()); 399 std::unique_ptr<DexZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg)); 400 if (zip_entry == nullptr) { 401 *error_code = DexFileLoaderErrorCode::kEntryNotFound; 402 return nullptr; 403 } 404 if (zip_entry->GetUncompressedLength() == 0) { 405 *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str()); 406 *error_code = DexFileLoaderErrorCode::kDexFileError; 407 return nullptr; 408 } 409 410 std::vector<uint8_t> map(zip_entry->Extract(error_msg)); 411 if (map.size() == 0) { 412 *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(), 413 error_msg->c_str()); 414 *error_code = DexFileLoaderErrorCode::kExtractToMemoryError; 415 return nullptr; 416 } 417 VerifyResult verify_result; 418 std::unique_ptr<const DexFile> dex_file = OpenCommon( 419 map.data(), 420 map.size(), 421 /*data_base=*/ nullptr, 422 /*data_size=*/ 0u, 423 location, 424 zip_entry->GetCrc32(), 425 /*oat_dex_file=*/ nullptr, 426 verify, 427 verify_checksum, 428 error_msg, 429 std::make_unique<VectorContainer>(std::move(map)), 430 &verify_result); 431 if (verify_result != VerifyResult::kVerifySucceeded) { 432 if (verify_result == VerifyResult::kVerifyNotAttempted) { 433 *error_code = DexFileLoaderErrorCode::kDexFileError; 434 } else { 435 *error_code = DexFileLoaderErrorCode::kVerifyError; 436 } 437 return nullptr; 438 } 439 *error_code = DexFileLoaderErrorCode::kNoError; 440 return dex_file; 441 } 442 443 // Technically we do not have a limitation with respect to the number of dex files that can be in a 444 // multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols 445 // (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what 446 // seems an excessive number. 447 static constexpr size_t kWarnOnManyDexFilesThreshold = 100; 448 449 bool DexFileLoader::OpenAllDexFilesFromZip( 450 const DexZipArchive& zip_archive, 451 const std::string& location, 452 bool verify, 453 bool verify_checksum, 454 DexFileLoaderErrorCode* error_code, 455 std::string* error_msg, 456 std::vector<std::unique_ptr<const DexFile>>* dex_files) const { 457 DCHECK(dex_files != nullptr) << "DexFile::OpenFromZip: out-param is nullptr"; 458 std::unique_ptr<const DexFile> dex_file(OpenOneDexFileFromZip(zip_archive, 459 kClassesDex, 460 location, 461 verify, 462 verify_checksum, 463 error_code, 464 error_msg)); 465 if (*error_code != DexFileLoaderErrorCode::kNoError) { 466 return false; 467 } else { 468 // Had at least classes.dex. 469 dex_files->push_back(std::move(dex_file)); 470 471 // Now try some more. 472 473 // We could try to avoid std::string allocations by working on a char array directly. As we 474 // do not expect a lot of iterations, this seems too involved and brittle. 475 476 for (size_t i = 1; ; ++i) { 477 std::string name = GetMultiDexClassesDexName(i); 478 std::string fake_location = GetMultiDexLocation(i, location.c_str()); 479 std::unique_ptr<const DexFile> next_dex_file(OpenOneDexFileFromZip(zip_archive, 480 name.c_str(), 481 fake_location, 482 verify, 483 verify_checksum, 484 error_code, 485 error_msg)); 486 if (next_dex_file.get() == nullptr) { 487 if (*error_code != DexFileLoaderErrorCode::kEntryNotFound) { 488 LOG(WARNING) << "Zip open failed: " << *error_msg; 489 } 490 break; 491 } else { 492 dex_files->push_back(std::move(next_dex_file)); 493 } 494 495 if (i == kWarnOnManyDexFilesThreshold) { 496 LOG(WARNING) << location << " has in excess of " << kWarnOnManyDexFilesThreshold 497 << " dex files. Please consider coalescing and shrinking the number to " 498 " avoid runtime overhead."; 499 } 500 501 if (i == std::numeric_limits<size_t>::max()) { 502 LOG(ERROR) << "Overflow in number of dex files!"; 503 break; 504 } 505 } 506 507 return true; 508 } 509 } 510 } // namespace art 511