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 "art_dex_file_loader.h"
     18 
     19 #include <sys/mman.h>  // For the PROT_* and MAP_* constants.
     20 #include <sys/stat.h>
     21 
     22 #include "android-base/stringprintf.h"
     23 
     24 #include "base/file_magic.h"
     25 #include "base/file_utils.h"
     26 #include "base/stl_util.h"
     27 #include "base/systrace.h"
     28 #include "base/unix_file/fd_file.h"
     29 #include "dex/compact_dex_file.h"
     30 #include "dex/dex_file.h"
     31 #include "dex/dex_file_verifier.h"
     32 #include "dex/standard_dex_file.h"
     33 #include "zip_archive.h"
     34 
     35 namespace art {
     36 
     37 namespace {
     38 
     39 class MemMapContainer : public DexFileContainer {
     40  public:
     41   explicit MemMapContainer(std::unique_ptr<MemMap>&& mem_map) : mem_map_(std::move(mem_map)) { }
     42   virtual ~MemMapContainer() OVERRIDE { }
     43 
     44   int GetPermissions() OVERRIDE {
     45     if (mem_map_.get() == nullptr) {
     46       return 0;
     47     } else {
     48       return mem_map_->GetProtect();
     49     }
     50   }
     51 
     52   bool IsReadOnly() OVERRIDE {
     53     return GetPermissions() == PROT_READ;
     54   }
     55 
     56   bool EnableWrite() OVERRIDE {
     57     CHECK(IsReadOnly());
     58     if (mem_map_.get() == nullptr) {
     59       return false;
     60     } else {
     61       return mem_map_->Protect(PROT_READ | PROT_WRITE);
     62     }
     63   }
     64 
     65   bool DisableWrite() OVERRIDE {
     66     CHECK(!IsReadOnly());
     67     if (mem_map_.get() == nullptr) {
     68       return false;
     69     } else {
     70       return mem_map_->Protect(PROT_READ);
     71     }
     72   }
     73 
     74  private:
     75   std::unique_ptr<MemMap> mem_map_;
     76   DISALLOW_COPY_AND_ASSIGN(MemMapContainer);
     77 };
     78 
     79 }  // namespace
     80 
     81 using android::base::StringPrintf;
     82 
     83 static constexpr OatDexFile* kNoOatDexFile = nullptr;
     84 
     85 
     86 bool ArtDexFileLoader::GetMultiDexChecksums(const char* filename,
     87                                             std::vector<uint32_t>* checksums,
     88                                             std::string* error_msg,
     89                                             int zip_fd,
     90                                             bool* zip_file_only_contains_uncompressed_dex) const {
     91   CHECK(checksums != nullptr);
     92   uint32_t magic;
     93 
     94   File fd;
     95   if (zip_fd != -1) {
     96      if (ReadMagicAndReset(zip_fd, &magic, error_msg)) {
     97        fd = File(zip_fd, false /* check_usage */);
     98      }
     99   } else {
    100     fd = OpenAndReadMagic(filename, &magic, error_msg);
    101   }
    102   if (fd.Fd() == -1) {
    103     DCHECK(!error_msg->empty());
    104     return false;
    105   }
    106   if (IsZipMagic(magic)) {
    107     std::unique_ptr<ZipArchive> zip_archive(
    108         ZipArchive::OpenFromFd(fd.Release(), filename, error_msg));
    109     if (zip_archive.get() == nullptr) {
    110       *error_msg = StringPrintf("Failed to open zip archive '%s' (error msg: %s)", filename,
    111                                 error_msg->c_str());
    112       return false;
    113     }
    114 
    115     uint32_t i = 0;
    116     std::string zip_entry_name = GetMultiDexClassesDexName(i++);
    117     std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
    118     if (zip_entry.get() == nullptr) {
    119       *error_msg = StringPrintf("Zip archive '%s' doesn't contain %s (error msg: %s)", filename,
    120           zip_entry_name.c_str(), error_msg->c_str());
    121       return false;
    122     }
    123 
    124     if (zip_file_only_contains_uncompressed_dex != nullptr) {
    125       // Start by assuming everything is uncompressed.
    126       *zip_file_only_contains_uncompressed_dex = true;
    127     }
    128 
    129     do {
    130       if (zip_file_only_contains_uncompressed_dex != nullptr) {
    131         if (!(zip_entry->IsUncompressed() && zip_entry->IsAlignedToDexHeader())) {
    132           *zip_file_only_contains_uncompressed_dex = false;
    133         }
    134       }
    135       checksums->push_back(zip_entry->GetCrc32());
    136       zip_entry_name = GetMultiDexClassesDexName(i++);
    137       zip_entry.reset(zip_archive->Find(zip_entry_name.c_str(), error_msg));
    138     } while (zip_entry.get() != nullptr);
    139     return true;
    140   }
    141   if (IsMagicValid(magic)) {
    142     std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(),
    143                                                      filename,
    144                                                      /* verify */ false,
    145                                                      /* verify_checksum */ false,
    146                                                      /* mmap_shared */ false,
    147                                                      error_msg));
    148     if (dex_file == nullptr) {
    149       return false;
    150     }
    151     checksums->push_back(dex_file->GetHeader().checksum_);
    152     return true;
    153   }
    154   *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
    155   return false;
    156 }
    157 
    158 std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const uint8_t* base,
    159                                                       size_t size,
    160                                                       const std::string& location,
    161                                                       uint32_t location_checksum,
    162                                                       const OatDexFile* oat_dex_file,
    163                                                       bool verify,
    164                                                       bool verify_checksum,
    165                                                       std::string* error_msg) const {
    166   ScopedTrace trace(std::string("Open dex file from RAM ") + location);
    167   return OpenCommon(base,
    168                     size,
    169                     /*data_base*/ nullptr,
    170                     /*data_size*/ 0u,
    171                     location,
    172                     location_checksum,
    173                     oat_dex_file,
    174                     verify,
    175                     verify_checksum,
    176                     error_msg,
    177                     /*container*/ nullptr,
    178                     /*verify_result*/ nullptr);
    179 }
    180 
    181 std::unique_ptr<const DexFile> ArtDexFileLoader::Open(const std::string& location,
    182                                                       uint32_t location_checksum,
    183                                                       std::unique_ptr<MemMap> map,
    184                                                       bool verify,
    185                                                       bool verify_checksum,
    186                                                       std::string* error_msg) const {
    187   ScopedTrace trace(std::string("Open dex file from mapped-memory ") + location);
    188   CHECK(map.get() != nullptr);
    189 
    190   if (map->Size() < sizeof(DexFile::Header)) {
    191     *error_msg = StringPrintf(
    192         "DexFile: failed to open dex file '%s' that is too short to have a header",
    193         location.c_str());
    194     return nullptr;
    195   }
    196 
    197   std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
    198                                                  map->Size(),
    199                                                  /*data_base*/ nullptr,
    200                                                  /*data_size*/ 0u,
    201                                                  location,
    202                                                  location_checksum,
    203                                                  kNoOatDexFile,
    204                                                  verify,
    205                                                  verify_checksum,
    206                                                  error_msg,
    207                                                  std::make_unique<MemMapContainer>(std::move(map)),
    208                                                  /*verify_result*/ nullptr);
    209   // Opening CompactDex is only supported from vdex files.
    210   if (dex_file != nullptr && dex_file->IsCompactDexFile()) {
    211     *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files",
    212                               location.c_str());
    213     return nullptr;
    214   }
    215   return dex_file;
    216 }
    217 
    218 bool ArtDexFileLoader::Open(const char* filename,
    219                             const std::string& location,
    220                             bool verify,
    221                             bool verify_checksum,
    222                             std::string* error_msg,
    223                             std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
    224   ScopedTrace trace(std::string("Open dex file ") + std::string(location));
    225   DCHECK(dex_files != nullptr) << "DexFile::Open: out-param is nullptr";
    226   uint32_t magic;
    227   File fd = OpenAndReadMagic(filename, &magic, error_msg);
    228   if (fd.Fd() == -1) {
    229     DCHECK(!error_msg->empty());
    230     return false;
    231   }
    232   if (IsZipMagic(magic)) {
    233     return OpenZip(fd.Release(), location, verify, verify_checksum, error_msg, dex_files);
    234   }
    235   if (IsMagicValid(magic)) {
    236     std::unique_ptr<const DexFile> dex_file(OpenFile(fd.Release(),
    237                                                      location,
    238                                                      verify,
    239                                                      verify_checksum,
    240                                                      /* mmap_shared */ false,
    241                                                      error_msg));
    242     if (dex_file.get() != nullptr) {
    243       dex_files->push_back(std::move(dex_file));
    244       return true;
    245     } else {
    246       return false;
    247     }
    248   }
    249   *error_msg = StringPrintf("Expected valid zip or dex file: '%s'", filename);
    250   return false;
    251 }
    252 
    253 std::unique_ptr<const DexFile> ArtDexFileLoader::OpenDex(int fd,
    254                                                          const std::string& location,
    255                                                          bool verify,
    256                                                          bool verify_checksum,
    257                                                          bool mmap_shared,
    258                                                          std::string* error_msg) const {
    259   ScopedTrace trace("Open dex file " + std::string(location));
    260   return OpenFile(fd, location, verify, verify_checksum, mmap_shared, error_msg);
    261 }
    262 
    263 bool ArtDexFileLoader::OpenZip(int fd,
    264                                const std::string& location,
    265                                bool verify,
    266                                bool verify_checksum,
    267                                std::string* error_msg,
    268                                std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
    269   ScopedTrace trace("Dex file open Zip " + std::string(location));
    270   DCHECK(dex_files != nullptr) << "DexFile::OpenZip: out-param is nullptr";
    271   std::unique_ptr<ZipArchive> zip_archive(ZipArchive::OpenFromFd(fd, location.c_str(), error_msg));
    272   if (zip_archive.get() == nullptr) {
    273     DCHECK(!error_msg->empty());
    274     return false;
    275   }
    276   return OpenAllDexFilesFromZip(
    277       *zip_archive, location, verify, verify_checksum, error_msg, dex_files);
    278 }
    279 
    280 std::unique_ptr<const DexFile> ArtDexFileLoader::OpenFile(int fd,
    281                                                           const std::string& location,
    282                                                           bool verify,
    283                                                           bool verify_checksum,
    284                                                           bool mmap_shared,
    285                                                           std::string* error_msg) const {
    286   ScopedTrace trace(std::string("Open dex file ") + std::string(location));
    287   CHECK(!location.empty());
    288   std::unique_ptr<MemMap> map;
    289   {
    290     File delayed_close(fd, /* check_usage */ false);
    291     struct stat sbuf;
    292     memset(&sbuf, 0, sizeof(sbuf));
    293     if (fstat(fd, &sbuf) == -1) {
    294       *error_msg = StringPrintf("DexFile: fstat '%s' failed: %s", location.c_str(),
    295                                 strerror(errno));
    296       return nullptr;
    297     }
    298     if (S_ISDIR(sbuf.st_mode)) {
    299       *error_msg = StringPrintf("Attempt to mmap directory '%s'", location.c_str());
    300       return nullptr;
    301     }
    302     size_t length = sbuf.st_size;
    303     map.reset(MemMap::MapFile(length,
    304                               PROT_READ,
    305                               mmap_shared ? MAP_SHARED : MAP_PRIVATE,
    306                               fd,
    307                               0,
    308                               /*low_4gb*/false,
    309                               location.c_str(),
    310                               error_msg));
    311     if (map == nullptr) {
    312       DCHECK(!error_msg->empty());
    313       return nullptr;
    314     }
    315   }
    316 
    317   if (map->Size() < sizeof(DexFile::Header)) {
    318     *error_msg = StringPrintf(
    319         "DexFile: failed to open dex file '%s' that is too short to have a header",
    320         location.c_str());
    321     return nullptr;
    322   }
    323 
    324   const DexFile::Header* dex_header = reinterpret_cast<const DexFile::Header*>(map->Begin());
    325 
    326   std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
    327                                                  map->Size(),
    328                                                  /*data_base*/ nullptr,
    329                                                  /*data_size*/ 0u,
    330                                                  location,
    331                                                  dex_header->checksum_,
    332                                                  kNoOatDexFile,
    333                                                  verify,
    334                                                  verify_checksum,
    335                                                  error_msg,
    336                                                  std::make_unique<MemMapContainer>(std::move(map)),
    337                                                  /*verify_result*/ nullptr);
    338 
    339   // Opening CompactDex is only supported from vdex files.
    340   if (dex_file != nullptr && dex_file->IsCompactDexFile()) {
    341     *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files",
    342                               location.c_str());
    343     return nullptr;
    344   }
    345   return dex_file;
    346 }
    347 
    348 std::unique_ptr<const DexFile> ArtDexFileLoader::OpenOneDexFileFromZip(
    349     const ZipArchive& zip_archive,
    350     const char* entry_name,
    351     const std::string& location,
    352     bool verify,
    353     bool verify_checksum,
    354     std::string* error_msg,
    355     ZipOpenErrorCode* error_code) const {
    356   ScopedTrace trace("Dex file open from Zip Archive " + std::string(location));
    357   CHECK(!location.empty());
    358   std::unique_ptr<ZipEntry> zip_entry(zip_archive.Find(entry_name, error_msg));
    359   if (zip_entry == nullptr) {
    360     *error_code = ZipOpenErrorCode::kEntryNotFound;
    361     return nullptr;
    362   }
    363   if (zip_entry->GetUncompressedLength() == 0) {
    364     *error_msg = StringPrintf("Dex file '%s' has zero length", location.c_str());
    365     *error_code = ZipOpenErrorCode::kDexFileError;
    366     return nullptr;
    367   }
    368 
    369   std::unique_ptr<MemMap> map;
    370   if (zip_entry->IsUncompressed()) {
    371     if (!zip_entry->IsAlignedTo(alignof(DexFile::Header))) {
    372       // Do not mmap unaligned ZIP entries because
    373       // doing so would fail dex verification which requires 4 byte alignment.
    374       LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
    375                    << "please zipalign to " << alignof(DexFile::Header) << " bytes. "
    376                    << "Falling back to extracting file.";
    377     } else {
    378       // Map uncompressed files within zip as file-backed to avoid a dirty copy.
    379       map.reset(zip_entry->MapDirectlyFromFile(location.c_str(), /*out*/error_msg));
    380       if (map == nullptr) {
    381         LOG(WARNING) << "Can't mmap dex file " << location << "!" << entry_name << " directly; "
    382                      << "is your ZIP file corrupted? Falling back to extraction.";
    383         // Try again with Extraction which still has a chance of recovery.
    384       }
    385     }
    386   }
    387 
    388   if (map == nullptr) {
    389     // Default path for compressed ZIP entries,
    390     // and fallback for stored ZIP entries.
    391     map.reset(zip_entry->ExtractToMemMap(location.c_str(), entry_name, error_msg));
    392   }
    393 
    394   if (map == nullptr) {
    395     *error_msg = StringPrintf("Failed to extract '%s' from '%s': %s", entry_name, location.c_str(),
    396                               error_msg->c_str());
    397     *error_code = ZipOpenErrorCode::kExtractToMemoryError;
    398     return nullptr;
    399   }
    400   VerifyResult verify_result;
    401   std::unique_ptr<DexFile> dex_file = OpenCommon(map->Begin(),
    402                                                  map->Size(),
    403                                                  /*data_base*/ nullptr,
    404                                                  /*data_size*/ 0u,
    405                                                  location,
    406                                                  zip_entry->GetCrc32(),
    407                                                  kNoOatDexFile,
    408                                                  verify,
    409                                                  verify_checksum,
    410                                                  error_msg,
    411                                                  std::make_unique<MemMapContainer>(std::move(map)),
    412                                                  &verify_result);
    413   if (dex_file != nullptr && dex_file->IsCompactDexFile()) {
    414     *error_msg = StringPrintf("Opening CompactDex file '%s' is only supported from vdex files",
    415                               location.c_str());
    416     return nullptr;
    417   }
    418   if (dex_file == nullptr) {
    419     if (verify_result == VerifyResult::kVerifyNotAttempted) {
    420       *error_code = ZipOpenErrorCode::kDexFileError;
    421     } else {
    422       *error_code = ZipOpenErrorCode::kVerifyError;
    423     }
    424     return nullptr;
    425   }
    426   if (!dex_file->DisableWrite()) {
    427     *error_msg = StringPrintf("Failed to make dex file '%s' read only", location.c_str());
    428     *error_code = ZipOpenErrorCode::kMakeReadOnlyError;
    429     return nullptr;
    430   }
    431   CHECK(dex_file->IsReadOnly()) << location;
    432   if (verify_result != VerifyResult::kVerifySucceeded) {
    433     *error_code = ZipOpenErrorCode::kVerifyError;
    434     return nullptr;
    435   }
    436   *error_code = ZipOpenErrorCode::kNoError;
    437   return dex_file;
    438 }
    439 
    440 // Technically we do not have a limitation with respect to the number of dex files that can be in a
    441 // multidex APK. However, it's bad practice, as each dex file requires its own tables for symbols
    442 // (types, classes, methods, ...) and dex caches. So warn the user that we open a zip with what
    443 // seems an excessive number.
    444 static constexpr size_t kWarnOnManyDexFilesThreshold = 100;
    445 
    446 bool ArtDexFileLoader::OpenAllDexFilesFromZip(
    447     const ZipArchive& zip_archive,
    448     const std::string& location,
    449     bool verify,
    450     bool verify_checksum,
    451     std::string* error_msg,
    452     std::vector<std::unique_ptr<const DexFile>>* dex_files) const {
    453   ScopedTrace trace("Dex file open from Zip " + std::string(location));
    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 
    509 std::unique_ptr<DexFile> ArtDexFileLoader::OpenCommon(const uint8_t* base,
    510                                                       size_t size,
    511                                                       const uint8_t* data_base,
    512                                                       size_t data_size,
    513                                                       const std::string& location,
    514                                                       uint32_t location_checksum,
    515                                                       const OatDexFile* oat_dex_file,
    516                                                       bool verify,
    517                                                       bool verify_checksum,
    518                                                       std::string* error_msg,
    519                                                       std::unique_ptr<DexFileContainer> container,
    520                                                       VerifyResult* verify_result) {
    521   std::unique_ptr<DexFile> dex_file = DexFileLoader::OpenCommon(base,
    522                                                                 size,
    523                                                                 data_base,
    524                                                                 data_size,
    525                                                                 location,
    526                                                                 location_checksum,
    527                                                                 oat_dex_file,
    528                                                                 verify,
    529                                                                 verify_checksum,
    530                                                                 error_msg,
    531                                                                 std::move(container),
    532                                                                 verify_result);
    533 
    534   // Check if this dex file is located in the framework directory.
    535   // If it is, set a flag on the dex file. This is used by hidden API
    536   // policy decision logic.
    537   // Location can contain multidex suffix, so fetch its canonical version. Note
    538   // that this will call `realpath`.
    539   std::string path = DexFileLoader::GetDexCanonicalLocation(location.c_str());
    540   if (dex_file != nullptr && LocationIsOnSystemFramework(path.c_str())) {
    541     dex_file->SetIsPlatformDexFile();
    542   }
    543 
    544   return dex_file;
    545 }
    546 
    547 }  // namespace art
    548