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 #ifndef ART_RUNTIME_DEX_FILE_VERIFIER_H_ 18 #define ART_RUNTIME_DEX_FILE_VERIFIER_H_ 19 20 #include <unordered_set> 21 22 #include "base/allocator.h" 23 #include "base/hash_map.h" 24 #include "dex_file.h" 25 #include "dex_file_types.h" 26 #include "safe_map.h" 27 28 namespace art { 29 30 class DexFileVerifier { 31 public: 32 static bool Verify(const DexFile* dex_file, 33 const uint8_t* begin, 34 size_t size, 35 const char* location, 36 bool verify_checksum, 37 std::string* error_msg); 38 39 const std::string& FailureReason() const { 40 return failure_reason_; 41 } 42 43 private: 44 DexFileVerifier(const DexFile* dex_file, 45 const uint8_t* begin, 46 size_t size, 47 const char* location, 48 bool verify_checksum) 49 : dex_file_(dex_file), 50 begin_(begin), 51 size_(size), 52 location_(location), 53 verify_checksum_(verify_checksum), 54 header_(&dex_file->GetHeader()), 55 ptr_(nullptr), 56 previous_item_(nullptr) { 57 } 58 59 bool Verify(); 60 61 bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, bool is_return_type); 62 bool CheckListSize(const void* start, size_t count, size_t element_size, const char* label); 63 // Check a list. The head is assumed to be at *ptr, and elements to be of size element_size. If 64 // successful, the ptr will be moved forward the amount covered by the list. 65 bool CheckList(size_t element_size, const char* label, const uint8_t* *ptr); 66 // Checks whether the offset is zero (when size is zero) or that the offset falls within the area 67 // claimed by the file. 68 bool CheckValidOffsetAndSize(uint32_t offset, uint32_t size, size_t alignment, const char* label); 69 // Checks whether the size is less than the limit. 70 bool CheckSizeLimit(uint32_t size, uint32_t limit, const char* label); 71 bool CheckIndex(uint32_t field, uint32_t limit, const char* label); 72 73 bool CheckHeader(); 74 bool CheckMap(); 75 76 uint32_t ReadUnsignedLittleEndian(uint32_t size); 77 bool CheckAndGetHandlerOffsets(const DexFile::CodeItem* code_item, 78 uint32_t* handler_offsets, uint32_t handlers_size); 79 bool CheckClassDataItemField(uint32_t idx, 80 uint32_t access_flags, 81 uint32_t class_access_flags, 82 dex::TypeIndex class_type_index, 83 bool expect_static); 84 bool CheckClassDataItemMethod(uint32_t idx, 85 uint32_t access_flags, 86 uint32_t class_access_flags, 87 dex::TypeIndex class_type_index, 88 uint32_t code_offset, 89 std::unordered_set<uint32_t>* direct_method_indexes, 90 bool expect_direct); 91 bool CheckOrderAndGetClassDef(bool is_field, 92 const char* type_descr, 93 uint32_t curr_index, 94 uint32_t prev_index, 95 bool* have_class, 96 dex::TypeIndex* class_type_index, 97 const DexFile::ClassDef** class_def); 98 bool CheckStaticFieldTypes(const DexFile::ClassDef* class_def); 99 100 bool CheckPadding(size_t offset, uint32_t aligned_offset); 101 bool CheckEncodedValue(); 102 bool CheckEncodedArray(); 103 bool CheckEncodedAnnotation(); 104 105 bool CheckIntraClassDataItem(); 106 // Check all fields of the given type from the given iterator. Load the class data from the first 107 // field, if necessary (and return it), or use the given values. 108 template <bool kStatic> 109 bool CheckIntraClassDataItemFields(ClassDataItemIterator* it, 110 bool* have_class, 111 dex::TypeIndex* class_type_index, 112 const DexFile::ClassDef** class_def); 113 // Check all methods of the given type from the given iterator. Load the class data from the first 114 // method, if necessary (and return it), or use the given values. 115 template <bool kDirect> 116 bool CheckIntraClassDataItemMethods(ClassDataItemIterator* it, 117 std::unordered_set<uint32_t>* direct_method_indexes, 118 bool* have_class, 119 dex::TypeIndex* class_type_index, 120 const DexFile::ClassDef** class_def); 121 122 bool CheckIntraCodeItem(); 123 bool CheckIntraStringDataItem(); 124 bool CheckIntraDebugInfoItem(); 125 bool CheckIntraAnnotationItem(); 126 bool CheckIntraAnnotationsDirectoryItem(); 127 128 bool CheckIntraSectionIterate(size_t offset, uint32_t count, DexFile::MapItemType type); 129 bool CheckIntraIdSection(size_t offset, uint32_t count, DexFile::MapItemType type); 130 bool CheckIntraDataSection(size_t offset, uint32_t count, DexFile::MapItemType type); 131 bool CheckIntraSection(); 132 133 bool CheckOffsetToTypeMap(size_t offset, uint16_t type); 134 135 // Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an 136 // additional out parameter to signal any errors loading an index. 137 dex::TypeIndex FindFirstClassDataDefiner(const uint8_t* ptr, bool* success); 138 dex::TypeIndex FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success); 139 140 bool CheckInterStringIdItem(); 141 bool CheckInterTypeIdItem(); 142 bool CheckInterProtoIdItem(); 143 bool CheckInterFieldIdItem(); 144 bool CheckInterMethodIdItem(); 145 bool CheckInterClassDefItem(); 146 bool CheckInterCallSiteIdItem(); 147 bool CheckInterMethodHandleItem(); 148 bool CheckInterAnnotationSetRefList(); 149 bool CheckInterAnnotationSetItem(); 150 bool CheckInterClassDataItem(); 151 bool CheckInterAnnotationsDirectoryItem(); 152 153 bool CheckInterSectionIterate(size_t offset, uint32_t count, DexFile::MapItemType type); 154 bool CheckInterSection(); 155 156 // Load a string by (type) index. Checks whether the index is in bounds, printing the error if 157 // not. If there is an error, null is returned. 158 const char* CheckLoadStringByIdx(dex::StringIndex idx, const char* error_fmt); 159 const char* CheckLoadStringByTypeIdx(dex::TypeIndex type_idx, const char* error_fmt); 160 161 // Load a field/method/proto Id by index. Checks whether the index is in bounds, printing the 162 // error if not. If there is an error, null is returned. 163 const DexFile::FieldId* CheckLoadFieldId(uint32_t idx, const char* error_fmt); 164 const DexFile::MethodId* CheckLoadMethodId(uint32_t idx, const char* error_fmt); 165 const DexFile::ProtoId* CheckLoadProtoId(uint32_t idx, const char* error_fmt); 166 167 void ErrorStringPrintf(const char* fmt, ...) 168 __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR; 169 bool FailureReasonIsSet() const { return failure_reason_.size() != 0; } 170 171 // Retrieve class index and class def from the given member. index is the member index, which is 172 // taken as either a field or a method index (as designated by is_field). The result, if the 173 // member and declaring class could be found, is stored in class_type_index and class_def. 174 // This is an expensive lookup, as we have to find the class def by type index, which is a 175 // linear search. The output values should thus be cached by the caller. 176 bool FindClassIndexAndDef(uint32_t index, 177 bool is_field, 178 dex::TypeIndex* class_type_index, 179 const DexFile::ClassDef** output_class_def); 180 181 // Check validity of the given access flags, interpreted for a field in the context of a class 182 // with the given second access flags. 183 bool CheckFieldAccessFlags(uint32_t idx, 184 uint32_t field_access_flags, 185 uint32_t class_access_flags, 186 std::string* error_message); 187 188 // Check validity of the given method and access flags, in the context of a class with the given 189 // second access flags. 190 bool CheckMethodAccessFlags(uint32_t method_index, 191 uint32_t method_access_flags, 192 uint32_t class_access_flags, 193 uint32_t constructor_flags_by_name, 194 bool has_code, 195 bool expect_direct, 196 std::string* error_message); 197 198 // Check validity of given method if it's a constructor or class initializer. 199 bool CheckConstructorProperties(uint32_t method_index, uint32_t constructor_flags); 200 201 const DexFile* const dex_file_; 202 const uint8_t* const begin_; 203 const size_t size_; 204 const char* const location_; 205 const bool verify_checksum_; 206 const DexFile::Header* const header_; 207 208 struct OffsetTypeMapEmptyFn { 209 // Make a hash map slot empty by making the offset 0. Offset 0 is a valid dex file offset that 210 // is in the offset of the dex file header. However, we only store data section items in the 211 // map, and these are after the header. 212 void MakeEmpty(std::pair<uint32_t, uint16_t>& pair) const { 213 pair.first = 0u; 214 } 215 // Check if a hash map slot is empty. 216 bool IsEmpty(const std::pair<uint32_t, uint16_t>& pair) const { 217 return pair.first == 0; 218 } 219 }; 220 struct OffsetTypeMapHashCompareFn { 221 // Hash function for offset. 222 size_t operator()(const uint32_t key) const { 223 return key; 224 } 225 // std::equal function for offset. 226 bool operator()(const uint32_t a, const uint32_t b) const { 227 return a == b; 228 } 229 }; 230 // Map from offset to dex file type, HashMap for performance reasons. 231 template<class Key, 232 class T, 233 class EmptyFn, 234 AllocatorTag kTag, 235 class Hash = std::hash<Key>, 236 class Pred = std::equal_to<Key>> 237 using AllocationTrackingHashMap = HashMap< 238 Key, T, EmptyFn, Hash, Pred, TrackingAllocator<std::pair<Key, T>, kTag>>; 239 240 AllocationTrackingHashMap<uint32_t, 241 uint16_t, 242 OffsetTypeMapEmptyFn, 243 kAllocatorTagDexFileVerifier, 244 OffsetTypeMapHashCompareFn, 245 OffsetTypeMapHashCompareFn> offset_to_type_map_; 246 const uint8_t* ptr_; 247 const void* previous_item_; 248 249 std::string failure_reason_; 250 251 // Set of type ids for which there are ClassDef elements in the dex file. 252 std::unordered_set<decltype(DexFile::ClassDef::class_idx_)> defined_classes_; 253 }; 254 255 } // namespace art 256 257 #endif // ART_RUNTIME_DEX_FILE_VERIFIER_H_ 258