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