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