blob: d0ce00fc66270e5f911204eea30d272093b5d195 [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());
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