dex_file_verifier_test.cc revision df10b32c4d0adfa86201169692eaa7ef038b642c
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 <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 222