1 /* 2 * Copyright (c) 2023 Huawei Device Co., Ltd. 3 * Licensed under the Apache License, Version 2.0 (the "License"); 4 * you may not use this file except in compliance with the License. 5 * You may obtain a copy of the License at 6 * 7 * http://www.apache.org/licenses/LICENSE-2.0 8 * 9 * Unless required by applicable law or agreed to in writing, software 10 * distributed under the License is distributed on an "AS IS" BASIS, 11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 * See the License for the specific language governing permissions and 13 * limitations under the License. 14 */ 15 16 #ifndef VERIFIER_VERIFIER_H 17 #define VERIFIER_VERIFIER_H 18 19 #include <string> 20 #include <unordered_map> 21 #include <unordered_set> 22 23 #include "bytecode_instruction_enum_gen.h" 24 #include "bytecode_instruction-inl.h" 25 #include "code_data_accessor-inl.h" 26 #include "file.h" 27 #include "file_items.h" 28 #include "literal_data_accessor.h" 29 #include "method_data_accessor-inl.h" 30 #include "utils/bit_utils.h" 31 #include "utils/utf.h" 32 33 namespace panda::verifier { 34 35 using Opcode = BytecodeInstruction::Opcode; 36 using TaggedType = uint64_t; 37 38 enum class ActionType { 39 CHECKCONSTPOOLCONTENT, 40 COLLECTINFOS, 41 }; 42 43 struct MethodInfos { 44 const BytecodeInstruction &bc_ins_init; 45 BytecodeInstruction &bc_ins; 46 const BytecodeInstruction &bc_ins_last; 47 panda_file::MethodDataAccessor &method_accessor; 48 const panda_file::File::EntityId &method_id; 49 std::optional<uint64_t> &valid_regs_num; 50 const uint8_t *ins_arr; 51 uint32_t &ins_slot_num; 52 bool &has_slot; 53 bool &is_two_slot; 54 }; 55 56 class Verifier { 57 public: 58 explicit Verifier(const std::string &filename); 59 ~Verifier() = default; 60 61 bool Verify(); 62 bool CollectIdInfos(); 63 bool VerifyChecksum(); 64 bool VerifyConstantPool(); 65 bool VerifyRegisterIndex(); 66 bool VerifyConstantPoolIndex(); 67 bool VerifyConstantPoolContent(); 68 69 bool include_literal_array_ids = true; 70 std::vector<uint32_t> literal_ids_; 71 std::unordered_map<uint32_t, uint32_t> inner_literal_map_; 72 std::unordered_map<uint32_t, uint32_t> inner_method_map_; 73 74 static constexpr size_t TAG_BITS_SIZE = 16; 75 static constexpr size_t TAG_BITS_SHIFT = BitNumbers<TaggedType>() - TAG_BITS_SIZE; 76 static_assert((TAG_BITS_SHIFT + TAG_BITS_SIZE) == sizeof(TaggedType) * CHAR_BIT, "Insufficient bits!"); 77 static constexpr TaggedType TAG_MASK = ((1ULL << TAG_BITS_SIZE) - 1ULL) << TAG_BITS_SHIFT; 78 static constexpr TaggedType TAG_INT = TAG_MASK; 79 static constexpr size_t DOUBLE_ENCODE_OFFSET_BIT = 48; 80 static constexpr TaggedType DOUBLE_ENCODE_OFFSET = 1ULL << DOUBLE_ENCODE_OFFSET_BIT; 81 82 private: 83 void GetLiteralIds(); 84 template <typename T> 85 void PushToLiteralIds(T &ids); 86 void GetConstantPoolIds(); 87 bool CollectIdInInstructions(const panda_file::File::EntityId &method_id); 88 void CollectModuleLiteralId(const panda_file::File::EntityId &field_id); 89 bool CheckConstantPool(const verifier::ActionType type); 90 size_t GetVRegCount(const BytecodeInstruction &bc_ins); 91 bool CheckConstantPoolActions(const verifier::ActionType type, panda_file::File::EntityId method_id); 92 bool VerifyMethodId(const uint32_t &method_id) const; 93 bool VerifyLiteralId(const uint32_t &literal_id) const; 94 bool VerifyStringId(const uint32_t &string_id) const; 95 bool IsRangeInstAndHasInvalidRegIdx(const BytecodeInstruction &bc_ins, 96 const size_t count, uint64_t valid_regs_num); 97 bool IsRegIdxOutOfBounds(uint64_t reg_idx, uint64_t valid_regs_num); 98 bool CheckVRegIdx(const BytecodeInstruction &bc_ins, const size_t count, uint64_t valid_regs_num); 99 std::optional<int64_t> GetFirstImmFromInstruction(const BytecodeInstruction &bc_ins); 100 std::optional<uint64_t> GetSlotNumberFromAnnotation(panda_file::MethodDataAccessor &method_accessor); 101 bool VerifyMethodIdInLiteralArray(const uint32_t &id); 102 bool VerifyStringIdInLiteralArray(const uint32_t &id); 103 bool VerifyLiteralIdInLiteralArray(const uint32_t &id); 104 bool IsModuleLiteralId(const panda_file::File::EntityId &id) const; 105 bool VerifySingleLiteralArray(const panda_file::File::EntityId &literal_id); 106 bool VerifyLiteralArrays(); 107 bool VerifyJumpInstruction(const BytecodeInstruction &bc_ins, const BytecodeInstruction &bc_ins_last, 108 const BytecodeInstruction &bc_ins_init, const uint8_t *ins_arr, 109 panda_file::File::EntityId code_id); 110 bool GetIcSlotFromInstruction(const BytecodeInstruction &bc_ins, uint32_t &first_slot_index, bool &has_slot, 111 bool &is_two_slot); 112 bool VerifySlotNumber(panda_file::MethodDataAccessor &method_accessor, const uint32_t &slot_number, 113 const panda_file::File::EntityId &method_id); 114 bool CheckConstantPoolMethodContent(const panda_file::File::EntityId &method_id); 115 bool CheckConstantPoolIndex() const; 116 std::optional<uint64_t> SafeAdd(uint64_t a, uint64_t b) const; 117 bool VerifyCatchBlocks(panda_file::CodeDataAccessor::TryBlock &try_block, const BytecodeInstruction &bc_ins, 118 const BytecodeInstruction &bc_ins_last); 119 bool VerifyTryBlocks(panda_file::CodeDataAccessor &code_accessor, const BytecodeInstruction &bc_ins, 120 const BytecodeInstruction &bc_ins_last); 121 bool PrecomputeInstructionIndices(const BytecodeInstruction &bc_ins_start, const BytecodeInstruction &bc_ins_last); 122 bool IsMethodBytecodeInstruction(const BytecodeInstruction &bc_ins_cur); 123 bool VerifyMethodRegisterIndex(panda_file::CodeDataAccessor &code_accessor, 124 std::optional<uint64_t> &max_reg_idx); 125 bool VerifyMethodInstructions(const MethodInfos &infos); 126 IsImpureNaN(double value)127 inline bool IsImpureNaN(double value) 128 { 129 // Tests if the double value would break tagged double encoding. 130 return bit_cast<TaggedType>(value) >= (Verifier::TAG_INT - Verifier::DOUBLE_ENCODE_OFFSET); 131 } 132 133 std::unique_ptr<const panda_file::File> file_; 134 std::vector<uint32_t> constant_pool_ids_; 135 std::vector<uint32_t> all_method_ids_; 136 std::unordered_set<uint32_t> ins_method_ids_; 137 std::unordered_set<uint32_t> ins_literal_ids_; 138 std::unordered_set<uint32_t> ins_string_ids_; 139 std::unordered_set<uint32_t> module_literals_; 140 static constexpr size_t DEFAULT_ARGUMENT_NUMBER = 3; 141 static constexpr uint32_t FILE_CONTENT_OFFSET = 12U; 142 static constexpr size_t FIRST_INDEX = 0; 143 static constexpr size_t SECOND_INDEX = 1; 144 static constexpr uint64_t MAX_REGISTER_INDEX = 0xffff; 145 std::unordered_map<const uint8_t*, size_t> instruction_index_map_; 146 }; 147 } // namespace panda::verifier 148 #endif 149