Home | History | Annotate | Download | only in dex
      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