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 uint8_t 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 uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
     59   std::vector<uint8_t> tmp;
     60   uint32_t t = 0, y = 0;
     61   int g = 3;
     62   for (size_t i = 0; src[i] != '\0'; ++i) {
     63     uint8_t 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<uint8_t[]> dst(new uint8_t[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 std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64,
    105                                                         const char* location,
    106                                                         std::string* error_msg) {
    107   // decode base64
    108   CHECK(base64 != nullptr);
    109   size_t length;
    110   std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length));
    111   CHECK(dex_bytes.get() != nullptr);
    112 
    113   // write to provided file
    114   std::unique_ptr<File> file(OS::CreateEmptyFile(location));
    115   CHECK(file.get() != nullptr);
    116   if (!file->WriteFully(dex_bytes.get(), length)) {
    117     PLOG(FATAL) << "Failed to write base64 as dex file";
    118   }
    119   if (file->FlushCloseOrErase() != 0) {
    120     PLOG(FATAL) << "Could not flush and close test file.";
    121   }
    122   file.reset();
    123 
    124   // read dex file
    125   ScopedObjectAccess soa(Thread::Current());
    126   std::vector<std::unique_ptr<const DexFile>> tmp;
    127   bool success = DexFile::Open(location, location, error_msg, &tmp);
    128   CHECK(success) << error_msg;
    129   EXPECT_EQ(1U, tmp.size());
    130   std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
    131   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
    132   EXPECT_TRUE(dex_file->IsReadOnly());
    133   return dex_file;
    134 }
    135 
    136 
    137 // For reference.
    138 static const char kGoodTestDex[] =
    139     "ZGV4CjAzNQDrVbyVkxX1HljTznNf95AglkUAhQuFtmKkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAN"
    140     "AAAAcAAAAAYAAACkAAAAAgAAALwAAAABAAAA1AAAAAQAAADcAAAAAQAAAPwAAACIAQAAHAEAAFoB"
    141     "AABiAQAAagEAAIEBAACVAQAAqQEAAL0BAADDAQAAzgEAANEBAADVAQAA2gEAAN8BAAABAAAAAgAA"
    142     "AAMAAAAEAAAABQAAAAgAAAAIAAAABQAAAAAAAAAJAAAABQAAAFQBAAAEAAEACwAAAAAAAAAAAAAA"
    143     "AAAAAAoAAAABAAEADAAAAAIAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAcAAAAAAAAA8wEAAAAAAAAB"
    144     "AAEAAQAAAOgBAAAEAAAAcBADAAAADgACAAAAAgAAAO0BAAAIAAAAYgAAABoBBgBuIAIAEAAOAAEA"
    145     "AAADAAY8aW5pdD4ABkxUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09i"
    146     "amVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AARUZXN0AAlUZXN0"
    147     "LmphdmEAAVYAAlZMAANmb28AA291dAAHcHJpbnRsbgABAAcOAAMABw54AAAAAgAAgYAEnAIBCbQC"
    148     "AAAADQAAAAAAAAABAAAAAAAAAAEAAAANAAAAcAAAAAIAAAAGAAAApAAAAAMAAAACAAAAvAAAAAQA"
    149     "AAABAAAA1AAAAAUAAAAEAAAA3AAAAAYAAAABAAAA/AAAAAEgAAACAAAAHAEAAAEQAAABAAAAVAEA"
    150     "AAIgAAANAAAAWgEAAAMgAAACAAAA6AEAAAAgAAABAAAA8wEAAAAQAAABAAAABAIAAA==";
    151 
    152 TEST_F(DexFileVerifierTest, GoodDex) {
    153   ScratchFile tmp;
    154   std::string error_msg;
    155   std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex, tmp.GetFilename().c_str(),
    156                                                        &error_msg));
    157   ASSERT_TRUE(raw.get() != nullptr) << error_msg;
    158 }
    159 
    160 static void FixUpChecksum(uint8_t* dex_file) {
    161   DexFile::Header* header = reinterpret_cast<DexFile::Header*>(dex_file);
    162   uint32_t expected_size = header->file_size_;
    163   uint32_t adler_checksum = adler32(0L, Z_NULL, 0);
    164   const uint32_t non_sum = sizeof(DexFile::Header::magic_) + sizeof(DexFile::Header::checksum_);
    165   const uint8_t* non_sum_ptr = dex_file + non_sum;
    166   adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
    167   header->checksum_ = adler_checksum;
    168 }
    169 
    170 static std::unique_ptr<const DexFile> FixChecksumAndOpen(uint8_t* bytes, size_t length,
    171                                                          const char* location,
    172                                                          std::string* error_msg) {
    173   // Check data.
    174   CHECK(bytes != nullptr);
    175 
    176   // Fixup of checksum.
    177   FixUpChecksum(bytes);
    178 
    179   // write to provided file
    180   std::unique_ptr<File> file(OS::CreateEmptyFile(location));
    181   CHECK(file.get() != nullptr);
    182   if (!file->WriteFully(bytes, length)) {
    183     PLOG(FATAL) << "Failed to write base64 as dex file";
    184   }
    185   if (file->FlushCloseOrErase() != 0) {
    186     PLOG(FATAL) << "Could not flush and close test file.";
    187   }
    188   file.reset();
    189 
    190   // read dex file
    191   ScopedObjectAccess soa(Thread::Current());
    192   std::vector<std::unique_ptr<const DexFile>> tmp;
    193   if (!DexFile::Open(location, location, error_msg, &tmp)) {
    194     return nullptr;
    195   }
    196   EXPECT_EQ(1U, tmp.size());
    197   std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
    198   EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
    199   EXPECT_TRUE(dex_file->IsReadOnly());
    200   return dex_file;
    201 }
    202 
    203 static bool ModifyAndLoad(const char* dex_file_content, const char* location, size_t offset,
    204                           uint8_t new_val, std::string* error_msg) {
    205   // Decode base64.
    206   size_t length;
    207   std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(dex_file_content, &length));
    208   CHECK(dex_bytes.get() != nullptr);
    209 
    210   // Make modifications.
    211   dex_bytes.get()[offset] = new_val;
    212 
    213   // Fixup and load.
    214   std::unique_ptr<const DexFile> file(FixChecksumAndOpen(dex_bytes.get(), length, location,
    215                                                          error_msg));
    216   return file.get() != nullptr;
    217 }
    218 
    219 TEST_F(DexFileVerifierTest, MethodId) {
    220   {
    221     // Class error.
    222     ScratchFile tmp;
    223     std::string error_msg;
    224     bool success = !ModifyAndLoad(kGoodTestDex, tmp.GetFilename().c_str(), 220, 0xFFU, &error_msg);
    225     ASSERT_TRUE(success);
    226     ASSERT_NE(error_msg.find("inter_method_id_item class_idx"), std::string::npos) << error_msg;
    227   }
    228 
    229   {
    230     // Proto error.
    231     ScratchFile tmp;
    232     std::string error_msg;
    233     bool success = !ModifyAndLoad(kGoodTestDex, tmp.GetFilename().c_str(), 222, 0xFFU, &error_msg);
    234     ASSERT_TRUE(success);
    235     ASSERT_NE(error_msg.find("inter_method_id_item proto_idx"), std::string::npos) << error_msg;
    236   }
    237 
    238   {
    239     // Name error.
    240     ScratchFile tmp;
    241     std::string error_msg;
    242     bool success = !ModifyAndLoad(kGoodTestDex, tmp.GetFilename().c_str(), 224, 0xFFU, &error_msg);
    243     ASSERT_TRUE(success);
    244     ASSERT_NE(error_msg.find("inter_method_id_item name_idx"), std::string::npos) << error_msg;
    245   }
    246 }
    247 
    248 // Generated from:
    249 //
    250 // .class public LTest;
    251 // .super Ljava/lang/Object;
    252 // .source "Test.java"
    253 //
    254 // .method public constructor <init>()V
    255 //     .registers 1
    256 //
    257 //     .prologue
    258 //     .line 1
    259 //     invoke-direct {p0}, Ljava/lang/Object;-><init>()V
    260 //
    261 //     return-void
    262 // .end method
    263 //
    264 // .method public static main()V
    265 //     .registers 2
    266 //
    267 //     const-string v0, "a"
    268 //     const-string v0, "b"
    269 //     const-string v0, "c"
    270 //     const-string v0, "d"
    271 //     const-string v0, "e"
    272 //     const-string v0, "f"
    273 //     const-string v0, "g"
    274 //     const-string v0, "h"
    275 //     const-string v0, "i"
    276 //     const-string v0, "j"
    277 //     const-string v0, "k"
    278 //
    279 //     .local v1, "local_var":Ljava/lang/String;
    280 //     const-string v1, "test"
    281 // .end method
    282 
    283 static const char kDebugInfoTestDex[] =
    284     "ZGV4CjAzNQCHRkHix2eIMQgvLD/0VGrlllZLo0Rb6VyUAgAAcAAAAHhWNBIAAAAAAAAAAAwCAAAU"
    285     "AAAAcAAAAAQAAADAAAAAAQAAANAAAAAAAAAAAAAAAAMAAADcAAAAAQAAAPQAAACAAQAAFAEAABQB"
    286     "AAAcAQAAJAEAADgBAABMAQAAVwEAAFoBAABdAQAAYAEAAGMBAABmAQAAaQEAAGwBAABvAQAAcgEA"
    287     "AHUBAAB4AQAAewEAAIYBAACMAQAAAQAAAAIAAAADAAAABQAAAAUAAAADAAAAAAAAAAAAAAAAAAAA"
    288     "AAAAABIAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAAEAAAAAAAAAPwBAAAAAAAABjxpbml0PgAG"
    289     "TFRlc3Q7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAJVGVzdC5qYXZh"
    290     "AAFWAAFhAAFiAAFjAAFkAAFlAAFmAAFnAAFoAAFpAAFqAAFrAAlsb2NhbF92YXIABG1haW4ABHRl"
    291     "c3QAAAABAAcOAAAAARYDARIDAAAAAQABAAEAAACUAQAABAAAAHAQAgAAAA4AAgAAAAAAAACZAQAA"
    292     "GAAAABoABgAaAAcAGgAIABoACQAaAAoAGgALABoADAAaAA0AGgAOABoADwAaABAAGgETAAAAAgAA"
    293     "gYAEpAMBCbwDAAALAAAAAAAAAAEAAAAAAAAAAQAAABQAAABwAAAAAgAAAAQAAADAAAAAAwAAAAEA"
    294     "AADQAAAABQAAAAMAAADcAAAABgAAAAEAAAD0AAAAAiAAABQAAAAUAQAAAyAAAAIAAACUAQAAASAA"
    295     "AAIAAACkAQAAACAAAAEAAAD8AQAAABAAAAEAAAAMAgAA";
    296 
    297 TEST_F(DexFileVerifierTest, DebugInfoTypeIdxTest) {
    298   {
    299     // The input dex file should be good before modification.
    300     ScratchFile tmp;
    301     std::string error_msg;
    302     std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kDebugInfoTestDex,
    303                                                          tmp.GetFilename().c_str(),
    304                                                          &error_msg));
    305     ASSERT_TRUE(raw.get() != nullptr) << error_msg;
    306   }
    307 
    308   {
    309     // Modify the debug information entry.
    310     ScratchFile tmp;
    311     std::string error_msg;
    312     bool success = !ModifyAndLoad(kDebugInfoTestDex, tmp.GetFilename().c_str(), 416, 0x14U,
    313                                   &error_msg);
    314     ASSERT_TRUE(success);
    315     ASSERT_NE(error_msg.find("DBG_START_LOCAL type_idx"), std::string::npos) << error_msg;
    316   }
    317 }
    318 
    319 }  // namespace art
    320