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 uint8_t 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 58 static inline uint8_t* DecodeBase64(const char* src, size_t* dst_size) { 59 std::vector<uint8_t> tmp; 60 uint32_t t = 0, y = 0; 61 int g = 3; 62 for (size_t i = 0; src[i] != '\0'; ++i) { 63 uint8_t 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<uint8_t[]> dst(new uint8_t[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 104 static std::unique_ptr<const DexFile> OpenDexFileBase64(const char* base64, 105 const char* location, 106 std::string* error_msg) { 107 // decode base64 108 CHECK(base64 != nullptr); 109 size_t length; 110 std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(base64, &length)); 111 CHECK(dex_bytes.get() != nullptr); 112 113 // write to provided file 114 std::unique_ptr<File> file(OS::CreateEmptyFile(location)); 115 CHECK(file.get() != nullptr); 116 if (!file->WriteFully(dex_bytes.get(), length)) { 117 PLOG(FATAL) << "Failed to write base64 as dex file"; 118 } 119 if (file->FlushCloseOrErase() != 0) { 120 PLOG(FATAL) << "Could not flush and close test file."; 121 } 122 file.reset(); 123 124 // read dex file 125 ScopedObjectAccess soa(Thread::Current()); 126 std::vector<std::unique_ptr<const DexFile>> tmp; 127 bool success = DexFile::Open(location, location, error_msg, &tmp); 128 CHECK(success) << error_msg; 129 EXPECT_EQ(1U, tmp.size()); 130 std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]); 131 EXPECT_EQ(PROT_READ, dex_file->GetPermissions()); 132 EXPECT_TRUE(dex_file->IsReadOnly()); 133 return dex_file; 134 } 135 136 137 // For reference. 138 static 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 152 TEST_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 160 static void FixUpChecksum(uint8_t* dex_file) { 161 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_); 165 const uint8_t* non_sum_ptr = dex_file + non_sum; 166 adler_checksum = adler32(adler_checksum, non_sum_ptr, expected_size - non_sum); 167 header->checksum_ = adler_checksum; 168 } 169 170 static std::unique_ptr<const DexFile> FixChecksumAndOpen(uint8_t* bytes, size_t length, 171 const char* location, 172 std::string* error_msg) { 173 // 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() != nullptr); 182 if (!file->WriteFully(bytes, length)) { 183 PLOG(FATAL) << "Failed to write base64 as dex file"; 184 } 185 if (file->FlushCloseOrErase() != 0) { 186 PLOG(FATAL) << "Could not flush and close test file."; 187 } 188 file.reset(); 189 190 // read dex file 191 ScopedObjectAccess soa(Thread::Current()); 192 std::vector<std::unique_ptr<const DexFile>> tmp; 193 if (!DexFile::Open(location, location, error_msg, &tmp)) { 194 return nullptr; 195 } 196 EXPECT_EQ(1U, tmp.size()); 197 std::unique_ptr<const DexFile> dex_file = std::move(tmp[0]); 198 EXPECT_EQ(PROT_READ, dex_file->GetPermissions()); 199 EXPECT_TRUE(dex_file->IsReadOnly()); 200 return dex_file; 201 } 202 203 static bool ModifyAndLoad(const char* dex_file_content, const char* location, size_t offset, 204 uint8_t new_val, std::string* error_msg) { 205 // Decode base64. 206 size_t length; 207 std::unique_ptr<uint8_t[]> dex_bytes(DecodeBase64(dex_file_content, &length)); 208 CHECK(dex_bytes.get() != nullptr); 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 219 TEST_F(DexFileVerifierTest, MethodId) { 220 { 221 // Class error. 222 ScratchFile tmp; 223 std::string error_msg; 224 bool success = !ModifyAndLoad(kGoodTestDex, 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(kGoodTestDex, 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(kGoodTestDex, 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 // Generated from: 249 // 250 // .class public LTest; 251 // .super Ljava/lang/Object; 252 // .source "Test.java" 253 // 254 // .method public constructor <init>()V 255 // .registers 1 256 // 257 // .prologue 258 // .line 1 259 // invoke-direct {p0}, Ljava/lang/Object;-><init>()V 260 // 261 // return-void 262 // .end method 263 // 264 // .method public static main()V 265 // .registers 2 266 // 267 // const-string v0, "a" 268 // const-string v0, "b" 269 // const-string v0, "c" 270 // const-string v0, "d" 271 // const-string v0, "e" 272 // const-string v0, "f" 273 // const-string v0, "g" 274 // const-string v0, "h" 275 // const-string v0, "i" 276 // const-string v0, "j" 277 // const-string v0, "k" 278 // 279 // .local v1, "local_var":Ljava/lang/String; 280 // const-string v1, "test" 281 // .end method 282 283 static const char kDebugInfoTestDex[] = 284 "ZGV4CjAzNQCHRkHix2eIMQgvLD/0VGrlllZLo0Rb6VyUAgAAcAAAAHhWNBIAAAAAAAAAAAwCAAAU" 285 "AAAAcAAAAAQAAADAAAAAAQAAANAAAAAAAAAAAAAAAAMAAADcAAAAAQAAAPQAAACAAQAAFAEAABQB" 286 "AAAcAQAAJAEAADgBAABMAQAAVwEAAFoBAABdAQAAYAEAAGMBAABmAQAAaQEAAGwBAABvAQAAcgEA" 287 "AHUBAAB4AQAAewEAAIYBAACMAQAAAQAAAAIAAAADAAAABQAAAAUAAAADAAAAAAAAAAAAAAAAAAAA" 288 "AAAAABIAAAABAAAAAAAAAAAAAAABAAAAAQAAAAAAAAAEAAAAAAAAAPwBAAAAAAAABjxpbml0PgAG" 289 "TFRlc3Q7ABJMamF2YS9sYW5nL09iamVjdDsAEkxqYXZhL2xhbmcvU3RyaW5nOwAJVGVzdC5qYXZh" 290 "AAFWAAFhAAFiAAFjAAFkAAFlAAFmAAFnAAFoAAFpAAFqAAFrAAlsb2NhbF92YXIABG1haW4ABHRl" 291 "c3QAAAABAAcOAAAAARYDARIDAAAAAQABAAEAAACUAQAABAAAAHAQAgAAAA4AAgAAAAAAAACZAQAA" 292 "GAAAABoABgAaAAcAGgAIABoACQAaAAoAGgALABoADAAaAA0AGgAOABoADwAaABAAGgETAAAAAgAA" 293 "gYAEpAMBCbwDAAALAAAAAAAAAAEAAAAAAAAAAQAAABQAAABwAAAAAgAAAAQAAADAAAAAAwAAAAEA" 294 "AADQAAAABQAAAAMAAADcAAAABgAAAAEAAAD0AAAAAiAAABQAAAAUAQAAAyAAAAIAAACUAQAAASAA" 295 "AAIAAACkAQAAACAAAAEAAAD8AQAAABAAAAEAAAAMAgAA"; 296 297 TEST_F(DexFileVerifierTest, DebugInfoTypeIdxTest) { 298 { 299 // The input dex file should be good before modification. 300 ScratchFile tmp; 301 std::string error_msg; 302 std::unique_ptr<const DexFile> raw(OpenDexFileBase64(kDebugInfoTestDex, 303 tmp.GetFilename().c_str(), 304 &error_msg)); 305 ASSERT_TRUE(raw.get() != nullptr) << error_msg; 306 } 307 308 { 309 // Modify the debug information entry. 310 ScratchFile tmp; 311 std::string error_msg; 312 bool success = !ModifyAndLoad(kDebugInfoTestDex, tmp.GetFilename().c_str(), 416, 0x14U, 313 &error_msg); 314 ASSERT_TRUE(success); 315 ASSERT_NE(error_msg.find("DBG_START_LOCAL type_idx"), std::string::npos) << error_msg; 316 } 317 } 318 319 } // namespace art 320