blob: 93faeaee7cac750cc96ce9a45b4b5047fd74a8d1 [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
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());
Andreas Gampe833a4852014-05-21 18:46:59 -0700118 std::vector<const DexFile*> tmp;
119 bool success = DexFile::Open(location, location, error_msg, &tmp);
120 CHECK(success) << error_msg;
121 EXPECT_EQ(1U, tmp.size());
122 const DexFile* dex_file = tmp[0];
123 EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
124 EXPECT_TRUE(dex_file->IsReadOnly());
125 return dex_file;
Andreas Gampedf10b322014-06-11 21:46:05 -0700126}
127
128
129// For reference.
130static const char kGoodTestDex[] =
131 "ZGV4CjAzNQDrVbyVkxX1HljTznNf95AglkUAhQuFtmKkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAN"
132 "AAAAcAAAAAYAAACkAAAAAgAAALwAAAABAAAA1AAAAAQAAADcAAAAAQAAAPwAAACIAQAAHAEAAFoB"
133 "AABiAQAAagEAAIEBAACVAQAAqQEAAL0BAADDAQAAzgEAANEBAADVAQAA2gEAAN8BAAABAAAAAgAA"
134 "AAMAAAAEAAAABQAAAAgAAAAIAAAABQAAAAAAAAAJAAAABQAAAFQBAAAEAAEACwAAAAAAAAAAAAAA"
135 "AAAAAAoAAAABAAEADAAAAAIAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAcAAAAAAAAA8wEAAAAAAAAB"
136 "AAEAAQAAAOgBAAAEAAAAcBADAAAADgACAAAAAgAAAO0BAAAIAAAAYgAAABoBBgBuIAIAEAAOAAEA"
137 "AAADAAY8aW5pdD4ABkxUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09i"
138 "amVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AARUZXN0AAlUZXN0"
139 "LmphdmEAAVYAAlZMAANmb28AA291dAAHcHJpbnRsbgABAAcOAAMABw54AAAAAgAAgYAEnAIBCbQC"
140 "AAAADQAAAAAAAAABAAAAAAAAAAEAAAANAAAAcAAAAAIAAAAGAAAApAAAAAMAAAACAAAAvAAAAAQA"
141 "AAABAAAA1AAAAAUAAAAEAAAA3AAAAAYAAAABAAAA/AAAAAEgAAACAAAAHAEAAAEQAAABAAAAVAEA"
142 "AAIgAAANAAAAWgEAAAMgAAACAAAA6AEAAAAgAAABAAAA8wEAAAAQAAABAAAABAIAAA==";
143
144TEST_F(DexFileVerifierTest, GoodDex) {
145 ScratchFile tmp;
146 std::string error_msg;
147 std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex, tmp.GetFilename().c_str(),
148 &error_msg));
149 ASSERT_TRUE(raw.get() != nullptr) << error_msg;
150}
151
152static void FixUpChecksum(byte* dex_file) {
153 DexFile::Header* header = reinterpret_cast<DexFile::Header*>(dex_file);
154 uint32_t expected_size = header->file_size_;
155 uint32_t adler_checksum = adler32(0L, Z_NULL, 0);
156 const uint32_t non_sum = sizeof(DexFile::Header::magic_) + sizeof(DexFile::Header::checksum_);
157 const byte* non_sum_ptr = dex_file + non_sum;
158 adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
159 header->checksum_ = adler_checksum;
160}
161
162static const DexFile* FixChecksumAndOpen(byte* bytes, size_t length, const char* location,
163 std::string* error_msg) {
164 // Check data.
165 CHECK(bytes != nullptr);
166
167 // Fixup of checksum.
168 FixUpChecksum(bytes);
169
170 // write to provided file
171 std::unique_ptr<File> file(OS::CreateEmptyFile(location));
172 CHECK(file.get() != NULL);
173 if (!file->WriteFully(bytes, length)) {
174 PLOG(FATAL) << "Failed to write base64 as dex file";
175 }
176 file.reset();
177
178 // read dex file
179 ScopedObjectAccess soa(Thread::Current());
Andreas Gampe833a4852014-05-21 18:46:59 -0700180 std::vector<const DexFile*> tmp;
181 if (!DexFile::Open(location, location, error_msg, &tmp)) {
182 return nullptr;
183 }
184 EXPECT_EQ(1U, tmp.size());
185 const DexFile* dex_file = tmp[0];
186 EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
187 EXPECT_TRUE(dex_file->IsReadOnly());
188 return dex_file;
Andreas Gampedf10b322014-06-11 21:46:05 -0700189}
190
191static bool ModifyAndLoad(const char* location, size_t offset, uint8_t new_val,
192 std::string* error_msg) {
193 // Decode base64.
194 size_t length;
195 std::unique_ptr<byte[]> dex_bytes(DecodeBase64(kGoodTestDex, &length));
196 CHECK(dex_bytes.get() != NULL);
197
198 // Make modifications.
199 dex_bytes.get()[offset] = new_val;
200
201 // Fixup and load.
202 std::unique_ptr<const DexFile> file(FixChecksumAndOpen(dex_bytes.get(), length, location,
203 error_msg));
204 return file.get() != nullptr;
205}
206
207TEST_F(DexFileVerifierTest, MethodId) {
208 {
209 // Class error.
210 ScratchFile tmp;
211 std::string error_msg;
212 bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 220, 0xFFU, &error_msg);
213 ASSERT_TRUE(success);
214 ASSERT_NE(error_msg.find("inter_method_id_item class_idx"), std::string::npos) << error_msg;
215 }
216
217 {
218 // Proto error.
219 ScratchFile tmp;
220 std::string error_msg;
221 bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 222, 0xFFU, &error_msg);
222 ASSERT_TRUE(success);
223 ASSERT_NE(error_msg.find("inter_method_id_item proto_idx"), std::string::npos) << error_msg;
224 }
225
226 {
227 // Name error.
228 ScratchFile tmp;
229 std::string error_msg;
230 bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 224, 0xFFU, &error_msg);
231 ASSERT_TRUE(success);
232 ASSERT_NE(error_msg.find("inter_method_id_item name_idx"), std::string::npos) << error_msg;
233 }
234}
235
236} // namespace art