Home | History | Annotate | Download | only in runtime
      1 /*
      2  * Copyright (C) 2011 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_verifier.h"
     18 
     19 #include "sys/mman.h"
     20 #include "zlib.h"
     21 #include <memory>
     22 
     23 #include "base/unix_file/fd_file.h"
     24 #include "base/macros.h"
     25 #include "common_runtime_test.h"
     26 #include "scoped_thread_state_change.h"
     27 #include "thread-inl.h"
     28 
     29 namespace art {
     30 
     31 class DexFileVerifierTest : public CommonRuntimeTest {};
     32 
     33 static const byte kBase64Map[256] = {
     34   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     35   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     36   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     37   255, 255, 255, 255, 255, 255, 255,  62, 255, 255, 255,  63,
     38   52,  53,  54,  55,  56,  57,  58,  59,  60,  61, 255, 255,
     39   255, 254, 255, 255, 255,   0,   1,   2,   3,   4,   5,   6,
     40     7,   8,   9,  10,  11,  12,  13,  14,  15,  16,  17,  18,  // NOLINT
     41    19,  20,  21,  22,  23,  24,  25, 255, 255, 255, 255, 255,  // NOLINT
     42   255,  26,  27,  28,  29,  30,  31,  32,  33,  34,  35,  36,
     43    37,  38,  39,  40,  41,  42,  43,  44,  45,  46,  47,  48,  // NOLINT
     44    49,  50,  51, 255, 255, 255, 255, 255, 255, 255, 255, 255,  // NOLINT
     45   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     46   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     47   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     48   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     49   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     50   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     51   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     52   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     53   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     54   255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
     55   255, 255, 255, 255
     56 };
     57 
     58 static inline byte* DecodeBase64(const char* src, size_t* dst_size) {
     59   std::vector<byte> tmp;
     60   uint32_t t = 0, y = 0;
     61   int g = 3;
     62   for (size_t i = 0; src[i] != '\0'; ++i) {
     63     byte c = kBase64Map[src[i] & 0xFF];
     64     if (c == 255) continue;
     65     // the final = symbols are read and used to trim the remaining bytes
     66     if (c == 254) {
     67       c = 0;
     68       // prevent g < 0 which would potentially allow an overflow later
     69       if (--g < 0) {
     70         *dst_size = 0;
     71         return nullptr;
     72       }
     73     } else if (g != 3) {
     74       // we only allow = to be at the end
     75       *dst_size = 0;
     76       return nullptr;
     77     }
     78     t = (t << 6) | c;
     79     if (++y == 4) {
     80       tmp.push_back((t >> 16) & 255);
     81       if (g > 1) {
     82         tmp.push_back((t >> 8) & 255);
     83       }
     84       if (g > 2) {
     85         tmp.push_back(t & 255);
     86       }
     87       y = t = 0;
     88     }
     89   }
     90   if (y != 0) {
     91     *dst_size = 0;
     92     return nullptr;
     93   }
     94   std::unique_ptr<byte[]> dst(new byte[tmp.size()]);
     95   if (dst_size != nullptr) {
     96     *dst_size = tmp.size();
     97   } else {
     98     *dst_size = 0;
     99   }
    100   std::copy(tmp.begin(), tmp.end(), dst.get());
    101   return dst.release();
    102 }
    103 
    104 static const DexFile* OpenDexFileBase64(const char* base64, const char* location,
    105                                         std::string* error_msg) {
    106   // decode base64
    107   CHECK(base64 != NULL);
    108   size_t length;
    109   std::unique_ptr<byte[]> dex_bytes(DecodeBase64(base64, &length));
    110   CHECK(dex_bytes.get() != NULL);
    111 
    112   // write to provided file
    113   std::unique_ptr<File> file(OS::CreateEmptyFile(location));
    114   CHECK(file.get() != NULL);
    115   if (!file->WriteFully(dex_bytes.get(), length)) {
    116     PLOG(FATAL) << "Failed to write base64 as dex file";
    117   }
    118   file.reset();
    119 
    120   // read dex file
    121   ScopedObjectAccess soa(Thread::Current());
    122   std::vector<const DexFile*> tmp;
    123   bool success = DexFile::Open(location, location, error_msg, &tmp);
    124   CHECK(success) << error_msg;
    125   EXPECT_EQ(1U, tmp.size());
    126   const DexFile* dex_file = tmp[0];
    127   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
    128   EXPECT_TRUE(dex_file->IsReadOnly());
    129   return dex_file;
    130 }
    131 
    132 
    133 // For reference.
    134 static const char kGoodTestDex[] =
    135     "ZGV4CjAzNQDrVbyVkxX1HljTznNf95AglkUAhQuFtmKkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAN"
    136     "AAAAcAAAAAYAAACkAAAAAgAAALwAAAABAAAA1AAAAAQAAADcAAAAAQAAAPwAAACIAQAAHAEAAFoB"
    137     "AABiAQAAagEAAIEBAACVAQAAqQEAAL0BAADDAQAAzgEAANEBAADVAQAA2gEAAN8BAAABAAAAAgAA"
    138     "AAMAAAAEAAAABQAAAAgAAAAIAAAABQAAAAAAAAAJAAAABQAAAFQBAAAEAAEACwAAAAAAAAAAAAAA"
    139     "AAAAAAoAAAABAAEADAAAAAIAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAcAAAAAAAAA8wEAAAAAAAAB"
    140     "AAEAAQAAAOgBAAAEAAAAcBADAAAADgACAAAAAgAAAO0BAAAIAAAAYgAAABoBBgBuIAIAEAAOAAEA"
    141     "AAADAAY8aW5pdD4ABkxUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09i"
    142     "amVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AARUZXN0AAlUZXN0"
    143     "LmphdmEAAVYAAlZMAANmb28AA291dAAHcHJpbnRsbgABAAcOAAMABw54AAAAAgAAgYAEnAIBCbQC"
    144     "AAAADQAAAAAAAAABAAAAAAAAAAEAAAANAAAAcAAAAAIAAAAGAAAApAAAAAMAAAACAAAAvAAAAAQA"
    145     "AAABAAAA1AAAAAUAAAAEAAAA3AAAAAYAAAABAAAA/AAAAAEgAAACAAAAHAEAAAEQAAABAAAAVAEA"
    146     "AAIgAAANAAAAWgEAAAMgAAACAAAA6AEAAAAgAAABAAAA8wEAAAAQAAABAAAABAIAAA==";
    147 
    148 TEST_F(DexFileVerifierTest, GoodDex) {
    149   ScratchFile tmp;
    150   std::string error_msg;
    151   std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex, tmp.GetFilename().c_str(),
    152                                                        &error_msg));
    153   ASSERT_TRUE(raw.get() != nullptr) << error_msg;
    154 }
    155 
    156 static void FixUpChecksum(byte* dex_file) {
    157   DexFile::Header* header = reinterpret_cast<DexFile::Header*>(dex_file);
    158   uint32_t expected_size = header->file_size_;
    159   uint32_t adler_checksum = adler32(0L, Z_NULL, 0);
    160   const uint32_t non_sum = sizeof(DexFile::Header::magic_) + sizeof(DexFile::Header::checksum_);
    161   const byte* non_sum_ptr = dex_file + non_sum;
    162   adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
    163   header->checksum_ = adler_checksum;
    164 }
    165 
    166 static const DexFile* FixChecksumAndOpen(byte* bytes, size_t length, const char* location,
    167                                          std::string* error_msg) {
    168   // Check data.
    169   CHECK(bytes != nullptr);
    170 
    171   // Fixup of checksum.
    172   FixUpChecksum(bytes);
    173 
    174   // write to provided file
    175   std::unique_ptr<File> file(OS::CreateEmptyFile(location));
    176   CHECK(file.get() != NULL);
    177   if (!file->WriteFully(bytes, length)) {
    178     PLOG(FATAL) << "Failed to write base64 as dex file";
    179   }
    180   file.reset();
    181 
    182   // read dex file
    183   ScopedObjectAccess soa(Thread::Current());
    184   std::vector<const DexFile*> tmp;
    185   if (!DexFile::Open(location, location, error_msg, &tmp)) {
    186     return nullptr;
    187   }
    188   EXPECT_EQ(1U, tmp.size());
    189   const DexFile* dex_file = tmp[0];
    190   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
    191   EXPECT_TRUE(dex_file->IsReadOnly());
    192   return dex_file;
    193 }
    194 
    195 static bool ModifyAndLoad(const char* location, size_t offset, uint8_t new_val,
    196                                     std::string* error_msg) {
    197   // Decode base64.
    198   size_t length;
    199   std::unique_ptr<byte[]> dex_bytes(DecodeBase64(kGoodTestDex, &length));
    200   CHECK(dex_bytes.get() != NULL);
    201 
    202   // Make modifications.
    203   dex_bytes.get()[offset] = new_val;
    204 
    205   // Fixup and load.
    206   std::unique_ptr<const DexFile> file(FixChecksumAndOpen(dex_bytes.get(), length, location,
    207                                                          error_msg));
    208   return file.get() != nullptr;
    209 }
    210 
    211 TEST_F(DexFileVerifierTest, MethodId) {
    212   {
    213     // Class error.
    214     ScratchFile tmp;
    215     std::string error_msg;
    216     bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 220, 0xFFU, &error_msg);
    217     ASSERT_TRUE(success);
    218     ASSERT_NE(error_msg.find("inter_method_id_item class_idx"), std::string::npos) << error_msg;
    219   }
    220 
    221   {
    222     // Proto error.
    223     ScratchFile tmp;
    224     std::string error_msg;
    225     bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 222, 0xFFU, &error_msg);
    226     ASSERT_TRUE(success);
    227     ASSERT_NE(error_msg.find("inter_method_id_item proto_idx"), std::string::npos) << error_msg;
    228   }
    229 
    230   {
    231     // Name error.
    232     ScratchFile tmp;
    233     std::string error_msg;
    234     bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 224, 0xFFU, &error_msg);
    235     ASSERT_TRUE(success);
    236     ASSERT_NE(error_msg.find("inter_method_id_item name_idx"), std::string::npos) << error_msg;
    237   }
    238 }
    239 
    240 }  // namespace art
    241