• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 #include <codecvt>
16 #include <locale>
17 
18 #include "verifier.h"
19 #include "zlib.h"
20 #include "class_data_accessor-inl.h"
21 
22 namespace panda::verifier {
23 
Verifier(const std::string & filename)24 Verifier::Verifier(const std::string &filename)
25 {
26     auto file_to_verify = panda_file::File::Open(filename);
27     file_.swap(file_to_verify);
28 }
29 
Verify()30 bool Verifier::Verify()
31 {
32     CollectIdInfos();
33 
34     if (!VerifyChecksum()) {
35         return false;
36     }
37 
38     if (!VerifyConstantPool()) {
39         return false;
40     }
41 
42     if (!VerifyRegisterIndex()) {
43         return false;
44     }
45 
46     return true;
47 }
48 
CollectIdInfos()49 void Verifier::CollectIdInfos()
50 {
51     if (file_ == nullptr) {
52         return;
53     }
54     GetConstantPoolIds();
55     GetLiteralIds();
56     CheckConstantPool(verifier::ActionType::COLLECTINFOS);
57 }
58 
VerifyChecksum()59 bool Verifier::VerifyChecksum()
60 {
61     if (file_ == nullptr) {
62         return false;
63     }
64     uint32_t file_size = file_->GetHeader()->file_size;
65     ASSERT(file_size > FILE_CONTENT_OFFSET);
66     uint32_t cal_checksum = adler32(1, file_->GetBase() + FILE_CONTENT_OFFSET, file_size - FILE_CONTENT_OFFSET);
67     return file_->GetHeader()->checksum == cal_checksum;
68 }
69 
VerifyConstantPool()70 bool Verifier::VerifyConstantPool()
71 {
72     if (file_ == nullptr) {
73         return false;
74     }
75 
76     if (!CheckConstantPoolIndex()) {
77         return false;
78     }
79 
80     if (!CheckConstantPool(verifier::ActionType::CHECKCONSTPOOLCONTENT)) {
81         return false;
82     }
83 
84     if (!VerifyLiteralArrays()) {
85         return false;
86     }
87 
88     return true;
89 }
90 
VerifyRegisterIndex()91 bool Verifier::VerifyRegisterIndex()
92 {
93     if (file_ == nullptr) {
94         return false;
95     }
96 
97     for (const auto id : all_method_ids_) {
98         const panda_file::File::EntityId method_id = panda_file::File::EntityId(id);
99         panda_file::MethodDataAccessor method_accessor {*file_, method_id};
100         if (!method_accessor.GetCodeId().has_value()) {
101             continue;
102         }
103         panda_file::CodeDataAccessor code_data(*file_, method_accessor.GetCodeId().value());
104         const uint32_t reg_nums = code_data.GetNumVregs();
105         const uint32_t arg_nums = code_data.GetNumArgs();
106         const uint32_t max_reg_idx = reg_nums + arg_nums;
107         auto bc_ins = BytecodeInstruction(code_data.GetInstructions());
108         const auto bc_ins_last = bc_ins.JumpTo(code_data.GetCodeSize());
109         ASSERT(arg_nums >= DEFAULT_ARGUMENT_NUMBER);
110         while (bc_ins.GetAddress() < bc_ins_last.GetAddress()) {
111             const size_t count = GetVRegCount(bc_ins);
112             if (count == 0) { // Skip instructions that do not use registers
113                 bc_ins = bc_ins.GetNext();
114                 continue;
115             }
116             if (!CheckVRegIdx(bc_ins, count, max_reg_idx)) {
117                 return false;
118             }
119             bc_ins = bc_ins.GetNext();
120         }
121     }
122     return true;
123 }
124 
VerifyConstantPoolIndex()125 bool Verifier::VerifyConstantPoolIndex()
126 {
127     if (file_ == nullptr) {
128         return false;
129     }
130 
131     if (!CheckConstantPoolIndex()) {
132         return false;
133     }
134 
135     return true;
136 }
137 
VerifyConstantPoolContent()138 bool Verifier::VerifyConstantPoolContent()
139 {
140     if (file_ == nullptr) {
141         return false;
142     }
143 
144     if (!CheckConstantPool(verifier::ActionType::CHECKCONSTPOOLCONTENT)) {
145         return false;
146     }
147 
148     if (!VerifyLiteralArrays()) {
149         return false;
150     }
151 
152     return true;
153 }
154 
GetConstantPoolIds()155 void Verifier::GetConstantPoolIds()
156 {
157     if (constant_pool_ids_.size() != 0) {
158         return;
159     }
160     auto index_headers = file_->GetIndexHeaders();
161     for (const auto &index_header : index_headers) {
162         auto region_indexs = file_->GetMethodIndex(&index_header);
163         for (auto &index : region_indexs) {
164             constant_pool_ids_.push_back(index.GetOffset());
165         }
166     }
167 }
168 
GetLiteralIds()169 void Verifier::GetLiteralIds()
170 {
171     if (literal_ids_.size() != 0) {
172         return;
173     }
174     const auto literal_arrays = file_->GetLiteralArrays();
175     for (const auto literal_id : literal_arrays) {
176         literal_ids_.push_back(literal_id);
177     }
178 }
179 
CheckConstantPoolActions(const verifier::ActionType type,panda_file::File::EntityId method_id)180 bool Verifier::CheckConstantPoolActions(const verifier::ActionType type, panda_file::File::EntityId method_id)
181 {
182     switch (type) {
183         case verifier::ActionType::CHECKCONSTPOOLCONTENT: {
184             return CheckConstantPoolMethodContent(method_id);
185         }
186         case verifier::ActionType::COLLECTINFOS: {
187             all_method_ids_.push_back(method_id.GetOffset());
188             return CollectIdInInstructions(method_id);
189         }
190         default: {
191             return true;
192         }
193     }
194 }
195 
CollectIdInInstructions(const panda_file::File::EntityId & method_id)196 bool Verifier::CollectIdInInstructions(const panda_file::File::EntityId &method_id)
197 {
198     panda_file::MethodDataAccessor method_accessor(*file_, method_id);
199     ASSERT(method_accessor.GetCodeId().has_value());
200     panda_file::CodeDataAccessor code_accessor(*file_, method_accessor.GetCodeId().value());
201     const auto ins_size = code_accessor.GetCodeSize();
202     const auto ins_arr = code_accessor.GetInstructions();
203 
204     auto bc_ins = BytecodeInstruction(ins_arr);
205     const auto bc_ins_last = bc_ins.JumpTo(ins_size);
206 
207     while (bc_ins.GetAddress() < bc_ins_last.GetAddress()) {
208         if (!bc_ins.IsPrimaryOpcodeValid()) {
209             LOG(ERROR, VERIFIER) << "Fail to verify primary opcode!";
210             return false;
211         }
212         if (bc_ins.HasFlag(BytecodeInstruction::Flags::LITERALARRAY_ID)) {
213             // the idx of any instruction with a literal id is 0 except defineclasswithbuffer
214             size_t idx = 0;
215             if (bc_ins.GetOpcode() == BytecodeInstruction::Opcode::DEFINECLASSWITHBUFFER_IMM8_ID16_ID16_IMM16_V8 ||
216                 bc_ins.GetOpcode() == BytecodeInstruction::Opcode::DEFINECLASSWITHBUFFER_IMM16_ID16_ID16_IMM16_V8) {
217                 idx = 1;
218             }
219             const auto arg_literal_idx = bc_ins.GetId(idx).AsIndex();
220             const auto literal_id = file_->ResolveMethodIndex(method_id, arg_literal_idx);
221             ins_literal_ids_.insert(literal_id.GetOffset());
222         }
223         if (bc_ins.HasFlag(BytecodeInstruction::Flags::METHOD_ID)) {
224             const auto arg_method_idx = bc_ins.GetId().AsIndex();
225             const auto arg_method_id = file_->ResolveMethodIndex(method_id, arg_method_idx);
226             ins_method_ids_.insert(arg_method_id.GetOffset());
227         }
228         if (bc_ins.HasFlag(BytecodeInstruction::Flags::STRING_ID)) {
229             const auto arg_string_idx = bc_ins.GetId().AsIndex();
230             const auto string_id = file_->ResolveOffsetByIndex(method_id, arg_string_idx);
231             ins_string_ids_.insert(string_id.GetOffset());
232         }
233         bc_ins = bc_ins.GetNext();
234     }
235     return true;
236 }
237 
CollectModuleLiteralId(const panda_file::File::EntityId & field_id)238 void Verifier::CollectModuleLiteralId(const panda_file::File::EntityId &field_id)
239 {
240     panda_file::FieldDataAccessor field_accessor(*file_, field_id);
241     const auto literal_id = field_accessor.GetValue<uint32_t>().value();
242     if (std::find(literal_ids_.begin(), literal_ids_.end(), literal_id) != literal_ids_.end()) {
243         module_literals_.insert(literal_id);
244     }
245 }
246 
CheckConstantPool(const verifier::ActionType type)247 bool Verifier::CheckConstantPool(const verifier::ActionType type)
248 {
249     const auto class_idx = file_->GetClasses();
250     for (size_t i = 0; i < class_idx.size(); i++) {
251         uint32_t class_id = class_idx[i];
252         if (class_id > file_->GetHeader()->file_size) {
253             LOG(ERROR, VERIFIER) << "Binary file corrupted. out of bounds (0x" << std::hex
254                                  << file_->GetHeader()->file_size;
255             return false;
256         }
257         const panda_file::File::EntityId record_id {class_id};
258         if (!file_->IsExternal(record_id)) {
259             panda_file::ClassDataAccessor class_accessor {*file_, record_id};
260             bool check_res = true;
261             class_accessor.EnumerateMethods([&](panda_file::MethodDataAccessor &method_accessor) -> void {
262                 check_res = check_res && CheckConstantPoolActions(type, method_accessor.GetMethodId());
263             });
264             if (!check_res) {
265                 return false;
266             }
267             if (type == verifier::ActionType::COLLECTINFOS) {
268                 class_accessor.EnumerateFields([&](panda_file::FieldDataAccessor &field_accessor) -> void {
269                     CollectModuleLiteralId(field_accessor.GetFieldId());
270                 });
271             }
272         }
273     }
274 
275     return true;
276 }
277 
GetVRegCount(const BytecodeInstruction & bc_ins)278 size_t Verifier::GetVRegCount(const BytecodeInstruction &bc_ins)
279 {
280     size_t idx = 0; // Represents the idxTH register index in an instruction
281     BytecodeInstruction::Format format = bc_ins.GetFormat();
282     while (bc_ins.HasVReg(format, idx)) {
283         idx++;
284     }
285     return idx;
286 }
287 
CheckVRegIdx(const BytecodeInstruction & bc_ins,const size_t count,const uint32_t max_reg_idx)288 bool Verifier::CheckVRegIdx(const BytecodeInstruction &bc_ins, const size_t count, const uint32_t max_reg_idx)
289 {
290     for (size_t idx = 0; idx < count; idx++) { // Represents the idxTH register index in an instruction
291         uint16_t reg_idx = bc_ins.GetVReg(idx);
292         if (reg_idx >= max_reg_idx) {
293             LOG(ERROR, VERIFIER) << "register index out of bounds. register index is (0x" << std::hex
294                                  << reg_idx << ")" << std::endl;
295             return false;
296         }
297     }
298     return true;
299 }
300 
VerifyMethodId(const uint32_t & method_id) const301 bool Verifier::VerifyMethodId(const uint32_t &method_id) const
302 {
303     auto iter = std::find(constant_pool_ids_.begin(), constant_pool_ids_.end(), method_id);
304     if (iter == constant_pool_ids_.end() ||
305         (std::find(literal_ids_.begin(), literal_ids_.end(), method_id) != literal_ids_.end()) ||
306         ins_string_ids_.count(method_id)) {
307         LOG(ERROR, VERIFIER) << "Fail to verify method id. method_id(0x" << std::hex << method_id << ")!";
308         return false;
309     }
310     return true;
311 }
312 
VerifyLiteralId(const uint32_t & literal_id) const313 bool Verifier::VerifyLiteralId(const uint32_t &literal_id) const
314 {
315     auto iter = std::find(literal_ids_.begin(), literal_ids_.end(), literal_id);
316     if (iter == literal_ids_.end()) {
317         LOG(ERROR, VERIFIER) << "Fail to verify literal id. literal_id(0x" << std::hex << literal_id << ")!";
318         return false;
319     }
320     return true;
321 }
322 
VerifyStringId(const uint32_t & string_id) const323 bool Verifier::VerifyStringId(const uint32_t &string_id) const
324 {
325     auto iter = std::find(constant_pool_ids_.begin(), constant_pool_ids_.end(), string_id);
326     if (iter == constant_pool_ids_.end() ||
327         ins_method_ids_.count(string_id) ||
328         (std::find(literal_ids_.begin(), literal_ids_.end(), string_id) != literal_ids_.end())) {
329         LOG(ERROR, VERIFIER) << "Fail to verify string id. string_id(0x" << std::hex << string_id << ")!";
330         return false;
331     }
332     return true;
333 }
334 
GetFirstImmFromInstruction(const BytecodeInstruction & bc_ins)335 std::optional<int64_t> Verifier::GetFirstImmFromInstruction(const BytecodeInstruction &bc_ins)
336 {
337     std::optional<int64_t> first_imm = std::optional<int64_t> {};
338     size_t index = 0;
339     const auto format = bc_ins.GetFormat();
340     if (bc_ins.HasImm(format, index)) {
341         first_imm = bc_ins.GetImm64(index);
342     }
343 
344     return first_imm;
345 }
346 
GetSlotNumberFromAnnotation(panda_file::MethodDataAccessor & method_accessor)347 std::optional<uint64_t> Verifier::GetSlotNumberFromAnnotation(panda_file::MethodDataAccessor &method_accessor)
348 {
349     std::optional<uint64_t> slot_number {};
350     method_accessor.EnumerateAnnotations([&](panda_file::File::EntityId annotation_id) {
351         panda_file::AnnotationDataAccessor ada(*file_, annotation_id);
352         auto *annotation_name = reinterpret_cast<const char *>(file_->GetStringData(ada.GetClassId()).data);
353         if (::strcmp("L_ESSlotNumberAnnotation;", annotation_name) == 0) {
354             uint32_t elem_count = ada.GetCount();
355             for (uint32_t i = 0; i < elem_count; i++) {
356                 panda_file::AnnotationDataAccessor::Elem adae = ada.GetElement(i);
357                 auto *elem_name = reinterpret_cast<const char *>(file_->GetStringData(adae.GetNameId()).data);
358                 if (::strcmp("SlotNumber", elem_name) == 0) {
359                     slot_number = adae.GetScalarValue().GetValue();
360                 }
361             }
362         }
363     });
364     return slot_number;
365 }
366 
VerifyMethodIdInLiteralArray(const uint32_t & id)367 bool Verifier::VerifyMethodIdInLiteralArray(const uint32_t &id)
368 {
369     const auto method_id = panda_file::File::EntityId(id).GetOffset();
370     auto iter = std::find(all_method_ids_.begin(), all_method_ids_.end(), method_id);
371     if (iter == all_method_ids_.end()) {
372         LOG(ERROR, VERIFIER) << "Invalid method id(0x" << id << ") in literal array";
373         return false;
374     }
375     return true;
376 }
377 
VerifyStringIdInLiteralArray(const uint32_t & id)378 bool Verifier::VerifyStringIdInLiteralArray(const uint32_t &id)
379 {
380     auto string_data = file_->GetStringData(panda_file::File::EntityId(id));
381     if (string_data.data == nullptr) {
382         LOG(ERROR, VERIFIER) << "Invalid string_id. string_id(0x" << std::hex << id << ")!";
383         return false;
384     }
385     auto desc = std::string(utf::Mutf8AsCString(string_data.data));
386     std::wstring_convert<std::codecvt_utf8_utf16<wchar_t>> converter;
387     std::wstring utf16_desc = converter.from_bytes(desc);
388     if (string_data.utf16_length != utf16_desc.length()) {
389         LOG(ERROR, VERIFIER) << "Invalid string value(0x" << id << ") in literal array";
390         return false;
391     }
392     return true;
393 }
394 
VerifyLiteralIdInLiteralArray(const uint32_t & id)395 bool Verifier::VerifyLiteralIdInLiteralArray(const uint32_t &id)
396 {
397     auto iter = std::find(literal_ids_.begin(), literal_ids_.end(), id);
398     if (iter == literal_ids_.end()) {
399         LOG(ERROR, VERIFIER) << "Invalid literal id(0x" << id << ") in literal array";
400         return false;
401     }
402     return true;
403 }
404 
VerifySingleLiteralArray(const panda_file::File::EntityId & literal_id)405 bool Verifier::VerifySingleLiteralArray(const panda_file::File::EntityId &literal_id)
406 {
407     auto sp = file_->GetSpanFromId(literal_id);
408     const auto literal_vals_num = panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
409     for (size_t i = 0; i < literal_vals_num; i += 2U) { // 2u skip literal item
410         const auto tag = static_cast<panda_file::LiteralTag>(panda_file::helpers::Read<panda_file::TAG_SIZE>(&sp));
411         switch (tag) {
412             case panda_file::LiteralTag::TAGVALUE:
413             case panda_file::LiteralTag::BOOL:
414             case panda_file::LiteralTag::ACCESSOR:
415             case panda_file::LiteralTag::NULLVALUE:
416             case panda_file::LiteralTag::BUILTINTYPEINDEX: {
417                 sp = sp.SubSpan(sizeof(uint8_t)); // run next sp
418                 break;
419             }
420             case panda_file::LiteralTag::METHODAFFILIATE: {
421                 sp = sp.SubSpan(sizeof(uint16_t));
422                 break;
423             }
424             case panda_file::LiteralTag::INTEGER:
425             case panda_file::LiteralTag::FLOAT:
426             case panda_file::LiteralTag::GETTER:
427             case panda_file::LiteralTag::SETTER:
428             case panda_file::LiteralTag::GENERATORMETHOD:
429             case panda_file::LiteralTag::LITERALBUFFERINDEX:
430             case panda_file::LiteralTag::ASYNCGENERATORMETHOD: {
431                 sp = sp.SubSpan(sizeof(uint32_t));
432                 break;
433             }
434             case panda_file::LiteralTag::DOUBLE: {
435                 sp = sp.SubSpan(sizeof(uint64_t));
436                 break;
437             }
438             case panda_file::LiteralTag::ARRAY_U1:
439             case panda_file::LiteralTag::ARRAY_U8:
440             case panda_file::LiteralTag::ARRAY_I8:
441             case panda_file::LiteralTag::ARRAY_U16:
442             case panda_file::LiteralTag::ARRAY_I16:
443             case panda_file::LiteralTag::ARRAY_U32:
444             case panda_file::LiteralTag::ARRAY_I32:
445             case panda_file::LiteralTag::ARRAY_U64:
446             case panda_file::LiteralTag::ARRAY_I64:
447             case panda_file::LiteralTag::ARRAY_F32:
448             case panda_file::LiteralTag::ARRAY_F64:
449             case panda_file::LiteralTag::ARRAY_STRING: {
450                 i = literal_vals_num;
451                 break;
452             }
453             case panda_file::LiteralTag::STRING: {
454                 panda_file::helpers::Read<sizeof(uint32_t)>(&sp);
455                 break;
456             }
457             case panda_file::LiteralTag::METHOD: {
458                 const auto value = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&sp));
459                 inner_method_map_.emplace(literal_id.GetOffset(), value);
460                 if (!VerifyMethodIdInLiteralArray(value)) {
461                     return false;
462                 }
463                 break;
464             }
465             case panda_file::LiteralTag::LITERALARRAY: {
466                 const auto value = static_cast<uint32_t>(panda_file::helpers::Read<sizeof(uint32_t)>(&sp));
467                 inner_literal_map_.emplace(literal_id.GetOffset(), value);
468                 if (!VerifyLiteralIdInLiteralArray(value)) {
469                     return false;
470                 }
471                 break;
472             }
473             default: {
474                 LOG(ERROR, VERIFIER) << "Invalid literal tag";
475                 return false;
476             }
477         }
478     }
479     return true;
480 }
481 
IsModuleLiteralId(const panda_file::File::EntityId & id) const482 bool Verifier::IsModuleLiteralId(const panda_file::File::EntityId &id) const
483 {
484     return module_literals_.find(id.GetOffset()) != module_literals_.end();
485 }
486 
VerifyLiteralArrays()487 bool Verifier::VerifyLiteralArrays()
488 {
489     for (const auto &arg_literal_id : literal_ids_) {
490         const auto literal_id = panda_file::File::EntityId(arg_literal_id);
491         if (!IsModuleLiteralId(literal_id) && !VerifySingleLiteralArray(literal_id)) {
492             return false;
493         }
494     }
495     return true;
496 }
497 
IsJumpInstruction(const Opcode & ins_opcode)498 bool Verifier::IsJumpInstruction(const Opcode &ins_opcode)
499 {
500     bool valid = true;
501 
502     switch (ins_opcode) {
503         case Opcode::JMP_IMM8:
504         case Opcode::JMP_IMM16:
505         case Opcode::JEQZ_IMM8:
506         case Opcode::JEQZ_IMM16:
507         case Opcode::JNEZ_IMM8:
508         case Opcode::JSTRICTEQZ_IMM8:
509         case Opcode::JNSTRICTEQZ_IMM8:
510         case Opcode::JEQNULL_IMM8:
511         case Opcode::JNENULL_IMM8:
512         case Opcode::JSTRICTEQNULL_IMM8:
513         case Opcode::JNSTRICTEQNULL_IMM8:
514         case Opcode::JEQUNDEFINED_IMM8:
515         case Opcode::JNEUNDEFINED_IMM8:
516         case Opcode::JSTRICTEQUNDEFINED_IMM8:
517         case Opcode::JNSTRICTEQUNDEFINED_IMM8:
518         case Opcode::JEQ_V8_IMM8:
519         case Opcode::JNE_V8_IMM8:
520         case Opcode::JSTRICTEQ_V8_IMM8:
521         case Opcode::JNSTRICTEQ_V8_IMM8:
522         case Opcode::JMP_IMM32:
523         case Opcode::JEQZ_IMM32:
524         case Opcode::JNEZ_IMM16:
525         case Opcode::JNEZ_IMM32:
526         case Opcode::JSTRICTEQZ_IMM16:
527         case Opcode::JNSTRICTEQZ_IMM16:
528         case Opcode::JEQNULL_IMM16:
529         case Opcode::JNENULL_IMM16:
530         case Opcode::JSTRICTEQNULL_IMM16:
531         case Opcode::JNSTRICTEQNULL_IMM16:
532         case Opcode::JEQUNDEFINED_IMM16:
533         case Opcode::JNEUNDEFINED_IMM16:
534         case Opcode::JSTRICTEQUNDEFINED_IMM16:
535         case Opcode::JEQ_V8_IMM16:
536         case Opcode::JNE_V8_IMM16:
537         case Opcode::JSTRICTEQ_V8_IMM16:
538         case Opcode::JNSTRICTEQ_V8_IMM16: {
539             valid = true;
540             break;
541         }
542         default: {
543             valid = false;
544             break;
545         }
546     }
547     return valid;
548 }
549 
VerifyJumpInstruction(const BytecodeInstruction & bc_ins,const BytecodeInstruction & bc_ins_last,const BytecodeInstruction & bc_ins_first)550 bool Verifier::VerifyJumpInstruction(const BytecodeInstruction &bc_ins, const BytecodeInstruction &bc_ins_last,
551                                      const BytecodeInstruction &bc_ins_first)
552 {
553     // update maximum forward offset
554     const auto bc_ins_forward_size = bc_ins_last.GetAddress() - bc_ins.GetAddress();
555     // update maximum backward offset
556     const auto bc_ins_backward_size = bc_ins.GetAddress() - bc_ins_first.GetAddress();
557     if (!bc_ins.IsPrimaryOpcodeValid()) {
558         LOG(ERROR, VERIFIER) << "Fail to verify primary opcode!";
559         return false;
560     }
561 
562     Opcode ins_opcode = bc_ins.GetOpcode();
563     if (IsJumpInstruction(ins_opcode)) {
564         std::optional<int64_t> immdata = GetFirstImmFromInstruction(bc_ins);
565         if (!immdata.has_value()) {
566             LOG(ERROR, VERIFIER) << "Fail to get immediate data!";
567             return false;
568         }
569         if ((immdata.value() > 0) && (immdata.value() >= bc_ins_forward_size)) {
570             LOG(ERROR, VERIFIER) << "Jump forward out of boundary";
571             return false;
572         }
573         if ((immdata.value() < 0) && (bc_ins_backward_size + immdata.value() < 0)) {
574             LOG(ERROR, VERIFIER) << "Jump backward out of boundary";
575             return false;
576         }
577     }
578     return true;
579 }
580 
GetIcSlotFromInstruction(const BytecodeInstruction & bc_ins,uint32_t & first_slot_index,bool & has_slot,bool & is_two_slot)581 bool Verifier::GetIcSlotFromInstruction(const BytecodeInstruction &bc_ins, uint32_t &first_slot_index,
582                                         bool &has_slot, bool &is_two_slot)
583 {
584     std::optional<uint64_t> first_imm = {};
585     if (bc_ins.HasFlag(BytecodeInstruction::Flags::ONE_SLOT)) {
586         first_imm = GetFirstImmFromInstruction(bc_ins);
587         if (!first_imm.has_value()) {
588             LOG(ERROR, VERIFIER) << "Fail to get first immediate data!";
589             return false;
590         }
591         first_slot_index = first_imm.value();
592         is_two_slot = false;
593         has_slot = true;
594     } else if (bc_ins.HasFlag(BytecodeInstruction::Flags::TWO_SLOT)) {
595         first_imm = GetFirstImmFromInstruction(bc_ins);
596         if (!first_imm.has_value()) {
597             LOG(ERROR, VERIFIER) << "Fail to get first immediate data!";
598             return false;
599         }
600         first_slot_index = first_imm.value();
601         has_slot = true;
602         is_two_slot = true;
603     }
604 
605     return true;
606 }
607 
VerifySlotNumber(panda_file::MethodDataAccessor & method_accessor,const uint32_t & slot_number,const panda_file::File::EntityId & method_id)608 bool Verifier::VerifySlotNumber(panda_file::MethodDataAccessor &method_accessor, const uint32_t &slot_number,
609                                 const panda_file::File::EntityId &method_id)
610 {
611     const auto ann_slot_number = GetSlotNumberFromAnnotation(method_accessor);
612     if (!ann_slot_number.has_value()) {
613         LOG(INFO, VERIFIER) << "There is no slot number information in annotaion.";
614         // To be compatible with old abc, slot number verification is not continued
615         return true;
616     }
617     if (slot_number == ann_slot_number.value()) {
618         return true;
619     }
620 
621     LOG(ERROR, VERIFIER) << "Slot number has been falsified in method 0x" << method_id;
622     return false;
623 }
624 
CheckConstantPoolMethodContent(const panda_file::File::EntityId & method_id)625 bool Verifier::CheckConstantPoolMethodContent(const panda_file::File::EntityId &method_id)
626 {
627     panda_file::MethodDataAccessor method_accessor(*file_, method_id);
628     ASSERT(method_accessor.GetCodeId().has_value());
629     panda_file::CodeDataAccessor code_accessor(*file_, method_accessor.GetCodeId().value());
630     const auto ins_size = code_accessor.GetCodeSize();
631     const auto ins_arr = code_accessor.GetInstructions();
632     auto bc_ins = BytecodeInstruction(ins_arr);
633     const auto bc_ins_last = bc_ins.JumpTo(ins_size);
634     const auto bc_ins_init = bc_ins; // initial PC value
635     uint32_t ins_slot_num = 0;
636     bool has_slot = false;
637     bool is_two_slot = false;
638 
639     while (bc_ins.GetAddress() < bc_ins_last.GetAddress()) {
640         if (!VerifyJumpInstruction(bc_ins, bc_ins_last, bc_ins_init)) {
641             LOG(ERROR, VERIFIER) << "Invalid target position of jump instruction";
642             return false;
643         }
644         if (!GetIcSlotFromInstruction(bc_ins, ins_slot_num, has_slot, is_two_slot)) {
645             LOG(ERROR, VERIFIER) << "Fail to get first slot index!";
646             return false;
647         }
648         bc_ins = bc_ins.GetNext();
649     }
650 
651     if (has_slot) {
652         if (is_two_slot) {
653             ins_slot_num += 1; // when there are two slots for the last instruction, the slot index increases
654         }
655         ins_slot_num += 1; // slot index starts with zero
656     }
657 
658     return true;
659 }
660 
CheckConstantPoolIndex() const661 bool Verifier::CheckConstantPoolIndex() const
662 {
663     for (auto &id : ins_method_ids_) {
664         if (!VerifyMethodId(id)) {
665             return false;
666         }
667     }
668 
669     for (auto &id : ins_literal_ids_) {
670         if (!VerifyLiteralId(id)) {
671             return false;
672         }
673     }
674 
675     for (auto &id : ins_string_ids_) {
676         if (!VerifyStringId(id)) {
677             return false;
678         }
679     }
680 
681     return true;
682 }
683 } // namespace panda::verifier
684