blob: 9f1ffec35fcac734192c2ec57e47a62bb697e822 [file] [log] [blame]
Andreas Gampedf10b322014-06-11 21:46:05 -07001/*
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
Ian Rogerse63db272014-07-15 15:36:11 -070019#include "sys/mman.h"
Andreas Gampedf10b322014-06-11 21:46:05 -070020#include "zlib.h"
Ian Rogerse63db272014-07-15 15:36:11 -070021#include <memory>
Andreas Gampedf10b322014-06-11 21:46:05 -070022
Ian Rogerse63db272014-07-15 15:36:11 -070023#include "base/unix_file/fd_file.h"
Andreas Gampedf10b322014-06-11 21:46:05 -070024#include "base/macros.h"
Ian Rogerse63db272014-07-15 15:36:11 -070025#include "common_runtime_test.h"
26#include "scoped_thread_state_change.h"
27#include "thread-inl.h"
Andreas Gampedf10b322014-06-11 21:46:05 -070028
29namespace art {
30
31class DexFileVerifierTest : public CommonRuntimeTest {};
32
Ian Rogers13735952014-10-08 12:43:28 -070033static const uint8_t kBase64Map[256] = {
Andreas Gampedf10b322014-06-11 21:46:05 -070034 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
Ian Rogers13735952014-10-08 12:43:28 -070058static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) {
59 std::vector<uint8_t> tmp;
Andreas Gampedf10b322014-06-11 21:46:05 -070060 uint32_t t = 0, y = 0;
61 int g = 3;
62 for (size_t i = 0; src[i] != '\0'; ++i) {
Ian Rogers13735952014-10-08 12:43:28 -070063 uint8_t c = kBase64Map[src[i] & 0xFF];
Andreas Gampedf10b322014-06-11 21:46:05 -070064 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 }
Ian Rogers13735952014-10-08 12:43:28 -070094 std::unique_ptr<uint8_t[]> dst(new uint8_t[tmp.size()]);
Andreas Gampedf10b322014-06-11 21:46:05 -070095 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
Richard Uhlerfbef44d2014-12-23 09:48:51 -0800104static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64,
105 const char* location,
106 std::string* error_msg) {
Andreas Gampedf10b322014-06-11 21:46:05 -0700107 // decode base64
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700108 CHECK(base64 != nullptr);
Andreas Gampedf10b322014-06-11 21:46:05 -0700109 size_t length;
Ian Rogers13735952014-10-08 12:43:28 -0700110 std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length));
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700111 CHECK(dex_bytes.get() != nullptr);
Andreas Gampedf10b322014-06-11 21:46:05 -0700112
113 // write to provided file
114 std::unique_ptr<File> file(OS::CreateEmptyFile(location));
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700115 CHECK(file.get() != nullptr);
Andreas Gampedf10b322014-06-11 21:46:05 -0700116 if (!file->WriteFully(dex_bytes.get(), length)) {
117 PLOG(FATAL) << "Failed to write base64 as dex file";
118 }
Andreas Gampe4303ba92014-11-06 01:00:46 -0800119 if (file->FlushCloseOrErase() != 0) {
120 PLOG(FATAL) << "Could not flush and close test file.";
121 }
Andreas Gampedf10b322014-06-11 21:46:05 -0700122 file.reset();
123
124 // read dex file
125 ScopedObjectAccess soa(Thread::Current());
Richard Uhlerfbef44d2014-12-23 09:48:51 -0800126 std::vector<std::unique_ptr<const DexFile>> tmp;
Andreas Gampe833a4852014-05-21 18:46:59 -0700127 bool success = DexFile::Open(location, location, error_msg, &tmp);
128 CHECK(success) << error_msg;
129 EXPECT_EQ(1U, tmp.size());
Richard Uhlerfbef44d2014-12-23 09:48:51 -0800130 std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
Andreas Gampe833a4852014-05-21 18:46:59 -0700131 EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
132 EXPECT_TRUE(dex_file->IsReadOnly());
133 return dex_file;
Andreas Gampedf10b322014-06-11 21:46:05 -0700134}
135
136
137// For reference.
138static 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
152TEST_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
Ian Rogers13735952014-10-08 12:43:28 -0700160static void FixUpChecksum(uint8_t* dex_file) {
Andreas Gampedf10b322014-06-11 21:46:05 -0700161 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_);
Ian Rogers13735952014-10-08 12:43:28 -0700165 const uint8_t* non_sum_ptr = dex_file + non_sum;
Andreas Gampedf10b322014-06-11 21:46:05 -0700166 adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
167 header->checksum_ = adler_checksum;
168}
169
Richard Uhlerfbef44d2014-12-23 09:48:51 -0800170static std::unique_ptr<const DexFile> FixChecksumAndOpen(uint8_t* bytes, size_t length,
171 const char* location,
172 std::string* error_msg) {
Andreas Gampedf10b322014-06-11 21:46:05 -0700173 // 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));
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700181 CHECK(file.get() != nullptr);
Andreas Gampedf10b322014-06-11 21:46:05 -0700182 if (!file->WriteFully(bytes, length)) {
183 PLOG(FATAL) << "Failed to write base64 as dex file";
184 }
Andreas Gampe4303ba92014-11-06 01:00:46 -0800185 if (file->FlushCloseOrErase() != 0) {
186 PLOG(FATAL) << "Could not flush and close test file.";
187 }
Andreas Gampedf10b322014-06-11 21:46:05 -0700188 file.reset();
189
190 // read dex file
191 ScopedObjectAccess soa(Thread::Current());
Richard Uhlerfbef44d2014-12-23 09:48:51 -0800192 std::vector<std::unique_ptr<const DexFile>> tmp;
Andreas Gampe833a4852014-05-21 18:46:59 -0700193 if (!DexFile::Open(location, location, error_msg, &tmp)) {
194 return nullptr;
195 }
196 EXPECT_EQ(1U, tmp.size());
Richard Uhlerfbef44d2014-12-23 09:48:51 -0800197 std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]);
Andreas Gampe833a4852014-05-21 18:46:59 -0700198 EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
199 EXPECT_TRUE(dex_file->IsReadOnly());
200 return dex_file;
Andreas Gampedf10b322014-06-11 21:46:05 -0700201}
202
Logan Chiendd3208d2015-04-19 23:27:52 +0800203static bool ModifyAndLoad(const char* dex_file_content, const char* location, size_t offset,
204 uint8_t new_val, std::string* error_msg) {
Andreas Gampedf10b322014-06-11 21:46:05 -0700205 // Decode base64.
206 size_t length;
Logan Chiendd3208d2015-04-19 23:27:52 +0800207 std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(dex_file_content, &length));
Mathieu Chartier2cebb242015-04-21 16:50:40 -0700208 CHECK(dex_bytes.get() != nullptr);
Andreas Gampedf10b322014-06-11 21:46:05 -0700209
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
219TEST_F(DexFileVerifierTest, MethodId) {
220 {
221 // Class error.
222 ScratchFile tmp;
223 std::string error_msg;
Logan Chiendd3208d2015-04-19 23:27:52 +0800224 bool success = !ModifyAndLoad(kGoodTestDex, tmp.GetFilename().c_str(), 220, 0xFFU, &error_msg);
Andreas Gampedf10b322014-06-11 21:46:05 -0700225 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;
Logan Chiendd3208d2015-04-19 23:27:52 +0800233 bool success = !ModifyAndLoad(kGoodTestDex, tmp.GetFilename().c_str(), 222, 0xFFU, &error_msg);
Andreas Gampedf10b322014-06-11 21:46:05 -0700234 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;
Logan Chiendd3208d2015-04-19 23:27:52 +0800242 bool success = !ModifyAndLoad(kGoodTestDex, tmp.GetFilename().c_str(), 224, 0xFFU, &error_msg);
Andreas Gampedf10b322014-06-11 21:46:05 -0700243 ASSERT_TRUE(success);
244 ASSERT_NE(error_msg.find("inter_method_id_item name_idx"), std::string::npos) << error_msg;
245 }
246}
247
Logan Chiendd3208d2015-04-19 23:27:52 +0800248// 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
283static 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
297TEST_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
Andreas Gampedf10b322014-06-11 21:46:05 -0700319} // namespace art