blob: d475d426ff2d4d35da88eaac53fb757eb14ca641 [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
33static 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
58static 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
104static 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());
Andreas Gampe833a4852014-05-21 18:46:59 -0700122 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;
Andreas Gampedf10b322014-06-11 21:46:05 -0700130}
131
132
133// For reference.
134static 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
148TEST_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
156static 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
166static 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());
Andreas Gampe833a4852014-05-21 18:46:59 -0700184 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;
Andreas Gampedf10b322014-06-11 21:46:05 -0700193}
194
195static 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
211TEST_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