1b1994897Sopenharmony_ci/* 2b1994897Sopenharmony_ci * Copyright (c) 2023 Huawei Device Co., Ltd. 3b1994897Sopenharmony_ci * Licensed under the Apache License, Version 2.0 (the "License"); 4b1994897Sopenharmony_ci * you may not use this file except in compliance with the License. 5b1994897Sopenharmony_ci * You may obtain a copy of the License at 6b1994897Sopenharmony_ci * 7b1994897Sopenharmony_ci * http://www.apache.org/licenses/LICENSE-2.0 8b1994897Sopenharmony_ci * 9b1994897Sopenharmony_ci * Unless required by applicable law or agreed to in writing, software 10b1994897Sopenharmony_ci * distributed under the License is distributed on an "AS IS" BASIS, 11b1994897Sopenharmony_ci * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12b1994897Sopenharmony_ci * See the License for the specific language governing permissions and 13b1994897Sopenharmony_ci * limitations under the License. 14b1994897Sopenharmony_ci */ 15b1994897Sopenharmony_ci#include <codecvt> 16b1994897Sopenharmony_ci#include <locale> 17b1994897Sopenharmony_ci 18b1994897Sopenharmony_ci#include "verifier.h" 19b1994897Sopenharmony_ci#include "class_data_accessor-inl.h" 20b1994897Sopenharmony_ci#include "libpandafile/util/collect_util.h" 21b1994897Sopenharmony_ci#include "zlib.h" 22b1994897Sopenharmony_ci 23b1994897Sopenharmony_cinamespace panda::verifier { 24b1994897Sopenharmony_ci 25b1994897Sopenharmony_ciVerifier::Verifier(const std::string &filename) 26b1994897Sopenharmony_ci{ 27b1994897Sopenharmony_ci auto file_to_verify = panda_file::File::Open(filename); 28b1994897Sopenharmony_ci file_.swap(file_to_verify); 29b1994897Sopenharmony_ci} 30b1994897Sopenharmony_ci 31b1994897Sopenharmony_cibool Verifier::Verify() 32b1994897Sopenharmony_ci{ 33b1994897Sopenharmony_ci if (!VerifyChecksum()) { 34b1994897Sopenharmony_ci return false; 35b1994897Sopenharmony_ci } 36b1994897Sopenharmony_ci 37b1994897Sopenharmony_ci if (!CollectIdInfos()) { 38b1994897Sopenharmony_ci return false; 39b1994897Sopenharmony_ci } 40b1994897Sopenharmony_ci 41b1994897Sopenharmony_ci if (!VerifyConstantPool()) { 42b1994897Sopenharmony_ci return false; 43b1994897Sopenharmony_ci } 44b1994897Sopenharmony_ci 45b1994897Sopenharmony_ci return true; 46b1994897Sopenharmony_ci} 47b1994897Sopenharmony_ci 48b1994897Sopenharmony_cibool Verifier::CollectIdInfos() 49b1994897Sopenharmony_ci{ 50b1994897Sopenharmony_ci if (file_ == nullptr) { 51b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!"; 52b1994897Sopenharmony_ci return false; 53b1994897Sopenharmony_ci } 54b1994897Sopenharmony_ci GetConstantPoolIds(); 55b1994897Sopenharmony_ci if (include_literal_array_ids) { 56b1994897Sopenharmony_ci GetLiteralIds(); 57b1994897Sopenharmony_ci } 58b1994897Sopenharmony_ci return CheckConstantPool(verifier::ActionType::COLLECTINFOS); 59b1994897Sopenharmony_ci} 60b1994897Sopenharmony_ci 61b1994897Sopenharmony_cibool Verifier::VerifyChecksum() 62b1994897Sopenharmony_ci{ 63b1994897Sopenharmony_ci if (file_ == nullptr) { 64b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!"; 65b1994897Sopenharmony_ci return false; 66b1994897Sopenharmony_ci } 67b1994897Sopenharmony_ci uint32_t file_size = file_->GetHeader()->file_size; 68b1994897Sopenharmony_ci ASSERT(file_size > FILE_CONTENT_OFFSET); 69b1994897Sopenharmony_ci uint32_t cal_checksum = adler32(1, file_->GetBase() + FILE_CONTENT_OFFSET, file_size - FILE_CONTENT_OFFSET); 70b1994897Sopenharmony_ci return file_->GetHeader()->checksum == cal_checksum; 71b1994897Sopenharmony_ci} 72b1994897Sopenharmony_ci 73b1994897Sopenharmony_cibool Verifier::VerifyConstantPool() 74b1994897Sopenharmony_ci{ 75b1994897Sopenharmony_ci if (file_ == nullptr) { 76b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!"; 77b1994897Sopenharmony_ci return false; 78b1994897Sopenharmony_ci } 79b1994897Sopenharmony_ci 80b1994897Sopenharmony_ci if (!CheckConstantPoolIndex()) { 81b1994897Sopenharmony_ci return false; 82b1994897Sopenharmony_ci } 83b1994897Sopenharmony_ci 84b1994897Sopenharmony_ci if (!CheckConstantPool(verifier::ActionType::CHECKCONSTPOOLCONTENT)) { 85b1994897Sopenharmony_ci return false; 86b1994897Sopenharmony_ci } 87b1994897Sopenharmony_ci 88b1994897Sopenharmony_ci if (!VerifyLiteralArrays()) { 89b1994897Sopenharmony_ci return false; 90b1994897Sopenharmony_ci } 91b1994897Sopenharmony_ci 92b1994897Sopenharmony_ci return true; 93b1994897Sopenharmony_ci} 94b1994897Sopenharmony_ci 95b1994897Sopenharmony_cibool Verifier::VerifyRegisterIndex() 96b1994897Sopenharmony_ci{ 97b1994897Sopenharmony_ci if (file_ == nullptr) { 98b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!"; 99b1994897Sopenharmony_ci return false; 100b1994897Sopenharmony_ci } 101b1994897Sopenharmony_ci 102b1994897Sopenharmony_ci for (const auto id : all_method_ids_) { 103b1994897Sopenharmony_ci const panda_file::File::EntityId method_id = panda_file::File::EntityId(id); 104b1994897Sopenharmony_ci panda_file::MethodDataAccessor method_accessor {*file_, method_id}; 105b1994897Sopenharmony_ci if (!method_accessor.GetCodeId().has_value()) { 106b1994897Sopenharmony_ci continue; 107b1994897Sopenharmony_ci } 108b1994897Sopenharmony_ci panda_file::CodeDataAccessor code_data(*file_, method_accessor.GetCodeId().value()); 109b1994897Sopenharmony_ci const uint64_t reg_nums = code_data.GetNumVregs(); 110b1994897Sopenharmony_ci const uint64_t arg_nums = code_data.GetNumArgs(); 111b1994897Sopenharmony_ci const std::optional<uint64_t> valid_regs_num = SafeAdd(reg_nums, arg_nums); 112b1994897Sopenharmony_ci if (!valid_regs_num.has_value()) { 113b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Integer overflow detected during register index calculation!"; 114b1994897Sopenharmony_ci return false; 115b1994897Sopenharmony_ci } 116b1994897Sopenharmony_ci if (valid_regs_num.value() > MAX_REGISTER_INDEX + 1) { 117b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Register index exceeds the maximum allowable value (0xffff)!"; 118b1994897Sopenharmony_ci return false; 119b1994897Sopenharmony_ci } 120b1994897Sopenharmony_ci auto bc_ins = BytecodeInstruction(code_data.GetInstructions()); 121b1994897Sopenharmony_ci const auto bc_ins_last = bc_ins.JumpTo(code_data.GetCodeSize()); 122b1994897Sopenharmony_ci ASSERT(arg_nums >= DEFAULT_ARGUMENT_NUMBER); 123b1994897Sopenharmony_ci while (bc_ins.GetAddress() < bc_ins_last.GetAddress()) { 124b1994897Sopenharmony_ci const size_t count = GetVRegCount(bc_ins); 125b1994897Sopenharmony_ci if (count == 0) { // Skip instructions that do not use registers 126b1994897Sopenharmony_ci bc_ins = bc_ins.GetNext(); 127b1994897Sopenharmony_ci continue; 128b1994897Sopenharmony_ci } 129b1994897Sopenharmony_ci if (!CheckVRegIdx(bc_ins, count, valid_regs_num.value())) { 130b1994897Sopenharmony_ci return false; 131b1994897Sopenharmony_ci } 132b1994897Sopenharmony_ci bc_ins = bc_ins.GetNext(); 133b1994897Sopenharmony_ci } 134b1994897Sopenharmony_ci } 135b1994897Sopenharmony_ci return true; 136b1994897Sopenharmony_ci} 137b1994897Sopenharmony_ci 138b1994897Sopenharmony_cibool Verifier::VerifyConstantPoolIndex() 139b1994897Sopenharmony_ci{ 140b1994897Sopenharmony_ci if (file_ == nullptr) { 141b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!"; 142b1994897Sopenharmony_ci return false; 143b1994897Sopenharmony_ci } 144b1994897Sopenharmony_ci 145b1994897Sopenharmony_ci if (!CheckConstantPoolIndex()) { 146b1994897Sopenharmony_ci return false; 147b1994897Sopenharmony_ci } 148b1994897Sopenharmony_ci 149b1994897Sopenharmony_ci return true; 150b1994897Sopenharmony_ci} 151b1994897Sopenharmony_ci 152b1994897Sopenharmony_cibool Verifier::VerifyConstantPoolContent() 153b1994897Sopenharmony_ci{ 154b1994897Sopenharmony_ci if (file_ == nullptr) { 155b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Failed to verify empty abc file!"; 156b1994897Sopenharmony_ci return false; 157b1994897Sopenharmony_ci } 158b1994897Sopenharmony_ci 159b1994897Sopenharmony_ci if (!CheckConstantPool(verifier::ActionType::CHECKCONSTPOOLCONTENT)) { 160b1994897Sopenharmony_ci return false; 161b1994897Sopenharmony_ci } 162b1994897Sopenharmony_ci 163b1994897Sopenharmony_ci if (!VerifyLiteralArrays()) { 164b1994897Sopenharmony_ci return false; 165b1994897Sopenharmony_ci } 166b1994897Sopenharmony_ci 167b1994897Sopenharmony_ci return true; 168b1994897Sopenharmony_ci} 169b1994897Sopenharmony_ci 170b1994897Sopenharmony_civoid Verifier::GetConstantPoolIds() 171b1994897Sopenharmony_ci{ 172b1994897Sopenharmony_ci if (constant_pool_ids_.size() != 0) { 173b1994897Sopenharmony_ci return; 174b1994897Sopenharmony_ci } 175b1994897Sopenharmony_ci auto index_headers = file_->GetIndexHeaders(); 176b1994897Sopenharmony_ci for (const auto &index_header : index_headers) { 177b1994897Sopenharmony_ci auto region_indexs = file_->GetMethodIndex(&index_header); 178b1994897Sopenharmony_ci for (auto &index : region_indexs) { 179b1994897Sopenharmony_ci constant_pool_ids_.push_back(index.GetOffset()); 180b1994897Sopenharmony_ci } 181b1994897Sopenharmony_ci } 182b1994897Sopenharmony_ci} 183b1994897Sopenharmony_ci 184b1994897Sopenharmony_civoid Verifier::GetLiteralIds() 185b1994897Sopenharmony_ci{ 186b1994897Sopenharmony_ci if (literal_ids_.size() != 0) { 187b1994897Sopenharmony_ci return; 188b1994897Sopenharmony_ci } 189b1994897Sopenharmony_ci 190b1994897Sopenharmony_ci if (panda_file::ContainsLiteralArrayInHeader(file_->GetHeader()->version)) { 191b1994897Sopenharmony_ci const auto literal_arrays = file_->GetLiteralArrays(); 192b1994897Sopenharmony_ci PushToLiteralIds(literal_arrays); 193b1994897Sopenharmony_ci } else { 194b1994897Sopenharmony_ci panda::libpandafile::CollectUtil collect_util; 195b1994897Sopenharmony_ci std::unordered_set<uint32_t> literal_array_ids; 196b1994897Sopenharmony_ci collect_util.CollectLiteralArray(*file_, literal_array_ids); 197b1994897Sopenharmony_ci PushToLiteralIds(literal_array_ids); 198b1994897Sopenharmony_ci } 199b1994897Sopenharmony_ci} 200b1994897Sopenharmony_ci 201b1994897Sopenharmony_citemplate <typename T> 202b1994897Sopenharmony_civoid Verifier::PushToLiteralIds(T &ids) 203b1994897Sopenharmony_ci{ 204b1994897Sopenharmony_ci for (const auto id : ids) { 205b1994897Sopenharmony_ci literal_ids_.push_back(id); 206b1994897Sopenharmony_ci } 207b1994897Sopenharmony_ci} 208b1994897Sopenharmony_ci 209b1994897Sopenharmony_cibool Verifier::CheckConstantPoolActions(const verifier::ActionType type, panda_file::File::EntityId method_id) 210b1994897Sopenharmony_ci{ 211b1994897Sopenharmony_ci switch (type) { 212b1994897Sopenharmony_ci case verifier::ActionType::CHECKCONSTPOOLCONTENT: { 213b1994897Sopenharmony_ci return CheckConstantPoolMethodContent(method_id); 214b1994897Sopenharmony_ci } 215b1994897Sopenharmony_ci case verifier::ActionType::COLLECTINFOS: { 216b1994897Sopenharmony_ci all_method_ids_.push_back(method_id.GetOffset()); 217b1994897Sopenharmony_ci return CollectIdInInstructions(method_id); 218b1994897Sopenharmony_ci } 219b1994897Sopenharmony_ci default: { 220b1994897Sopenharmony_ci return true; 221b1994897Sopenharmony_ci } 222b1994897Sopenharmony_ci } 223b1994897Sopenharmony_ci} 224b1994897Sopenharmony_ci 225b1994897Sopenharmony_cibool Verifier::CollectIdInInstructions(const panda_file::File::EntityId &method_id) 226b1994897Sopenharmony_ci{ 227b1994897Sopenharmony_ci panda_file::MethodDataAccessor method_accessor(*file_, method_id); 228b1994897Sopenharmony_ci ASSERT(method_accessor.GetCodeId().has_value()); 229b1994897Sopenharmony_ci panda_file::CodeDataAccessor code_accessor(*file_, method_accessor.GetCodeId().value()); 230b1994897Sopenharmony_ci const auto ins_size = code_accessor.GetCodeSize(); 231b1994897Sopenharmony_ci const auto ins_arr = code_accessor.GetInstructions(); 232b1994897Sopenharmony_ci 233b1994897Sopenharmony_ci auto bc_ins = BytecodeInstruction(ins_arr); 234b1994897Sopenharmony_ci const auto bc_ins_last = bc_ins.JumpTo(ins_size); 235b1994897Sopenharmony_ci 236b1994897Sopenharmony_ci while (bc_ins.GetAddress() < bc_ins_last.GetAddress()) { 237b1994897Sopenharmony_ci if (!bc_ins.IsPrimaryOpcodeValid()) { 238b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify primary opcode!"; 239b1994897Sopenharmony_ci return false; 240b1994897Sopenharmony_ci } 241b1994897Sopenharmony_ci if (bc_ins.HasFlag(BytecodeInstruction::Flags::LITERALARRAY_ID)) { 242b1994897Sopenharmony_ci // the idx of any instruction with a literal id is 0 243b1994897Sopenharmony_ci // except defineclasswithbuffer/callruntime.definesendableclass 244b1994897Sopenharmony_ci size_t idx = bc_ins.GetLiteralIndex(); 245b1994897Sopenharmony_ci const auto arg_literal_idx = bc_ins.GetId(idx).AsIndex(); 246b1994897Sopenharmony_ci const auto literal_id = file_->ResolveMethodIndex(method_id, arg_literal_idx); 247b1994897Sopenharmony_ci ins_literal_ids_.insert(literal_id.GetOffset()); 248b1994897Sopenharmony_ci } 249b1994897Sopenharmony_ci if (bc_ins.HasFlag(BytecodeInstruction::Flags::METHOD_ID)) { 250b1994897Sopenharmony_ci const auto arg_method_idx = bc_ins.GetId().AsIndex(); 251b1994897Sopenharmony_ci const auto arg_method_id = file_->ResolveMethodIndex(method_id, arg_method_idx); 252b1994897Sopenharmony_ci ins_method_ids_.insert(arg_method_id.GetOffset()); 253b1994897Sopenharmony_ci } 254b1994897Sopenharmony_ci if (bc_ins.HasFlag(BytecodeInstruction::Flags::STRING_ID)) { 255b1994897Sopenharmony_ci const auto arg_string_idx = bc_ins.GetId().AsIndex(); 256b1994897Sopenharmony_ci const auto string_id = file_->ResolveOffsetByIndex(method_id, arg_string_idx); 257b1994897Sopenharmony_ci ins_string_ids_.insert(string_id.GetOffset()); 258b1994897Sopenharmony_ci } 259b1994897Sopenharmony_ci bc_ins = bc_ins.GetNext(); 260b1994897Sopenharmony_ci } 261b1994897Sopenharmony_ci return true; 262b1994897Sopenharmony_ci} 263b1994897Sopenharmony_ci 264b1994897Sopenharmony_civoid Verifier::CollectModuleLiteralId(const panda_file::File::EntityId &field_id) 265b1994897Sopenharmony_ci{ 266b1994897Sopenharmony_ci panda_file::FieldDataAccessor field_accessor(*file_, field_id); 267b1994897Sopenharmony_ci const auto literal_id = field_accessor.GetValue<uint32_t>().value(); 268b1994897Sopenharmony_ci if (std::find(literal_ids_.begin(), literal_ids_.end(), literal_id) != literal_ids_.end()) { 269b1994897Sopenharmony_ci module_literals_.insert(literal_id); 270b1994897Sopenharmony_ci } 271b1994897Sopenharmony_ci} 272b1994897Sopenharmony_ci 273b1994897Sopenharmony_cibool Verifier::CheckConstantPool(const verifier::ActionType type) 274b1994897Sopenharmony_ci{ 275b1994897Sopenharmony_ci const auto class_idx = file_->GetClasses(); 276b1994897Sopenharmony_ci for (size_t i = 0; i < class_idx.size(); i++) { 277b1994897Sopenharmony_ci uint32_t class_id = class_idx[i]; 278b1994897Sopenharmony_ci if (class_id > file_->GetHeader()->file_size) { 279b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Binary file corrupted. out of bounds (0x" << std::hex 280b1994897Sopenharmony_ci << file_->GetHeader()->file_size; 281b1994897Sopenharmony_ci return false; 282b1994897Sopenharmony_ci } 283b1994897Sopenharmony_ci const panda_file::File::EntityId record_id {class_id}; 284b1994897Sopenharmony_ci if (!file_->IsExternal(record_id)) { 285b1994897Sopenharmony_ci panda_file::ClassDataAccessor class_accessor {*file_, record_id}; 286b1994897Sopenharmony_ci bool check_res = true; 287b1994897Sopenharmony_ci class_accessor.EnumerateMethods([&](panda_file::MethodDataAccessor &method_accessor) -> void { 288b1994897Sopenharmony_ci check_res = check_res && CheckConstantPoolActions(type, method_accessor.GetMethodId()); 289b1994897Sopenharmony_ci }); 290b1994897Sopenharmony_ci if (!check_res) { 291b1994897Sopenharmony_ci return false; 292b1994897Sopenharmony_ci } 293b1994897Sopenharmony_ci if (type == verifier::ActionType::COLLECTINFOS) { 294b1994897Sopenharmony_ci class_accessor.EnumerateFields([&](panda_file::FieldDataAccessor &field_accessor) -> void { 295b1994897Sopenharmony_ci CollectModuleLiteralId(field_accessor.GetFieldId()); 296b1994897Sopenharmony_ci }); 297b1994897Sopenharmony_ci } 298b1994897Sopenharmony_ci } 299b1994897Sopenharmony_ci } 300b1994897Sopenharmony_ci 301b1994897Sopenharmony_ci return true; 302b1994897Sopenharmony_ci} 303b1994897Sopenharmony_ci 304b1994897Sopenharmony_cisize_t Verifier::GetVRegCount(const BytecodeInstruction &bc_ins) 305b1994897Sopenharmony_ci{ 306b1994897Sopenharmony_ci size_t idx = 0; // Represents the idxTH register index in an instruction 307b1994897Sopenharmony_ci BytecodeInstruction::Format format = bc_ins.GetFormat(); 308b1994897Sopenharmony_ci while (bc_ins.HasVReg(format, idx)) { 309b1994897Sopenharmony_ci idx++; 310b1994897Sopenharmony_ci } 311b1994897Sopenharmony_ci return idx; 312b1994897Sopenharmony_ci} 313b1994897Sopenharmony_ci 314b1994897Sopenharmony_cibool Verifier::IsRangeInstAndHasInvalidRegIdx(const BytecodeInstruction &bc_ins, 315b1994897Sopenharmony_ci const size_t count, uint64_t valid_regs_num) 316b1994897Sopenharmony_ci{ 317b1994897Sopenharmony_ci ASSERT(bc_ins.IsRangeInstruction()); 318b1994897Sopenharmony_ci 319b1994897Sopenharmony_ci uint64_t reg_idx = bc_ins.GetVReg(FIRST_INDEX); 320b1994897Sopenharmony_ci if (IsRegIdxOutOfBounds(reg_idx, valid_regs_num)) { // for [format: +AA/+AAAA vBB vCC], vBB can be verified here 321b1994897Sopenharmony_ci return true; 322b1994897Sopenharmony_ci } 323b1994897Sopenharmony_ci 324b1994897Sopenharmony_ci std::optional<uint64_t> max_ins_reg_idx_opt = bc_ins.GetRangeInsLastRegIdx(); 325b1994897Sopenharmony_ci if (!max_ins_reg_idx_opt.has_value()) { 326b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Integer overflow detected during register index calculation!"; 327b1994897Sopenharmony_ci return true; 328b1994897Sopenharmony_ci } 329b1994897Sopenharmony_ci 330b1994897Sopenharmony_ci reg_idx = max_ins_reg_idx_opt.value(); 331b1994897Sopenharmony_ci if (IsRegIdxOutOfBounds(reg_idx, valid_regs_num)) { 332b1994897Sopenharmony_ci return true; 333b1994897Sopenharmony_ci } 334b1994897Sopenharmony_ci 335b1994897Sopenharmony_ci return false; 336b1994897Sopenharmony_ci} 337b1994897Sopenharmony_ci 338b1994897Sopenharmony_cibool Verifier::IsRegIdxOutOfBounds(uint64_t reg_idx, uint64_t valid_regs_num) 339b1994897Sopenharmony_ci{ 340b1994897Sopenharmony_ci if (reg_idx >= valid_regs_num) { 341b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Register index out of bounds: 0x" << std::hex 342b1994897Sopenharmony_ci << reg_idx << ", Max allowed: 0x" << std::hex << valid_regs_num; 343b1994897Sopenharmony_ci return true; 344b1994897Sopenharmony_ci } 345b1994897Sopenharmony_ci return false; 346b1994897Sopenharmony_ci} 347b1994897Sopenharmony_ci 348b1994897Sopenharmony_cibool Verifier::CheckVRegIdx(const BytecodeInstruction &bc_ins, const size_t count, uint64_t valid_regs_num) 349b1994897Sopenharmony_ci{ 350b1994897Sopenharmony_ci if (bc_ins.IsRangeInstruction() && 351b1994897Sopenharmony_ci IsRangeInstAndHasInvalidRegIdx(bc_ins, count, valid_regs_num)) { 352b1994897Sopenharmony_ci return false; 353b1994897Sopenharmony_ci } 354b1994897Sopenharmony_ci for (size_t idx = 0; idx < count; idx++) { // Represents the idxTH register index in an instruction 355b1994897Sopenharmony_ci uint16_t reg_idx = bc_ins.GetVReg(idx); 356b1994897Sopenharmony_ci if (reg_idx >= valid_regs_num) { 357b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Register index out of bounds: 0x" << std::hex 358b1994897Sopenharmony_ci << reg_idx << ", Max allowed: 0x" << std::hex << valid_regs_num; 359b1994897Sopenharmony_ci return false; 360b1994897Sopenharmony_ci } 361b1994897Sopenharmony_ci } 362b1994897Sopenharmony_ci return true; 363b1994897Sopenharmony_ci} 364b1994897Sopenharmony_ci 365b1994897Sopenharmony_cibool Verifier::VerifyMethodId(const uint32_t &method_id) const 366b1994897Sopenharmony_ci{ 367b1994897Sopenharmony_ci auto iter = std::find(constant_pool_ids_.begin(), constant_pool_ids_.end(), method_id); 368b1994897Sopenharmony_ci if (iter == constant_pool_ids_.end() || 369b1994897Sopenharmony_ci (std::find(literal_ids_.begin(), literal_ids_.end(), method_id) != literal_ids_.end()) || 370b1994897Sopenharmony_ci ins_string_ids_.count(method_id)) { 371b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify method id. method_id(0x" << std::hex << method_id << ")!"; 372b1994897Sopenharmony_ci return false; 373b1994897Sopenharmony_ci } 374b1994897Sopenharmony_ci return true; 375b1994897Sopenharmony_ci} 376b1994897Sopenharmony_ci 377b1994897Sopenharmony_cibool Verifier::VerifyLiteralId(const uint32_t &literal_id) const 378b1994897Sopenharmony_ci{ 379b1994897Sopenharmony_ci auto iter = std::find(constant_pool_ids_.begin(), constant_pool_ids_.end(), literal_id); 380b1994897Sopenharmony_ci if (iter == constant_pool_ids_.end() || 381b1994897Sopenharmony_ci (std::find(all_method_ids_.begin(), all_method_ids_.end(), literal_id) != all_method_ids_.end()) || 382b1994897Sopenharmony_ci ins_string_ids_.count(literal_id)) { 383b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify literal id. literal_id(0x" << std::hex << literal_id << ")!"; 384b1994897Sopenharmony_ci return false; 385b1994897Sopenharmony_ci } 386b1994897Sopenharmony_ci return true; 387b1994897Sopenharmony_ci} 388b1994897Sopenharmony_ci 389b1994897Sopenharmony_cibool Verifier::VerifyStringId(const uint32_t &string_id) const 390b1994897Sopenharmony_ci{ 391b1994897Sopenharmony_ci auto iter = std::find(constant_pool_ids_.begin(), constant_pool_ids_.end(), string_id); 392b1994897Sopenharmony_ci if (iter == constant_pool_ids_.end() || 393b1994897Sopenharmony_ci ins_method_ids_.count(string_id) || 394b1994897Sopenharmony_ci (std::find(literal_ids_.begin(), literal_ids_.end(), string_id) != literal_ids_.end())) { 395b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify string id. string_id(0x" << std::hex << string_id << ")!"; 396b1994897Sopenharmony_ci return false; 397b1994897Sopenharmony_ci } 398b1994897Sopenharmony_ci return true; 399b1994897Sopenharmony_ci} 400b1994897Sopenharmony_ci 401b1994897Sopenharmony_cistd::optional<int64_t> Verifier::GetFirstImmFromInstruction(const BytecodeInstruction &bc_ins) 402b1994897Sopenharmony_ci{ 403b1994897Sopenharmony_ci std::optional<int64_t> first_imm = std::optional<int64_t> {}; 404b1994897Sopenharmony_ci size_t index = 0; 405b1994897Sopenharmony_ci const auto format = bc_ins.GetFormat(); 406b1994897Sopenharmony_ci if (bc_ins.HasImm(format, index)) { 407b1994897Sopenharmony_ci first_imm = bc_ins.GetImm64(index); 408b1994897Sopenharmony_ci } 409b1994897Sopenharmony_ci 410b1994897Sopenharmony_ci return first_imm; 411b1994897Sopenharmony_ci} 412b1994897Sopenharmony_ci 413b1994897Sopenharmony_cistd::optional<uint64_t> Verifier::GetSlotNumberFromAnnotation(panda_file::MethodDataAccessor &method_accessor) 414b1994897Sopenharmony_ci{ 415b1994897Sopenharmony_ci std::optional<uint64_t> slot_number {}; 416b1994897Sopenharmony_ci method_accessor.EnumerateAnnotations([&](panda_file::File::EntityId annotation_id) { 417b1994897Sopenharmony_ci panda_file::AnnotationDataAccessor ada(*file_, annotation_id); 418b1994897Sopenharmony_ci auto *annotation_name = reinterpret_cast<const char *>(file_->GetStringData(ada.GetClassId()).data); 419b1994897Sopenharmony_ci if (::strcmp("L_ESSlotNumberAnnotation;", annotation_name) == 0) { 420b1994897Sopenharmony_ci uint32_t elem_count = ada.GetCount(); 421b1994897Sopenharmony_ci for (uint32_t i = 0; i < elem_count; i++) { 422b1994897Sopenharmony_ci panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i); 423b1994897Sopenharmony_ci auto *elem_name = reinterpret_cast<const char *>(file_->GetStringData(adae.GetNameId()).data); 424b1994897Sopenharmony_ci if (::strcmp("SlotNumber", elem_name) == 0) { 425b1994897Sopenharmony_ci slot_number = adae.GetScalarValue().GetValue(); 426b1994897Sopenharmony_ci } 427b1994897Sopenharmony_ci } 428b1994897Sopenharmony_ci } 429b1994897Sopenharmony_ci }); 430b1994897Sopenharmony_ci return slot_number; 431b1994897Sopenharmony_ci} 432b1994897Sopenharmony_ci 433b1994897Sopenharmony_cibool Verifier::VerifyMethodIdInLiteralArray(const uint32_t &id) 434b1994897Sopenharmony_ci{ 435b1994897Sopenharmony_ci const auto method_id = panda_file::File::EntityId(id).GetOffset(); 436b1994897Sopenharmony_ci auto iter = std::find(all_method_ids_.begin(), all_method_ids_.end(), method_id); 437b1994897Sopenharmony_ci if (iter == all_method_ids_.end()) { 438b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Invalid method id(0x" << id << ") in literal array"; 439b1994897Sopenharmony_ci return false; 440b1994897Sopenharmony_ci } 441b1994897Sopenharmony_ci return true; 442b1994897Sopenharmony_ci} 443b1994897Sopenharmony_ci 444b1994897Sopenharmony_cibool Verifier::VerifyStringIdInLiteralArray(const uint32_t &id) 445b1994897Sopenharmony_ci{ 446b1994897Sopenharmony_ci auto string_data = file_->GetStringData(panda_file::File::EntityId(id)); 447b1994897Sopenharmony_ci if (string_data.data == nullptr) { 448b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Invalid string_id. string_id(0x" << std::hex << id << ")!"; 449b1994897Sopenharmony_ci return false; 450b1994897Sopenharmony_ci } 451b1994897Sopenharmony_ci auto desc = std::string(utf::Mutf8AsCString(string_data.data)); 452b1994897Sopenharmony_ci std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter; 453b1994897Sopenharmony_ci std::wstring utf16_desc = converter.from_bytes(desc); 454b1994897Sopenharmony_ci if (string_data.utf16_length != utf16_desc.length()) { 455b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Invalid string value(0x" << id << ") in literal array"; 456b1994897Sopenharmony_ci return false; 457b1994897Sopenharmony_ci } 458b1994897Sopenharmony_ci return true; 459b1994897Sopenharmony_ci} 460b1994897Sopenharmony_ci 461b1994897Sopenharmony_cibool Verifier::VerifyLiteralIdInLiteralArray(const uint32_t &id) 462b1994897Sopenharmony_ci{ 463b1994897Sopenharmony_ci auto iter = std::find(literal_ids_.begin(), literal_ids_.end(), id); 464b1994897Sopenharmony_ci if (iter == literal_ids_.end()) { 465b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Invalid literal id(0x" << id << ") in literal array"; 466b1994897Sopenharmony_ci return false; 467b1994897Sopenharmony_ci } 468b1994897Sopenharmony_ci return true; 469b1994897Sopenharmony_ci} 470b1994897Sopenharmony_ci 471b1994897Sopenharmony_cibool Verifier::VerifySingleLiteralArray(const panda_file::File::EntityId &literal_id) 472b1994897Sopenharmony_ci{ 473b1994897Sopenharmony_ci auto sp = file_->GetSpanFromId(literal_id); 474b1994897Sopenharmony_ci const auto literal_vals_num = panda_file::helpers::Read<sizeof(uint32_t)>(&sp); 475b1994897Sopenharmony_ci for (size_t i = 0; i < literal_vals_num; i += 2U) { // 2u skip literal item 476b1994897Sopenharmony_ci const auto tag = static_cast<panda_file::LiteralTag>(panda_file::helpers::Read<panda_file::TAG_SIZE>(&sp)); 477b1994897Sopenharmony_ci switch (tag) { 478b1994897Sopenharmony_ci case panda_file::LiteralTag::TAGVALUE: 479b1994897Sopenharmony_ci case panda_file::LiteralTag::BOOL: 480b1994897Sopenharmony_ci case panda_file::LiteralTag::ACCESSOR: 481b1994897Sopenharmony_ci case panda_file::LiteralTag::NULLVALUE: 482b1994897Sopenharmony_ci case panda_file::LiteralTag::BUILTINTYPEINDEX: { 483b1994897Sopenharmony_ci sp = sp.SubSpan(sizeof(uint8_t)); // run next sp 484b1994897Sopenharmony_ci break; 485b1994897Sopenharmony_ci } 486b1994897Sopenharmony_ci case panda_file::LiteralTag::METHODAFFILIATE: { 487b1994897Sopenharmony_ci sp = sp.SubSpan(sizeof(uint16_t)); 488b1994897Sopenharmony_ci break; 489b1994897Sopenharmony_ci } 490b1994897Sopenharmony_ci case panda_file::LiteralTag::INTEGER: 491b1994897Sopenharmony_ci case panda_file::LiteralTag::FLOAT: 492b1994897Sopenharmony_ci case panda_file::LiteralTag::GETTER: 493b1994897Sopenharmony_ci case panda_file::LiteralTag::SETTER: 494b1994897Sopenharmony_ci case panda_file::LiteralTag::GENERATORMETHOD: 495b1994897Sopenharmony_ci case panda_file::LiteralTag::LITERALBUFFERINDEX: 496b1994897Sopenharmony_ci case panda_file::LiteralTag::ASYNCGENERATORMETHOD: { 497b1994897Sopenharmony_ci sp = sp.SubSpan(sizeof(uint32_t)); 498b1994897Sopenharmony_ci break; 499b1994897Sopenharmony_ci } 500b1994897Sopenharmony_ci case panda_file::LiteralTag::DOUBLE: { 501b1994897Sopenharmony_ci const auto value = bit_cast<double>(panda_file::helpers::Read<sizeof(uint64_t)>(&sp)); 502b1994897Sopenharmony_ci // true: High 16-bit of double value >= 0xffff 503b1994897Sopenharmony_ci if (IsImpureNaN(value)) { 504b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify double value " << value << " in literal array"; 505b1994897Sopenharmony_ci return false; 506b1994897Sopenharmony_ci } 507b1994897Sopenharmony_ci break; 508b1994897Sopenharmony_ci } 509b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_U1: 510b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_U8: 511b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_I8: 512b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_U16: 513b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_I16: 514b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_U32: 515b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_I32: 516b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_U64: 517b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_I64: 518b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_F32: 519b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_F64: 520b1994897Sopenharmony_ci case panda_file::LiteralTag::ARRAY_STRING: { 521b1994897Sopenharmony_ci i = literal_vals_num; 522b1994897Sopenharmony_ci break; 523b1994897Sopenharmony_ci } 524b1994897Sopenharmony_ci case panda_file::LiteralTag::STRING: { 525b1994897Sopenharmony_ci panda_file::helpers::Read<sizeof(uint32_t)>(&sp); 526b1994897Sopenharmony_ci break; 527b1994897Sopenharmony_ci } 528b1994897Sopenharmony_ci case panda_file::LiteralTag::METHOD: { 529b1994897Sopenharmony_ci const auto value = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&sp)); 530b1994897Sopenharmony_ci inner_method_map_.emplace(literal_id.GetOffset(), value); 531b1994897Sopenharmony_ci if (!VerifyMethodIdInLiteralArray(value)) { 532b1994897Sopenharmony_ci return false; 533b1994897Sopenharmony_ci } 534b1994897Sopenharmony_ci break; 535b1994897Sopenharmony_ci } 536b1994897Sopenharmony_ci case panda_file::LiteralTag::LITERALARRAY: { 537b1994897Sopenharmony_ci const auto value = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&sp)); 538b1994897Sopenharmony_ci inner_literal_map_.emplace(literal_id.GetOffset(), value); 539b1994897Sopenharmony_ci if (!VerifyLiteralIdInLiteralArray(value)) { 540b1994897Sopenharmony_ci return false; 541b1994897Sopenharmony_ci } 542b1994897Sopenharmony_ci break; 543b1994897Sopenharmony_ci } 544b1994897Sopenharmony_ci default: { 545b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Invalid literal tag"; 546b1994897Sopenharmony_ci return false; 547b1994897Sopenharmony_ci } 548b1994897Sopenharmony_ci } 549b1994897Sopenharmony_ci } 550b1994897Sopenharmony_ci return true; 551b1994897Sopenharmony_ci} 552b1994897Sopenharmony_ci 553b1994897Sopenharmony_cibool Verifier::IsModuleLiteralId(const panda_file::File::EntityId &id) const 554b1994897Sopenharmony_ci{ 555b1994897Sopenharmony_ci return module_literals_.find(id.GetOffset()) != module_literals_.end(); 556b1994897Sopenharmony_ci} 557b1994897Sopenharmony_ci 558b1994897Sopenharmony_cibool Verifier::VerifyLiteralArrays() 559b1994897Sopenharmony_ci{ 560b1994897Sopenharmony_ci for (const auto &arg_literal_id : literal_ids_) { 561b1994897Sopenharmony_ci const auto literal_id = panda_file::File::EntityId(arg_literal_id); 562b1994897Sopenharmony_ci if (!IsModuleLiteralId(literal_id) && !VerifySingleLiteralArray(literal_id)) { 563b1994897Sopenharmony_ci return false; 564b1994897Sopenharmony_ci } 565b1994897Sopenharmony_ci } 566b1994897Sopenharmony_ci return true; 567b1994897Sopenharmony_ci} 568b1994897Sopenharmony_ci 569b1994897Sopenharmony_cibool Verifier::PrecomputeInstructionIndices(const BytecodeInstruction &bc_ins_start, 570b1994897Sopenharmony_ci const BytecodeInstruction &bc_ins_last) 571b1994897Sopenharmony_ci{ 572b1994897Sopenharmony_ci instruction_index_map_.clear(); 573b1994897Sopenharmony_ci size_t index = 0; 574b1994897Sopenharmony_ci auto current_ins = bc_ins_start; 575b1994897Sopenharmony_ci instruction_index_map_[current_ins.GetAddress()] = index; 576b1994897Sopenharmony_ci 577b1994897Sopenharmony_ci while (current_ins.GetAddress() < bc_ins_last.GetAddress()) { 578b1994897Sopenharmony_ci //Must keep IsPrimaryOpcodeValid is the first check item 579b1994897Sopenharmony_ci if (!current_ins.IsPrimaryOpcodeValid()) { 580b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify primary opcode!"; 581b1994897Sopenharmony_ci return false; 582b1994897Sopenharmony_ci } 583b1994897Sopenharmony_ci current_ins = current_ins.GetNext(); 584b1994897Sopenharmony_ci index++; 585b1994897Sopenharmony_ci instruction_index_map_[current_ins.GetAddress()] = index; 586b1994897Sopenharmony_ci } 587b1994897Sopenharmony_ci return true; 588b1994897Sopenharmony_ci} 589b1994897Sopenharmony_ci 590b1994897Sopenharmony_cibool Verifier::IsMethodBytecodeInstruction(const BytecodeInstruction &bc_ins_cur) 591b1994897Sopenharmony_ci{ 592b1994897Sopenharmony_ci if (instruction_index_map_.find(bc_ins_cur.GetAddress()) != instruction_index_map_.end()) { 593b1994897Sopenharmony_ci return true; 594b1994897Sopenharmony_ci } 595b1994897Sopenharmony_ci return false; 596b1994897Sopenharmony_ci} 597b1994897Sopenharmony_ci 598b1994897Sopenharmony_cibool Verifier::VerifyJumpInstruction(const BytecodeInstruction &bc_ins, const BytecodeInstruction &bc_ins_last, 599b1994897Sopenharmony_ci const BytecodeInstruction &bc_ins_first, const uint8_t *ins_arr, 600b1994897Sopenharmony_ci panda_file::File::EntityId code_id) 601b1994897Sopenharmony_ci{ 602b1994897Sopenharmony_ci // update maximum forward offset 603b1994897Sopenharmony_ci const auto bc_ins_forward_size = bc_ins_last.GetAddress() - bc_ins.GetAddress(); 604b1994897Sopenharmony_ci // update maximum backward offset 605b1994897Sopenharmony_ci const auto bc_ins_backward_size = bc_ins.GetAddress() - bc_ins_first.GetAddress(); 606b1994897Sopenharmony_ci 607b1994897Sopenharmony_ci if (bc_ins.IsJumpInstruction()) { 608b1994897Sopenharmony_ci std::optional<int64_t> immdata = GetFirstImmFromInstruction(bc_ins); 609b1994897Sopenharmony_ci if (!immdata.has_value()) { 610b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to get immediate data!"; 611b1994897Sopenharmony_ci return false; 612b1994897Sopenharmony_ci } 613b1994897Sopenharmony_ci if ((immdata.value() > 0) && (immdata.value() >= bc_ins_forward_size)) { 614b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Jump forward out of boundary"; 615b1994897Sopenharmony_ci return false; 616b1994897Sopenharmony_ci } 617b1994897Sopenharmony_ci if ((immdata.value() < 0) && (bc_ins_backward_size + immdata.value() < 0)) { 618b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Jump backward out of boundary"; 619b1994897Sopenharmony_ci return false; 620b1994897Sopenharmony_ci } 621b1994897Sopenharmony_ci 622b1994897Sopenharmony_ci const auto bc_ins_dest = bc_ins.JumpTo(immdata.value()); 623b1994897Sopenharmony_ci if (!bc_ins_dest.IsPrimaryOpcodeValid()) { 624b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify target jump primary opcode!"; 625b1994897Sopenharmony_ci return false; 626b1994897Sopenharmony_ci } 627b1994897Sopenharmony_ci if (!IsMethodBytecodeInstruction(bc_ins_dest)) { 628b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> error encountered at " << code_id << " (0x" << std::hex << code_id 629b1994897Sopenharmony_ci << "). incorrect instruction at offset: 0x" << (bc_ins.GetAddress() - ins_arr) 630b1994897Sopenharmony_ci << ": invalid jump offset 0x" << immdata.value() 631b1994897Sopenharmony_ci << " - jumping in the middle of another instruction!"; 632b1994897Sopenharmony_ci return false; 633b1994897Sopenharmony_ci } 634b1994897Sopenharmony_ci } 635b1994897Sopenharmony_ci 636b1994897Sopenharmony_ci return true; 637b1994897Sopenharmony_ci} 638b1994897Sopenharmony_ci 639b1994897Sopenharmony_cibool Verifier::GetIcSlotFromInstruction(const BytecodeInstruction &bc_ins, uint32_t &first_slot_index, 640b1994897Sopenharmony_ci bool &has_slot, bool &is_two_slot) 641b1994897Sopenharmony_ci{ 642b1994897Sopenharmony_ci std::optional<uint64_t> first_imm = {}; 643b1994897Sopenharmony_ci if (bc_ins.HasFlag(BytecodeInstruction::Flags::ONE_SLOT)) { 644b1994897Sopenharmony_ci first_imm = GetFirstImmFromInstruction(bc_ins); 645b1994897Sopenharmony_ci if (!first_imm.has_value()) { 646b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to get first immediate data!"; 647b1994897Sopenharmony_ci return false; 648b1994897Sopenharmony_ci } 649b1994897Sopenharmony_ci first_slot_index = first_imm.value(); 650b1994897Sopenharmony_ci is_two_slot = false; 651b1994897Sopenharmony_ci has_slot = true; 652b1994897Sopenharmony_ci } else if (bc_ins.HasFlag(BytecodeInstruction::Flags::TWO_SLOT)) { 653b1994897Sopenharmony_ci first_imm = GetFirstImmFromInstruction(bc_ins); 654b1994897Sopenharmony_ci if (!first_imm.has_value()) { 655b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to get first immediate data!"; 656b1994897Sopenharmony_ci return false; 657b1994897Sopenharmony_ci } 658b1994897Sopenharmony_ci first_slot_index = first_imm.value(); 659b1994897Sopenharmony_ci has_slot = true; 660b1994897Sopenharmony_ci is_two_slot = true; 661b1994897Sopenharmony_ci } 662b1994897Sopenharmony_ci 663b1994897Sopenharmony_ci return true; 664b1994897Sopenharmony_ci} 665b1994897Sopenharmony_ci 666b1994897Sopenharmony_cibool Verifier::VerifyCatchBlocks(panda_file::CodeDataAccessor::TryBlock &try_block, const BytecodeInstruction &bc_ins, 667b1994897Sopenharmony_ci const BytecodeInstruction &bc_ins_last) 668b1994897Sopenharmony_ci{ 669b1994897Sopenharmony_ci bool result = true; 670b1994897Sopenharmony_ci 671b1994897Sopenharmony_ci try_block.EnumerateCatchBlocks([&](panda_file::CodeDataAccessor::CatchBlock &catch_block) { 672b1994897Sopenharmony_ci const auto handler_begin_offset = catch_block.GetHandlerPc(); 673b1994897Sopenharmony_ci // GetCodeSize() returns a unsigned long value, which is always >= 0, 674b1994897Sopenharmony_ci // so handler_end_offset is guaranteed to be >= handler_begin_offset 675b1994897Sopenharmony_ci const auto handler_end_offset = handler_begin_offset + catch_block.GetCodeSize(); 676b1994897Sopenharmony_ci 677b1994897Sopenharmony_ci const auto handler_begin_bc_ins = bc_ins.JumpTo(handler_begin_offset); 678b1994897Sopenharmony_ci const auto handler_end_bc_ins = bc_ins.JumpTo(handler_end_offset); 679b1994897Sopenharmony_ci 680b1994897Sopenharmony_ci const bool handler_begin_offset_in_range = bc_ins_last.GetAddress() > handler_begin_bc_ins.GetAddress(); 681b1994897Sopenharmony_ci const bool handler_end_offset_in_range = bc_ins_last.GetAddress() >= handler_end_bc_ins.GetAddress(); 682b1994897Sopenharmony_ci 683b1994897Sopenharmony_ci if (!handler_begin_offset_in_range) { 684b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> Invalid catch block begin offset range! address is: 0x" << std::hex 685b1994897Sopenharmony_ci << handler_begin_bc_ins.GetAddress(); 686b1994897Sopenharmony_ci result = false; 687b1994897Sopenharmony_ci return false; 688b1994897Sopenharmony_ci } 689b1994897Sopenharmony_ci if (!IsMethodBytecodeInstruction(handler_begin_bc_ins)) { 690b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> Invalid catch block begin offset validity! address is: 0x" << std::hex 691b1994897Sopenharmony_ci << handler_begin_bc_ins.GetAddress(); 692b1994897Sopenharmony_ci result = false; 693b1994897Sopenharmony_ci return false; 694b1994897Sopenharmony_ci } 695b1994897Sopenharmony_ci if (!handler_end_offset_in_range) { 696b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> Invalid catch block end offset range! address is: 0x" << std::hex 697b1994897Sopenharmony_ci << handler_end_bc_ins.GetAddress(); 698b1994897Sopenharmony_ci result = false; 699b1994897Sopenharmony_ci return false; 700b1994897Sopenharmony_ci } 701b1994897Sopenharmony_ci if (!IsMethodBytecodeInstruction(handler_end_bc_ins)) { 702b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> Invalid catch block end offset validity! address is: 0x" << std::hex 703b1994897Sopenharmony_ci << handler_end_bc_ins.GetAddress(); 704b1994897Sopenharmony_ci result = false; 705b1994897Sopenharmony_ci return false; 706b1994897Sopenharmony_ci } 707b1994897Sopenharmony_ci 708b1994897Sopenharmony_ci return true; 709b1994897Sopenharmony_ci }); 710b1994897Sopenharmony_ci 711b1994897Sopenharmony_ci return result; 712b1994897Sopenharmony_ci} 713b1994897Sopenharmony_ci 714b1994897Sopenharmony_cibool Verifier::VerifyTryBlocks(panda_file::CodeDataAccessor &code_accessor, const BytecodeInstruction &bc_ins, 715b1994897Sopenharmony_ci const BytecodeInstruction &bc_ins_last) 716b1994897Sopenharmony_ci{ 717b1994897Sopenharmony_ci bool result = true; 718b1994897Sopenharmony_ci 719b1994897Sopenharmony_ci code_accessor.EnumerateTryBlocks([&](panda_file::CodeDataAccessor::TryBlock &try_block) { 720b1994897Sopenharmony_ci const auto try_begin_bc_ins = bc_ins.JumpTo(try_block.GetStartPc()); 721b1994897Sopenharmony_ci // GetLength() returns a uint32 value, which is always >= 0, 722b1994897Sopenharmony_ci // so try_end_bc_ins is guaranteed to be >= try_begin_bc_ins 723b1994897Sopenharmony_ci const auto try_end_bc_ins = bc_ins.JumpTo(try_block.GetStartPc() + try_block.GetLength()); 724b1994897Sopenharmony_ci 725b1994897Sopenharmony_ci const bool try_begin_offset_in_range = bc_ins_last.GetAddress() > try_begin_bc_ins.GetAddress(); 726b1994897Sopenharmony_ci const bool try_end_offset_in_range = bc_ins_last.GetAddress() >= try_end_bc_ins.GetAddress(); 727b1994897Sopenharmony_ci 728b1994897Sopenharmony_ci if (!try_begin_offset_in_range) { 729b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> Invalid try block begin offset range! address is: 0x" << std::hex 730b1994897Sopenharmony_ci << try_begin_bc_ins.GetAddress(); 731b1994897Sopenharmony_ci result = false; 732b1994897Sopenharmony_ci return false; 733b1994897Sopenharmony_ci } 734b1994897Sopenharmony_ci if (!IsMethodBytecodeInstruction(try_begin_bc_ins)) { 735b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> Invalid try block begin offset validity! address is: 0x" << std::hex 736b1994897Sopenharmony_ci << try_begin_bc_ins.GetAddress(); 737b1994897Sopenharmony_ci result = false; 738b1994897Sopenharmony_ci return false; 739b1994897Sopenharmony_ci } 740b1994897Sopenharmony_ci if (!try_end_offset_in_range) { 741b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> Invalid try block end offset range! address is: 0x" << std::hex 742b1994897Sopenharmony_ci << try_end_bc_ins.GetAddress(); 743b1994897Sopenharmony_ci result = false; 744b1994897Sopenharmony_ci return false; 745b1994897Sopenharmony_ci } 746b1994897Sopenharmony_ci if (!IsMethodBytecodeInstruction(try_end_bc_ins)) { 747b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> Invalid try block end offset validity! address is: 0x" << std::hex 748b1994897Sopenharmony_ci << try_end_bc_ins.GetAddress(); 749b1994897Sopenharmony_ci result = false; 750b1994897Sopenharmony_ci return false; 751b1994897Sopenharmony_ci } 752b1994897Sopenharmony_ci if (!VerifyCatchBlocks(try_block, bc_ins, bc_ins_last)) { 753b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Catch block validation failed!"; 754b1994897Sopenharmony_ci result = false; 755b1994897Sopenharmony_ci return false; 756b1994897Sopenharmony_ci } 757b1994897Sopenharmony_ci 758b1994897Sopenharmony_ci return true; 759b1994897Sopenharmony_ci }); 760b1994897Sopenharmony_ci 761b1994897Sopenharmony_ci return result; 762b1994897Sopenharmony_ci} 763b1994897Sopenharmony_ci 764b1994897Sopenharmony_ci 765b1994897Sopenharmony_cibool Verifier::VerifySlotNumber(panda_file::MethodDataAccessor &method_accessor, const uint32_t &slot_number, 766b1994897Sopenharmony_ci const panda_file::File::EntityId &method_id) 767b1994897Sopenharmony_ci{ 768b1994897Sopenharmony_ci const auto ann_slot_number = GetSlotNumberFromAnnotation(method_accessor); 769b1994897Sopenharmony_ci if (!ann_slot_number.has_value()) { 770b1994897Sopenharmony_ci LOG(INFO, VERIFIER) << "There is no slot number information in annotaion."; 771b1994897Sopenharmony_ci // To be compatible with old abc, slot number verification is not continued 772b1994897Sopenharmony_ci return true; 773b1994897Sopenharmony_ci } 774b1994897Sopenharmony_ci if (slot_number == ann_slot_number.value()) { 775b1994897Sopenharmony_ci return true; 776b1994897Sopenharmony_ci } 777b1994897Sopenharmony_ci 778b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Slot number has been falsified in method 0x" << method_id; 779b1994897Sopenharmony_ci return false; 780b1994897Sopenharmony_ci} 781b1994897Sopenharmony_ci 782b1994897Sopenharmony_cibool Verifier::VerifyMethodRegisterIndex(panda_file::CodeDataAccessor &code_accessor, 783b1994897Sopenharmony_ci std::optional<uint64_t> &valid_regs_num) 784b1994897Sopenharmony_ci{ 785b1994897Sopenharmony_ci const uint64_t reg_nums = code_accessor.GetNumVregs(); 786b1994897Sopenharmony_ci const uint64_t arg_nums = code_accessor.GetNumArgs(); 787b1994897Sopenharmony_ci valid_regs_num = SafeAdd(reg_nums, arg_nums); 788b1994897Sopenharmony_ci if (!valid_regs_num.has_value()) { 789b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Integer overflow detected during register index calculation!"; 790b1994897Sopenharmony_ci return false; 791b1994897Sopenharmony_ci } 792b1994897Sopenharmony_ci if (valid_regs_num.value() > MAX_REGISTER_INDEX + 1) { 793b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Register index exceeds the maximum allowable value (0xffff)!"; 794b1994897Sopenharmony_ci return false; 795b1994897Sopenharmony_ci } 796b1994897Sopenharmony_ci return true; 797b1994897Sopenharmony_ci} 798b1994897Sopenharmony_ci 799b1994897Sopenharmony_cibool Verifier::VerifyMethodInstructions(const MethodInfos &infos) 800b1994897Sopenharmony_ci{ 801b1994897Sopenharmony_ci auto current_ins = infos.bc_ins; 802b1994897Sopenharmony_ci auto last_ins = infos.bc_ins_last; 803b1994897Sopenharmony_ci auto code_id = infos.method_accessor.GetCodeId().value(); 804b1994897Sopenharmony_ci auto method_id = infos.method_id; 805b1994897Sopenharmony_ci auto valid_regs_num = infos.valid_regs_num.value(); 806b1994897Sopenharmony_ci auto ins_slot_num = infos.ins_slot_num; 807b1994897Sopenharmony_ci auto has_slot = infos.has_slot; 808b1994897Sopenharmony_ci auto is_two_slot = infos.is_two_slot; 809b1994897Sopenharmony_ci 810b1994897Sopenharmony_ci while (current_ins.GetAddress() != last_ins.GetAddress()) { 811b1994897Sopenharmony_ci if (current_ins.GetAddress() > last_ins.GetAddress()) { 812b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> error encountered at " << code_id 813b1994897Sopenharmony_ci << " (0x" << std::hex << code_id 814b1994897Sopenharmony_ci << "). bytecode instructions sequence corrupted for method " 815b1994897Sopenharmony_ci << method_id 816b1994897Sopenharmony_ci << "! went out of bounds"; 817b1994897Sopenharmony_ci return false; 818b1994897Sopenharmony_ci } 819b1994897Sopenharmony_ci if (!current_ins.IsJumpInstruction() && !current_ins.IsReturnOrThrowInstruction() 820b1994897Sopenharmony_ci && current_ins.GetNext().GetAddress() == last_ins.GetAddress()) { 821b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "> error encountered at " << code_id 822b1994897Sopenharmony_ci << " (0x" << std::hex << code_id 823b1994897Sopenharmony_ci << "). bytecode instructions sequence corrupted for method " 824b1994897Sopenharmony_ci << method_id 825b1994897Sopenharmony_ci << "! went out of bounds"; 826b1994897Sopenharmony_ci return false; 827b1994897Sopenharmony_ci } 828b1994897Sopenharmony_ci const size_t count = GetVRegCount(current_ins); 829b1994897Sopenharmony_ci if (count != 0 && !CheckVRegIdx(current_ins, count, valid_regs_num)) { 830b1994897Sopenharmony_ci return false; 831b1994897Sopenharmony_ci } 832b1994897Sopenharmony_ci if (!VerifyJumpInstruction(current_ins, last_ins, 833b1994897Sopenharmony_ci infos.bc_ins_init, infos.ins_arr, 834b1994897Sopenharmony_ci code_id)) { 835b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Invalid target position of jump instruction"; 836b1994897Sopenharmony_ci return false; 837b1994897Sopenharmony_ci } 838b1994897Sopenharmony_ci if (!GetIcSlotFromInstruction(current_ins, ins_slot_num, 839b1994897Sopenharmony_ci has_slot, is_two_slot)) { 840b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to get first slot index!"; 841b1994897Sopenharmony_ci return false; 842b1994897Sopenharmony_ci } 843b1994897Sopenharmony_ci current_ins = current_ins.GetNext(); 844b1994897Sopenharmony_ci } 845b1994897Sopenharmony_ci return true; 846b1994897Sopenharmony_ci} 847b1994897Sopenharmony_ci 848b1994897Sopenharmony_cibool Verifier::CheckConstantPoolMethodContent(const panda_file::File::EntityId &method_id) 849b1994897Sopenharmony_ci{ 850b1994897Sopenharmony_ci panda_file::MethodDataAccessor method_accessor(*file_, method_id); 851b1994897Sopenharmony_ci if (!method_accessor.GetCodeId().has_value()) { 852b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to get code id!"; 853b1994897Sopenharmony_ci return false; 854b1994897Sopenharmony_ci } 855b1994897Sopenharmony_ci panda_file::CodeDataAccessor code_accessor(*file_, method_accessor.GetCodeId().value()); 856b1994897Sopenharmony_ci const auto ins_size = code_accessor.GetCodeSize(); 857b1994897Sopenharmony_ci const auto ins_arr = code_accessor.GetInstructions(); 858b1994897Sopenharmony_ci auto bc_ins = BytecodeInstruction(ins_arr); 859b1994897Sopenharmony_ci const auto bc_ins_last = bc_ins.JumpTo(ins_size); 860b1994897Sopenharmony_ci const auto bc_ins_init = bc_ins; // initial PC value 861b1994897Sopenharmony_ci uint32_t ins_slot_num = 0; // For ic slot index verification 862b1994897Sopenharmony_ci bool has_slot = false; 863b1994897Sopenharmony_ci bool is_two_slot = false; 864b1994897Sopenharmony_ci std::optional<uint64_t> valid_regs_num = 0; 865b1994897Sopenharmony_ci MethodInfos infos = {bc_ins_init, bc_ins, bc_ins_last, method_accessor, method_id, 866b1994897Sopenharmony_ci valid_regs_num, ins_arr, ins_slot_num, has_slot, is_two_slot}; 867b1994897Sopenharmony_ci if (ins_size <= 0) { 868b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify code size!"; 869b1994897Sopenharmony_ci return false; 870b1994897Sopenharmony_ci } 871b1994897Sopenharmony_ci if (!VerifyMethodRegisterIndex(code_accessor, valid_regs_num)) { 872b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify method register index!"; 873b1994897Sopenharmony_ci return false; 874b1994897Sopenharmony_ci } 875b1994897Sopenharmony_ci if (!PrecomputeInstructionIndices(bc_ins, bc_ins_last)) { 876b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to precompute instruction indices!"; 877b1994897Sopenharmony_ci return false; 878b1994897Sopenharmony_ci } 879b1994897Sopenharmony_ci if (!IsMethodBytecodeInstruction(bc_ins)) { 880b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify method first bytecode instruction!"; 881b1994897Sopenharmony_ci } 882b1994897Sopenharmony_ci if (!VerifyTryBlocks(code_accessor, bc_ins, bc_ins_last)) { 883b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify try blocks or catch blocks!"; 884b1994897Sopenharmony_ci return false; 885b1994897Sopenharmony_ci } 886b1994897Sopenharmony_ci if (!VerifyMethodInstructions(infos)) { 887b1994897Sopenharmony_ci LOG(ERROR, VERIFIER) << "Fail to verify method instructions!"; 888b1994897Sopenharmony_ci return false; 889b1994897Sopenharmony_ci } 890b1994897Sopenharmony_ci if (has_slot) { 891b1994897Sopenharmony_ci if (is_two_slot) { 892b1994897Sopenharmony_ci ins_slot_num += 1; // when there are two slots for the last instruction, the slot index increases 893b1994897Sopenharmony_ci } 894b1994897Sopenharmony_ci ins_slot_num += 1; // slot index starts with zero 895b1994897Sopenharmony_ci } 896b1994897Sopenharmony_ci return true; 897b1994897Sopenharmony_ci} 898b1994897Sopenharmony_ci 899b1994897Sopenharmony_cibool Verifier::CheckConstantPoolIndex() const 900b1994897Sopenharmony_ci{ 901b1994897Sopenharmony_ci for (auto &id : ins_method_ids_) { 902b1994897Sopenharmony_ci if (!VerifyMethodId(id)) { 903b1994897Sopenharmony_ci return false; 904b1994897Sopenharmony_ci } 905b1994897Sopenharmony_ci } 906b1994897Sopenharmony_ci 907b1994897Sopenharmony_ci for (auto &id : ins_literal_ids_) { 908b1994897Sopenharmony_ci if (!VerifyLiteralId(id)) { 909b1994897Sopenharmony_ci return false; 910b1994897Sopenharmony_ci } 911b1994897Sopenharmony_ci } 912b1994897Sopenharmony_ci 913b1994897Sopenharmony_ci for (auto &id : ins_string_ids_) { 914b1994897Sopenharmony_ci if (!VerifyStringId(id)) { 915b1994897Sopenharmony_ci return false; 916b1994897Sopenharmony_ci } 917b1994897Sopenharmony_ci } 918b1994897Sopenharmony_ci 919b1994897Sopenharmony_ci return true; 920b1994897Sopenharmony_ci} 921b1994897Sopenharmony_ci 922b1994897Sopenharmony_cistd::optional<uint64_t> Verifier::SafeAdd(uint64_t a, uint64_t b) const 923b1994897Sopenharmony_ci{ 924b1994897Sopenharmony_ci if (a > std::numeric_limits<uint64_t>::max() - b) { 925b1994897Sopenharmony_ci return std::nullopt; 926b1994897Sopenharmony_ci } 927b1994897Sopenharmony_ci return a + b; 928b1994897Sopenharmony_ci} 929b1994897Sopenharmony_ci} // namespace panda::verifier 930