1 /*
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 "sys/mman.h"
20 #include "zlib.h"
21 #include <memory>
22
23 #include "base/unix_file/fd_file.h"
24 #include "base/macros.h"
25 #include "common_runtime_test.h"
26 #include "scoped_thread_state_change.h"
27 #include "thread-inl.h"
28
29 namespace art {
30
31 class DexFileVerifierTest : public CommonRuntimeTest {};
32
33 static 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
DecodeBase64(const char * src,size_t * dst_size)58 static 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
OpenDexFileBase64(const char * base64,const char * location,std::string * error_msg)104 static 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 if (file->FlushCloseOrErase() != 0) {
119 PLOG(FATAL) << "Could not flush and close test file.";
120 }
121 file.reset();
122
123 // read dex file
124 ScopedObjectAccess soa(Thread::Current());
125 std::vector<const DexFile*> tmp;
126 bool success = DexFile::Open(location, location, error_msg, &tmp);
127 CHECK(success) << error_msg;
128 EXPECT_EQ(1U, tmp.size());
129 const DexFile* dex_file = tmp[0];
130 EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
131 EXPECT_TRUE(dex_file->IsReadOnly());
132 return dex_file;
133 }
134
135
136 // For reference.
137 static const char kGoodTestDex[] =
138 "ZGV4CjAzNQDrVbyVkxX1HljTznNf95AglkUAhQuFtmKkAgAAcAAAAHhWNBIAAAAAAAAAAAQCAAAN"
139 "AAAAcAAAAAYAAACkAAAAAgAAALwAAAABAAAA1AAAAAQAAADcAAAAAQAAAPwAAACIAQAAHAEAAFoB"
140 "AABiAQAAagEAAIEBAACVAQAAqQEAAL0BAADDAQAAzgEAANEBAADVAQAA2gEAAN8BAAABAAAAAgAA"
141 "AAMAAAAEAAAABQAAAAgAAAAIAAAABQAAAAAAAAAJAAAABQAAAFQBAAAEAAEACwAAAAAAAAAAAAAA"
142 "AAAAAAoAAAABAAEADAAAAAIAAAAAAAAAAAAAAAEAAAACAAAAAAAAAAcAAAAAAAAA8wEAAAAAAAAB"
143 "AAEAAQAAAOgBAAAEAAAAcBADAAAADgACAAAAAgAAAO0BAAAIAAAAYgAAABoBBgBuIAIAEAAOAAEA"
144 "AAADAAY8aW5pdD4ABkxUZXN0OwAVTGphdmEvaW8vUHJpbnRTdHJlYW07ABJMamF2YS9sYW5nL09i"
145 "amVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwASTGphdmEvbGFuZy9TeXN0ZW07AARUZXN0AAlUZXN0"
146 "LmphdmEAAVYAAlZMAANmb28AA291dAAHcHJpbnRsbgABAAcOAAMABw54AAAAAgAAgYAEnAIBCbQC"
147 "AAAADQAAAAAAAAABAAAAAAAAAAEAAAANAAAAcAAAAAIAAAAGAAAApAAAAAMAAAACAAAAvAAAAAQA"
148 "AAABAAAA1AAAAAUAAAAEAAAA3AAAAAYAAAABAAAA/AAAAAEgAAACAAAAHAEAAAEQAAABAAAAVAEA"
149 "AAIgAAANAAAAWgEAAAMgAAACAAAA6AEAAAAgAAABAAAA8wEAAAAQAAABAAAABAIAAA==";
150
TEST_F(DexFileVerifierTest,GoodDex)151 TEST_F(DexFileVerifierTest, GoodDex) {
152 ScratchFile tmp;
153 std::string error_msg;
154 std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kGoodTestDex, tmp.GetFilename().c_str(),
155 &error_msg));
156 ASSERT_TRUE(raw.get() != nullptr) << error_msg;
157 }
158
FixUpChecksum(byte * dex_file)159 static void FixUpChecksum(byte* dex_file) {
160 DexFile::Header* header = reinterpret_cast<DexFile::Header*>(dex_file);
161 uint32_t expected_size = header->file_size_;
162 uint32_t adler_checksum = adler32(0L, Z_NULL, 0);
163 const uint32_t non_sum = sizeof(DexFile::Header::magic_) + sizeof(DexFile::Header::checksum_);
164 const byte* non_sum_ptr = dex_file + non_sum;
165 adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum);
166 header->checksum_ = adler_checksum;
167 }
168
FixChecksumAndOpen(byte * bytes,size_t length,const char * location,std::string * error_msg)169 static const DexFile* FixChecksumAndOpen(byte* bytes, size_t length, const char* location,
170 std::string* error_msg) {
171 // Check data.
172 CHECK(bytes != nullptr);
173
174 // Fixup of checksum.
175 FixUpChecksum(bytes);
176
177 // write to provided file
178 std::unique_ptr<File> file(OS::CreateEmptyFile(location));
179 CHECK(file.get() != NULL);
180 if (!file->WriteFully(bytes, length)) {
181 PLOG(FATAL) << "Failed to write base64 as dex file";
182 }
183 if (file->FlushCloseOrErase() != 0) {
184 PLOG(FATAL) << "Could not flush and close test file.";
185 }
186 file.reset();
187
188 // read dex file
189 ScopedObjectAccess soa(Thread::Current());
190 std::vector<const DexFile*> tmp;
191 if (!DexFile::Open(location, location, error_msg, &tmp)) {
192 return nullptr;
193 }
194 EXPECT_EQ(1U, tmp.size());
195 const DexFile* dex_file = tmp[0];
196 EXPECT_EQ(PROT_READ, dex_file->GetPermissions());
197 EXPECT_TRUE(dex_file->IsReadOnly());
198 return dex_file;
199 }
200
ModifyAndLoad(const char * location,size_t offset,uint8_t new_val,std::string * error_msg)201 static bool ModifyAndLoad(const char* location, size_t offset, uint8_t new_val,
202 std::string* error_msg) {
203 // Decode base64.
204 size_t length;
205 std::unique_ptr<byte[]> dex_bytes(DecodeBase64(kGoodTestDex, &length));
206 CHECK(dex_bytes.get() != NULL);
207
208 // Make modifications.
209 dex_bytes.get()[offset] = new_val;
210
211 // Fixup and load.
212 std::unique_ptr<const DexFile> file(FixChecksumAndOpen(dex_bytes.get(), length, location,
213 error_msg));
214 return file.get() != nullptr;
215 }
216
TEST_F(DexFileVerifierTest,MethodId)217 TEST_F(DexFileVerifierTest, MethodId) {
218 {
219 // Class error.
220 ScratchFile tmp;
221 std::string error_msg;
222 bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 220, 0xFFU, &error_msg);
223 ASSERT_TRUE(success);
224 ASSERT_NE(error_msg.find("inter_method_id_item class_idx"), std::string::npos) << error_msg;
225 }
226
227 {
228 // Proto error.
229 ScratchFile tmp;
230 std::string error_msg;
231 bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 222, 0xFFU, &error_msg);
232 ASSERT_TRUE(success);
233 ASSERT_NE(error_msg.find("inter_method_id_item proto_idx"), std::string::npos) << error_msg;
234 }
235
236 {
237 // Name error.
238 ScratchFile tmp;
239 std::string error_msg;
240 bool success = !ModifyAndLoad(tmp.GetFilename().c_str(), 224, 0xFFU, &error_msg);
241 ASSERT_TRUE(success);
242 ASSERT_NE(error_msg.find("inter_method_id_item name_idx"), std::string::npos) << error_msg;
243 }
244 }
245
246 } // namespace art
247