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