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 // 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