diff options
author | 2019-07-02 14:03:13 -0700 | |
---|---|---|
committer | 2019-07-05 15:58:24 +0000 | |
commit | 60415ae617133fd06b3dd909b6db37f5c26dcd6b (patch) | |
tree | 0cae4f834b8398b6f8ef52a942b7dfc94db724fc | |
parent | 07a560d98c5e5e6dfcdb966d19f9d2cc155ace4f (diff) |
ART: Move DexFileVerifier class to cc file
Hide all details. None were accessible before anyways. Instead,
only expose art::dex::Verify.
Test: m test-art-host
Change-Id: I19a68440045622b78c1678c92027f6e0e1185d75
-rw-r--r-- | libdexfile/dex/class_accessor.h | 9 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_loader.cc | 12 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_verifier.cc | 286 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_verifier.h | 266 | ||||
-rw-r--r-- | libdexfile/dex/dex_file_verifier_test.cc | 158 | ||||
-rw-r--r-- | openjdkjvmti/fixed_up_dex_file.cc | 12 |
6 files changed, 376 insertions, 367 deletions
diff --git a/libdexfile/dex/class_accessor.h b/libdexfile/dex/class_accessor.h index 16282562cc..a3ee2bd386 100644 --- a/libdexfile/dex/class_accessor.h +++ b/libdexfile/dex/class_accessor.h @@ -27,6 +27,7 @@ namespace art { namespace dex { struct ClassDef; struct CodeItem; +class DexFileVerifier; } // namespace dex class ClassIteratorData; @@ -146,7 +147,7 @@ class ClassAccessor { uint32_t code_off_ = 0u; friend class ClassAccessor; - friend class DexFileVerifier; + friend class dex::DexFileVerifier; }; // A decoded version of the field of a class_data_item. @@ -172,7 +173,7 @@ class ClassAccessor { bool is_static_ = true; friend class ClassAccessor; - friend class DexFileVerifier; + friend class dex::DexFileVerifier; }; template <typename DataType> @@ -264,7 +265,7 @@ class ClassAccessor { // At iterator_end_, the iterator is no longer valid. const uint32_t iterator_end_; - friend class DexFileVerifier; + friend class dex::DexFileVerifier; }; // Not explicit specifically for range-based loops. @@ -390,7 +391,7 @@ class ClassAccessor { const uint32_t num_direct_methods_ = 0u; const uint32_t num_virtual_methods_ = 0u; - friend class DexFileVerifier; + friend class dex::DexFileVerifier; }; } // namespace art diff --git a/libdexfile/dex/dex_file_loader.cc b/libdexfile/dex/dex_file_loader.cc index 54b90d3d0c..7ccc93f8e7 100644 --- a/libdexfile/dex/dex_file_loader.cc +++ b/libdexfile/dex/dex_file_loader.cc @@ -370,12 +370,12 @@ std::unique_ptr<DexFile> DexFileLoader::OpenCommon(const uint8_t* base, dex_file.reset(); return nullptr; } - if (verify && !DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - location.c_str(), - verify_checksum, - error_msg)) { + if (verify && !dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + location.c_str(), + verify_checksum, + error_msg)) { if (verify_result != nullptr) { *verify_result = VerifyResult::kVerifyFailed; } diff --git a/libdexfile/dex/dex_file_verifier.cc b/libdexfile/dex/dex_file_verifier.cc index 580d0b7cfb..96cc773695 100644 --- a/libdexfile/dex/dex_file_verifier.cc +++ b/libdexfile/dex/dex_file_verifier.cc @@ -16,30 +16,279 @@ #include "dex_file_verifier.h" -#include <inttypes.h> - #include <algorithm> +#include <bitset> +#include <limits> #include <memory> #include "android-base/logging.h" #include "android-base/macros.h" #include "android-base/stringprintf.h" +#include "base/hash_map.h" #include "base/leb128.h" +#include "base/safe_map.h" #include "class_accessor-inl.h" #include "code_item_accessors-inl.h" #include "descriptors_names.h" #include "dex_file-inl.h" +#include "dex_file_types.h" #include "modifiers.h" #include "utf-inl.h" namespace art { +namespace dex { + +// Note: an anonymous namespace would be nice, but we need friend access into accessors. using android::base::StringAppendV; using android::base::StringPrintf; static constexpr uint32_t kTypeIdLimit = std::numeric_limits<uint16_t>::max(); +class DexFileVerifier { + public: + DexFileVerifier(const DexFile* dex_file, + const uint8_t* begin, + size_t size, + const char* location, + bool verify_checksum) + : dex_file_(dex_file), + begin_(begin), + size_(size), + location_(location), + verify_checksum_(verify_checksum), + header_(&dex_file->GetHeader()), + ptr_(nullptr), + previous_item_(nullptr), + init_indices_{std::numeric_limits<size_t>::max(), + std::numeric_limits<size_t>::max(), + std::numeric_limits<size_t>::max(), + std::numeric_limits<size_t>::max()} { + } + + bool Verify(); + + const std::string& FailureReason() const { + return failure_reason_; + } + + private: + bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, bool is_return_type); + bool CheckListSize(const void* start, size_t count, size_t element_size, const char* label); + // Check a list. The head is assumed to be at *ptr, and elements to be of size element_size. If + // successful, the ptr will be moved forward the amount covered by the list. + bool CheckList(size_t element_size, const char* label, const uint8_t* *ptr); + // Checks whether the offset is zero (when size is zero) or that the offset falls within the area + // claimed by the file. + bool CheckValidOffsetAndSize(uint32_t offset, uint32_t size, size_t alignment, const char* label); + // Checks whether the size is less than the limit. + bool CheckSizeLimit(uint32_t size, uint32_t limit, const char* label); + bool CheckIndex(uint32_t field, uint32_t limit, const char* label); + + bool CheckHeader(); + bool CheckMap(); + + uint32_t ReadUnsignedLittleEndian(uint32_t size); + bool CheckAndGetHandlerOffsets(const dex::CodeItem* code_item, + uint32_t* handler_offsets, uint32_t handlers_size); + bool CheckClassDataItemField(uint32_t idx, + uint32_t access_flags, + uint32_t class_access_flags, + dex::TypeIndex class_type_index, + bool expect_static); + bool CheckClassDataItemMethod(uint32_t idx, + uint32_t access_flags, + uint32_t class_access_flags, + dex::TypeIndex class_type_index, + uint32_t code_offset, + ClassAccessor::Method* direct_method, + size_t* remaining_directs); + ALWAYS_INLINE + bool CheckOrder(const char* type_descr, uint32_t curr_index, uint32_t prev_index); + bool CheckStaticFieldTypes(const dex::ClassDef* class_def); + + bool CheckPadding(size_t offset, uint32_t aligned_offset, DexFile::MapItemType type); + bool CheckEncodedValue(); + bool CheckEncodedArray(); + bool CheckEncodedAnnotation(); + + bool CheckIntraClassDataItem(); + // Check all fields of the given type from the given iterator. Load the class data from the first + // field, if necessary (and return it), or use the given values. + template <bool kStatic> + bool CheckIntraClassDataItemFields(size_t count, + ClassAccessor::Field* field, + bool* have_class, + dex::TypeIndex* class_type_index, + const dex::ClassDef** class_def); + // Check all methods of the given type from the given iterator. Load the class data from the first + // method, if necessary (and return it), or use the given values. + bool CheckIntraClassDataItemMethods(ClassAccessor::Method* method, + size_t num_methods, + ClassAccessor::Method* direct_method, + size_t num_directs, + bool* have_class, + dex::TypeIndex* class_type_index, + const dex::ClassDef** class_def); + + bool CheckIntraCodeItem(); + bool CheckIntraStringDataItem(); + bool CheckIntraDebugInfoItem(); + bool CheckIntraAnnotationItem(); + bool CheckIntraAnnotationsDirectoryItem(); + bool CheckIntraHiddenapiClassData(); + + template <DexFile::MapItemType kType> + bool CheckIntraSectionIterate(size_t offset, uint32_t count); + template <DexFile::MapItemType kType> + bool CheckIntraIdSection(size_t offset, uint32_t count); + template <DexFile::MapItemType kType> + bool CheckIntraDataSection(size_t offset, uint32_t count); + bool CheckIntraSection(); + + bool CheckOffsetToTypeMap(size_t offset, uint16_t type); + + // Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an + // additional out parameter to signal any errors loading an index. + dex::TypeIndex FindFirstClassDataDefiner(const uint8_t* ptr, bool* success); + dex::TypeIndex FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success); + + bool CheckInterStringIdItem(); + bool CheckInterTypeIdItem(); + bool CheckInterProtoIdItem(); + bool CheckInterFieldIdItem(); + bool CheckInterMethodIdItem(); + bool CheckInterClassDefItem(); + bool CheckInterCallSiteIdItem(); + bool CheckInterMethodHandleItem(); + bool CheckInterAnnotationSetRefList(); + bool CheckInterAnnotationSetItem(); + bool CheckInterClassDataItem(); + bool CheckInterAnnotationsDirectoryItem(); + + bool CheckInterSectionIterate(size_t offset, uint32_t count, DexFile::MapItemType type); + bool CheckInterSection(); + + // Load a string by (type) index. Checks whether the index is in bounds, printing the error if + // not. If there is an error, null is returned. + const char* CheckLoadStringByIdx(dex::StringIndex idx, const char* error_fmt); + const char* CheckLoadStringByTypeIdx(dex::TypeIndex type_idx, const char* error_fmt); + + // Load a field/method/proto Id by index. Checks whether the index is in bounds, printing the + // error if not. If there is an error, null is returned. + const dex::FieldId* CheckLoadFieldId(uint32_t idx, const char* error_fmt); + const dex::MethodId* CheckLoadMethodId(uint32_t idx, const char* error_fmt); + const dex::ProtoId* CheckLoadProtoId(dex::ProtoIndex idx, const char* error_fmt); + + void ErrorStringPrintf(const char* fmt, ...) + __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR; + bool FailureReasonIsSet() const { return failure_reason_.size() != 0; } + + // Retrieve class index and class def from the given member. index is the member index, which is + // taken as either a field or a method index (as designated by is_field). The result, if the + // member and declaring class could be found, is stored in class_type_index and class_def. + // This is an expensive lookup, as we have to find the class def by type index, which is a + // linear search. The output values should thus be cached by the caller. + bool FindClassIndexAndDef(uint32_t index, + bool is_field, + dex::TypeIndex* class_type_index, + const dex::ClassDef** output_class_def); + + // Check validity of the given access flags, interpreted for a field in the context of a class + // with the given second access flags. + bool CheckFieldAccessFlags(uint32_t idx, + uint32_t field_access_flags, + uint32_t class_access_flags, + std::string* error_message); + + // Check validity of the given method and access flags, in the context of a class with the given + // second access flags. + bool CheckMethodAccessFlags(uint32_t method_index, + uint32_t method_access_flags, + uint32_t class_access_flags, + uint32_t constructor_flags_by_name, + bool has_code, + bool expect_direct, + std::string* error_message); + + // Check validity of given method if it's a constructor or class initializer. + bool CheckConstructorProperties(uint32_t method_index, uint32_t constructor_flags); + + void FindStringRangesForMethodNames(); + + template <typename ExtraCheckFn> + bool VerifyTypeDescriptor(dex::TypeIndex idx, + const char* error_msg1, + const char* error_msg2, + ExtraCheckFn extra_check); + + const DexFile* const dex_file_; + const uint8_t* const begin_; + const size_t size_; + const char* const location_; + const bool verify_checksum_; + const DexFile::Header* const header_; + + struct OffsetTypeMapEmptyFn { + // Make a hash map slot empty by making the offset 0. Offset 0 is a valid dex file offset that + // is in the offset of the dex file header. However, we only store data section items in the + // map, and these are after the header. + void MakeEmpty(std::pair<uint32_t, uint16_t>& pair) const { + pair.first = 0u; + } + // Check if a hash map slot is empty. + bool IsEmpty(const std::pair<uint32_t, uint16_t>& pair) const { + return pair.first == 0; + } + }; + struct OffsetTypeMapHashCompareFn { + // Hash function for offset. + size_t operator()(const uint32_t key) const { + return key; + } + // std::equal function for offset. + bool operator()(const uint32_t a, const uint32_t b) const { + return a == b; + } + }; + // Map from offset to dex file type, HashMap for performance reasons. + HashMap<uint32_t, + uint16_t, + OffsetTypeMapEmptyFn, + OffsetTypeMapHashCompareFn, + OffsetTypeMapHashCompareFn> offset_to_type_map_; + const uint8_t* ptr_; + const void* previous_item_; + + std::string failure_reason_; + + // Cached string indices for "interesting" entries wrt/ method names. Will be populated by + // FindStringRangesForMethodNames (which is automatically called before verifying the + // classdataitem section). + // + // Strings starting with '<' are in the range + // [angle_bracket_start_index_,angle_bracket_end_index_). + // angle_init_angle_index_ and angle_clinit_angle_index_ denote the indices of "<init>" and + // "<clinit>", respectively. If any value is not found, the corresponding index will be larger + // than any valid string index for this dex file. + struct { + size_t angle_bracket_start_index; + size_t angle_bracket_end_index; + size_t angle_init_angle_index; + size_t angle_clinit_angle_index; + } init_indices_; + + // A bitvector for verified type descriptors. Each bit corresponds to a type index. A set + // bit denotes that the descriptor has been verified wrt/ IsValidDescriptor. + std::vector<char> verified_type_descriptors_; + + // Set of type ids for which there are ClassDef elements in the dex file. Using a bitset + // avoids all allocations. The bitset should be implemented as 8K of storage, which is + // tight enough for all callers. + std::bitset<kTypeIdLimit + 1> defined_classes_; +}; + static bool IsValidOrNoTypeId(uint16_t low, uint16_t high) { return (high == 0) || ((high == 0xffffU) && (low == 0xffffU)); } @@ -210,21 +459,6 @@ bool DexFileVerifier::VerifyTypeDescriptor(dex::TypeIndex idx, return true; } -bool DexFileVerifier::Verify(const DexFile* dex_file, - const uint8_t* begin, - size_t size, - const char* location, - bool verify_checksum, - std::string* error_msg) { - std::unique_ptr<DexFileVerifier> verifier( - new DexFileVerifier(dex_file, begin, size, location, verify_checksum)); - if (!verifier->Verify()) { - *error_msg = verifier->FailureReason(); - return false; - } - return true; -} - bool DexFileVerifier::CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, bool is_return_type) { switch (shorty_char) { @@ -2474,7 +2708,7 @@ bool DexFileVerifier::CheckInterClassDefItem() { // Sanity checks, should be optimized away. DCHECK_LE(item->class_idx_.index_, kTypeIdLimit); - static_assert(kTypeIdLimit < kTypeIdSize, "Unexpected type-id range."); + DCHECK_LT(kTypeIdLimit, defined_classes_.size()); if (defined_classes_[item->class_idx_.index_]) { ErrorStringPrintf("Redefinition of class with type idx: '%d'", item->class_idx_.index_); @@ -3557,4 +3791,20 @@ bool DexFileVerifier::CheckConstructorProperties( return true; } +bool Verify(const DexFile* dex_file, + const uint8_t* begin, + size_t size, + const char* location, + bool verify_checksum, + std::string* error_msg) { + std::unique_ptr<DexFileVerifier> verifier( + new DexFileVerifier(dex_file, begin, size, location, verify_checksum)); + if (!verifier->Verify()) { + *error_msg = verifier->FailureReason(); + return false; + } + return true; +} + +} // namespace dex } // namespace art diff --git a/libdexfile/dex/dex_file_verifier.h b/libdexfile/dex/dex_file_verifier.h index fe3aa84764..8ae6e7a5fd 100644 --- a/libdexfile/dex/dex_file_verifier.h +++ b/libdexfile/dex/dex_file_verifier.h @@ -17,268 +17,24 @@ #ifndef ART_LIBDEXFILE_DEX_DEX_FILE_VERIFIER_H_ #define ART_LIBDEXFILE_DEX_DEX_FILE_VERIFIER_H_ -#include <bitset> -#include <limits> +#include <string> -#include "base/hash_map.h" -#include "base/safe_map.h" -#include "class_accessor.h" -#include "dex_file.h" -#include "dex_file_types.h" +#include <inttypes.h> namespace art { -class DexFileVerifier { - public: - static bool Verify(const DexFile* dex_file, - const uint8_t* begin, - size_t size, - const char* location, - bool verify_checksum, - std::string* error_msg); +class DexFile; - const std::string& FailureReason() const { - return failure_reason_; - } +namespace dex { - private: - DexFileVerifier(const DexFile* dex_file, - const uint8_t* begin, - size_t size, - const char* location, - bool verify_checksum) - : dex_file_(dex_file), - begin_(begin), - size_(size), - location_(location), - verify_checksum_(verify_checksum), - header_(&dex_file->GetHeader()), - ptr_(nullptr), - previous_item_(nullptr), - init_indices_{std::numeric_limits<size_t>::max(), - std::numeric_limits<size_t>::max(), - std::numeric_limits<size_t>::max(), - std::numeric_limits<size_t>::max()} { - } - - bool Verify(); - - bool CheckShortyDescriptorMatch(char shorty_char, const char* descriptor, bool is_return_type); - bool CheckListSize(const void* start, size_t count, size_t element_size, const char* label); - // Check a list. The head is assumed to be at *ptr, and elements to be of size element_size. If - // successful, the ptr will be moved forward the amount covered by the list. - bool CheckList(size_t element_size, const char* label, const uint8_t* *ptr); - // Checks whether the offset is zero (when size is zero) or that the offset falls within the area - // claimed by the file. - bool CheckValidOffsetAndSize(uint32_t offset, uint32_t size, size_t alignment, const char* label); - // Checks whether the size is less than the limit. - bool CheckSizeLimit(uint32_t size, uint32_t limit, const char* label); - bool CheckIndex(uint32_t field, uint32_t limit, const char* label); - - bool CheckHeader(); - bool CheckMap(); - - uint32_t ReadUnsignedLittleEndian(uint32_t size); - bool CheckAndGetHandlerOffsets(const dex::CodeItem* code_item, - uint32_t* handler_offsets, uint32_t handlers_size); - bool CheckClassDataItemField(uint32_t idx, - uint32_t access_flags, - uint32_t class_access_flags, - dex::TypeIndex class_type_index, - bool expect_static); - bool CheckClassDataItemMethod(uint32_t idx, - uint32_t access_flags, - uint32_t class_access_flags, - dex::TypeIndex class_type_index, - uint32_t code_offset, - ClassAccessor::Method* direct_method, - size_t* remaining_directs); - ALWAYS_INLINE - bool CheckOrder(const char* type_descr, uint32_t curr_index, uint32_t prev_index); - bool CheckStaticFieldTypes(const dex::ClassDef* class_def); - - bool CheckPadding(size_t offset, uint32_t aligned_offset, DexFile::MapItemType type); - bool CheckEncodedValue(); - bool CheckEncodedArray(); - bool CheckEncodedAnnotation(); - - bool CheckIntraClassDataItem(); - // Check all fields of the given type from the given iterator. Load the class data from the first - // field, if necessary (and return it), or use the given values. - template <bool kStatic> - bool CheckIntraClassDataItemFields(size_t count, - ClassAccessor::Field* field, - bool* have_class, - dex::TypeIndex* class_type_index, - const dex::ClassDef** class_def); - // Check all methods of the given type from the given iterator. Load the class data from the first - // method, if necessary (and return it), or use the given values. - bool CheckIntraClassDataItemMethods(ClassAccessor::Method* method, - size_t num_methods, - ClassAccessor::Method* direct_method, - size_t num_directs, - bool* have_class, - dex::TypeIndex* class_type_index, - const dex::ClassDef** class_def); - - bool CheckIntraCodeItem(); - bool CheckIntraStringDataItem(); - bool CheckIntraDebugInfoItem(); - bool CheckIntraAnnotationItem(); - bool CheckIntraAnnotationsDirectoryItem(); - bool CheckIntraHiddenapiClassData(); - - template <DexFile::MapItemType kType> - bool CheckIntraSectionIterate(size_t offset, uint32_t count); - template <DexFile::MapItemType kType> - bool CheckIntraIdSection(size_t offset, uint32_t count); - template <DexFile::MapItemType kType> - bool CheckIntraDataSection(size_t offset, uint32_t count); - bool CheckIntraSection(); - - bool CheckOffsetToTypeMap(size_t offset, uint16_t type); - - // Note: as sometimes kDexNoIndex16, being 0xFFFF, is a valid return value, we need an - // additional out parameter to signal any errors loading an index. - dex::TypeIndex FindFirstClassDataDefiner(const uint8_t* ptr, bool* success); - dex::TypeIndex FindFirstAnnotationsDirectoryDefiner(const uint8_t* ptr, bool* success); - - bool CheckInterStringIdItem(); - bool CheckInterTypeIdItem(); - bool CheckInterProtoIdItem(); - bool CheckInterFieldIdItem(); - bool CheckInterMethodIdItem(); - bool CheckInterClassDefItem(); - bool CheckInterCallSiteIdItem(); - bool CheckInterMethodHandleItem(); - bool CheckInterAnnotationSetRefList(); - bool CheckInterAnnotationSetItem(); - bool CheckInterClassDataItem(); - bool CheckInterAnnotationsDirectoryItem(); - - bool CheckInterSectionIterate(size_t offset, uint32_t count, DexFile::MapItemType type); - bool CheckInterSection(); - - // Load a string by (type) index. Checks whether the index is in bounds, printing the error if - // not. If there is an error, null is returned. - const char* CheckLoadStringByIdx(dex::StringIndex idx, const char* error_fmt); - const char* CheckLoadStringByTypeIdx(dex::TypeIndex type_idx, const char* error_fmt); - - // Load a field/method/proto Id by index. Checks whether the index is in bounds, printing the - // error if not. If there is an error, null is returned. - const dex::FieldId* CheckLoadFieldId(uint32_t idx, const char* error_fmt); - const dex::MethodId* CheckLoadMethodId(uint32_t idx, const char* error_fmt); - const dex::ProtoId* CheckLoadProtoId(dex::ProtoIndex idx, const char* error_fmt); - - void ErrorStringPrintf(const char* fmt, ...) - __attribute__((__format__(__printf__, 2, 3))) COLD_ATTR; - bool FailureReasonIsSet() const { return failure_reason_.size() != 0; } - - // Retrieve class index and class def from the given member. index is the member index, which is - // taken as either a field or a method index (as designated by is_field). The result, if the - // member and declaring class could be found, is stored in class_type_index and class_def. - // This is an expensive lookup, as we have to find the class def by type index, which is a - // linear search. The output values should thus be cached by the caller. - bool FindClassIndexAndDef(uint32_t index, - bool is_field, - dex::TypeIndex* class_type_index, - const dex::ClassDef** output_class_def); - - // Check validity of the given access flags, interpreted for a field in the context of a class - // with the given second access flags. - bool CheckFieldAccessFlags(uint32_t idx, - uint32_t field_access_flags, - uint32_t class_access_flags, - std::string* error_message); - - // Check validity of the given method and access flags, in the context of a class with the given - // second access flags. - bool CheckMethodAccessFlags(uint32_t method_index, - uint32_t method_access_flags, - uint32_t class_access_flags, - uint32_t constructor_flags_by_name, - bool has_code, - bool expect_direct, - std::string* error_message); - - // Check validity of given method if it's a constructor or class initializer. - bool CheckConstructorProperties(uint32_t method_index, uint32_t constructor_flags); - - void FindStringRangesForMethodNames(); - - template <typename ExtraCheckFn> - bool VerifyTypeDescriptor(dex::TypeIndex idx, - const char* error_msg1, - const char* error_msg2, - ExtraCheckFn extra_check); - - const DexFile* const dex_file_; - const uint8_t* const begin_; - const size_t size_; - const char* const location_; - const bool verify_checksum_; - const DexFile::Header* const header_; - - struct OffsetTypeMapEmptyFn { - // Make a hash map slot empty by making the offset 0. Offset 0 is a valid dex file offset that - // is in the offset of the dex file header. However, we only store data section items in the - // map, and these are after the header. - void MakeEmpty(std::pair<uint32_t, uint16_t>& pair) const { - pair.first = 0u; - } - // Check if a hash map slot is empty. - bool IsEmpty(const std::pair<uint32_t, uint16_t>& pair) const { - return pair.first == 0; - } - }; - struct OffsetTypeMapHashCompareFn { - // Hash function for offset. - size_t operator()(const uint32_t key) const { - return key; - } - // std::equal function for offset. - bool operator()(const uint32_t a, const uint32_t b) const { - return a == b; - } - }; - // Map from offset to dex file type, HashMap for performance reasons. - HashMap<uint32_t, - uint16_t, - OffsetTypeMapEmptyFn, - OffsetTypeMapHashCompareFn, - OffsetTypeMapHashCompareFn> offset_to_type_map_; - const uint8_t* ptr_; - const void* previous_item_; - - std::string failure_reason_; - - // Cached string indices for "interesting" entries wrt/ method names. Will be populated by - // FindStringRangesForMethodNames (which is automatically called before verifying the - // classdataitem section). - // - // Strings starting with '<' are in the range - // [angle_bracket_start_index_,angle_bracket_end_index_). - // angle_init_angle_index_ and angle_clinit_angle_index_ denote the indices of "<init>" and - // "<clinit>", respectively. If any value is not found, the corresponding index will be larger - // than any valid string index for this dex file. - struct { - size_t angle_bracket_start_index; - size_t angle_bracket_end_index; - size_t angle_init_angle_index; - size_t angle_clinit_angle_index; - } init_indices_; - - // A bitvector for verified type descriptors. Each bit corresponds to a type index. A set - // bit denotes that the descriptor has been verified wrt/ IsValidDescriptor. - std::vector<char> verified_type_descriptors_; - - // Set of type ids for which there are ClassDef elements in the dex file. Using a bitset - // avoids all allocations. The bitset should be implemented as 8K of storage, which is - // tight enough for all callers. - static constexpr size_t kTypeIdSize = 65536u; - std::bitset<kTypeIdSize> defined_classes_; -}; +bool Verify(const DexFile* dex_file, + const uint8_t* begin, + size_t size, + const char* location, + bool verify_checksum, + std::string* error_msg); +} // namespace dex } // namespace art #endif // ART_LIBDEXFILE_DEX_DEX_FILE_VERIFIER_H_ diff --git a/libdexfile/dex/dex_file_verifier_test.cc b/libdexfile/dex/dex_file_verifier_test.cc index b2cff4f311..37c06b1b0c 100644 --- a/libdexfile/dex/dex_file_verifier_test.cc +++ b/libdexfile/dex/dex_file_verifier_test.cc @@ -21,6 +21,8 @@ #include <functional> #include <memory> +#include <android-base/logging.h> + #include "base/bit_utils.h" #include "base/leb128.h" #include "base/macros.h" @@ -74,12 +76,12 @@ class DexFileVerifierTest : public testing::Test { static constexpr bool kVerifyChecksum = true; std::string error_msg; - bool success = DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - location, - kVerifyChecksum, - &error_msg); + bool success = dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + location, + kVerifyChecksum, + &error_msg); if (expected_error == nullptr) { EXPECT_TRUE(success) << error_msg; } else { @@ -1617,35 +1619,35 @@ TEST_F(DexFileVerifierTest, Checksum) { std::string error_msg; // Good checksum: all pass. - EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "good checksum, no verify", - /*verify_checksum=*/ false, - &error_msg)); - EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "good checksum, verify", - /*verify_checksum=*/ true, - &error_msg)); + EXPECT_TRUE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "good checksum, no verify", + /*verify_checksum=*/ false, + &error_msg)); + EXPECT_TRUE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "good checksum, verify", + /*verify_checksum=*/ true, + &error_msg)); // Bad checksum: !verify_checksum passes verify_checksum fails. DexFile::Header* header = reinterpret_cast<DexFile::Header*>( const_cast<uint8_t*>(dex_file->Begin())); header->checksum_ = 0; - EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "bad checksum, no verify", - /*verify_checksum=*/ false, - &error_msg)); - EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "bad checksum, verify", - /*verify_checksum=*/ true, - &error_msg)); + EXPECT_TRUE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "bad checksum, no verify", + /*verify_checksum=*/ false, + &error_msg)); + EXPECT_FALSE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "bad checksum, verify", + /*verify_checksum=*/ true, + &error_msg)); EXPECT_NE(error_msg.find("Bad checksum"), std::string::npos) << error_msg; } @@ -1687,12 +1689,12 @@ TEST_F(DexFileVerifierTest, BadStaticMethodName) { // Note: `dex_file` will be destroyed before `dex_bytes`. std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length)); std::string error_msg; - EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "bad static method name", - /*verify_checksum=*/ true, - &error_msg)); + EXPECT_FALSE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "bad static method name", + /*verify_checksum=*/ true, + &error_msg)); } TEST_F(DexFileVerifierTest, BadVirtualMethodName) { @@ -1731,12 +1733,12 @@ TEST_F(DexFileVerifierTest, BadVirtualMethodName) { // Note: `dex_file` will be destroyed before `dex_bytes`. std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length)); std::string error_msg; - EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "bad virtual method name", - /*verify_checksum=*/ true, - &error_msg)); + EXPECT_FALSE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "bad virtual method name", + /*verify_checksum=*/ true, + &error_msg)); } TEST_F(DexFileVerifierTest, BadClinitSignature) { @@ -1775,12 +1777,12 @@ TEST_F(DexFileVerifierTest, BadClinitSignature) { // Note: `dex_file` will be destroyed before `dex_bytes`. std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length)); std::string error_msg; - EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "bad clinit signature", - /*verify_checksum=*/ true, - &error_msg)); + EXPECT_FALSE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "bad clinit signature", + /*verify_checksum=*/ true, + &error_msg)); } TEST_F(DexFileVerifierTest, BadClinitSignatureAgain) { @@ -1819,12 +1821,12 @@ TEST_F(DexFileVerifierTest, BadClinitSignatureAgain) { // Note: `dex_file` will be destroyed before `dex_bytes`. std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length)); std::string error_msg; - EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "bad clinit signature", - /*verify_checksum=*/ true, - &error_msg)); + EXPECT_FALSE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "bad clinit signature", + /*verify_checksum=*/ true, + &error_msg)); } TEST_F(DexFileVerifierTest, BadInitSignature) { @@ -1856,12 +1858,12 @@ TEST_F(DexFileVerifierTest, BadInitSignature) { // Note: `dex_file` will be destroyed before `dex_bytes`. std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length)); std::string error_msg; - EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "bad init signature", - /*verify_checksum=*/ true, - &error_msg)); + EXPECT_FALSE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "bad init signature", + /*verify_checksum=*/ true, + &error_msg)); } static const char* kInvokeCustomDexFiles[] = { @@ -2059,12 +2061,12 @@ TEST_F(DexFileVerifierTest, InvokeCustomDexSamples) { // Note: `dex_file` will be destroyed before `dex_bytes`. std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length)); std::string error_msg; - EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "good checksum, verify", - /*verify_checksum=*/ true, - &error_msg)); + EXPECT_TRUE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "good checksum, verify", + /*verify_checksum=*/ true, + &error_msg)); // TODO(oth): Test corruptions (b/35308502) } } @@ -2106,12 +2108,12 @@ TEST_F(DexFileVerifierTest, BadStaticFieldInitialValuesArray) { // Note: `dex_file` will be destroyed before `dex_bytes`. std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length)); std::string error_msg; - EXPECT_FALSE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "bad static field initial values array", - /*verify_checksum=*/ true, - &error_msg)); + EXPECT_FALSE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "bad static field initial values array", + /*verify_checksum=*/ true, + &error_msg)); } TEST_F(DexFileVerifierTest, GoodStaticFieldInitialValuesArray) { @@ -2162,12 +2164,12 @@ TEST_F(DexFileVerifierTest, GoodStaticFieldInitialValuesArray) { // Note: `dex_file` will be destroyed before `dex_bytes`. std::unique_ptr<DexFile> dex_file(GetDexFile(dex_bytes.get(), length)); std::string error_msg; - EXPECT_TRUE(DexFileVerifier::Verify(dex_file.get(), - dex_file->Begin(), - dex_file->Size(), - "good static field initial values array", - /*verify_checksum=*/ true, - &error_msg)); + EXPECT_TRUE(dex::Verify(dex_file.get(), + dex_file->Begin(), + dex_file->Size(), + "good static field initial values array", + /*verify_checksum=*/ true, + &error_msg)); } } // namespace art diff --git a/openjdkjvmti/fixed_up_dex_file.cc b/openjdkjvmti/fixed_up_dex_file.cc index e8b34354a6..eefbe41503 100644 --- a/openjdkjvmti/fixed_up_dex_file.cc +++ b/openjdkjvmti/fixed_up_dex_file.cc @@ -76,12 +76,12 @@ static void DoDexUnquicken(const art::DexFile& new_dex_file, static void DCheckVerifyDexFile(const art::DexFile& dex) { if (art::kIsDebugBuild) { std::string error; - if (!art::DexFileVerifier::Verify(&dex, - dex.Begin(), - dex.Size(), - "FixedUpDexFile_Verification.dex", - /*verify_checksum=*/ true, - &error)) { + if (!art::dex::Verify(&dex, + dex.Begin(), + dex.Size(), + "FixedUpDexFile_Verification.dex", + /*verify_checksum=*/ true, + &error)) { LOG(FATAL) << "Failed to verify de-quickened dex file: " << error; } } |