blob: 00ca8a9169e8025b839e8daf7e2a2435df2f5b99 [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
108 CHECK(base64 != NULL);
109 size_t length;
Ian Rogers13735952014-10-08 12:43:28 -0700110 std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length));
Andreas Gampedf10b322014-06-11 21:46:05 -0700111 CHECK(dex_bytes.get() != NULL);
112
113 // write to provided file
114 std::unique_ptr<File> file(OS::CreateEmptyFile(location));
115 CHECK(file.get() != NULL);
116 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));
181 CHECK(file.get() != NULL);
182 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
203static bool ModifyAndLoad(const char* location, size_t offset, uint8_t new_val,
204 std::string* error_msg) {
205 // Decode base64.
206 size_t length;
Ian Rogers13735952014-10-08 12:43:28 -0700207 std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(kGoodTestDex, &length));
Andreas Gampedf10b322014-06-11 21:46:05 -0700208 CHECK(dex_bytes.get() != NULL);
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
219TEST_F(DexFileVerifierTest, MethodId) {
220 {
221 // Class error.
222 ScratchFile tmp;
223 std::string error_msg;
224 bool success = !ModifyAndLoad(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(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(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} // namespace art