1 /* 2 * Copyright (c) 2021 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 PANDA_VERIFICATION_CFLOW_JUMPS_MAP_H_ 17 #define PANDA_VERIFICATION_CFLOW_JUMPS_MAP_H_ 18 19 #include "instructions_map.h" 20 21 #include "util/index.h" 22 #include "util/addr_map.h" 23 #include "util/lazy.h" 24 25 #include "runtime/include/mem/panda_containers.h" 26 27 #include <cstdint> 28 29 namespace panda::verifier { 30 class JumpsMap { 31 public: 32 struct FromTo { 33 const void *From; 34 const void *To; 35 }; 36 PutJump(const void * pc_jump_ptr,const void * pc_target_ptr)37 bool PutJump(const void *pc_jump_ptr, const void *pc_target_ptr) 38 { 39 if (!AddrMap_.IsInAddressSpace(pc_jump_ptr) || !AddrMap_.IsInAddressSpace(pc_target_ptr)) { 40 return false; 41 } 42 bool target_already_marked = AddrMap_.HasMark(pc_target_ptr); 43 if (!AddrMap_.Mark(pc_target_ptr)) { 44 return false; 45 } 46 FromTo_.push_back({pc_jump_ptr, pc_target_ptr}); 47 if (!target_already_marked) { 48 Target_.push_back(pc_target_ptr); 49 } 50 return true; 51 } 52 JumpsMap(const void * pc_start_ptr,const void * pc_end_ptr)53 JumpsMap(const void *pc_start_ptr, const void *pc_end_ptr) : AddrMap_(pc_start_ptr, pc_end_ptr) {} JumpsMap(const void * pc_start_ptr,size_t size)54 JumpsMap(const void *pc_start_ptr, size_t size) 55 : JumpsMap(pc_start_ptr, reinterpret_cast<const void *>(reinterpret_cast<uintptr_t>(pc_start_ptr) + size - 1)) 56 { 57 } 58 JumpsMap() = delete; 59 ~JumpsMap() = default; 60 61 template <typename PtrType, typename Callback> EnumerateAllTargets(Callback cb)62 void EnumerateAllTargets(Callback cb) const 63 { 64 for (const auto &tgt : Target_) { 65 if (!cb(reinterpret_cast<PtrType>(tgt))) { 66 return; 67 } 68 } 69 } 70 71 template <typename PtrType> AllTargetsLazy()72 auto AllTargetsLazy() const 73 { 74 return Transform(ConstLazyFetch(Target_), 75 [](const void *ptr) -> PtrType { return reinterpret_cast<PtrType>(const_cast<void *>(ptr)); }); 76 } 77 78 template <typename PtrType, typename Callback> EnumerateAllJumpsToTarget(PtrType pc_target_ptr,Callback cb)79 void EnumerateAllJumpsToTarget(PtrType pc_target_ptr, Callback cb) const 80 { 81 // it is slow, but this operation is assumed to be very rare, only on 82 // cflow verification failures, so we here trade speed of this function 83 // for much faster positive path checks 84 for (const auto &from_to : FromTo_) { 85 if (from_to.To == reinterpret_cast<const void *>(pc_target_ptr)) { 86 if (!cb(reinterpret_cast<PtrType>(from_to.From))) { 87 return; 88 } 89 } 90 } 91 } IsConflictingWith(const InstructionsMap & inst_map)92 bool IsConflictingWith(const InstructionsMap &inst_map) const 93 { 94 return AddrMap_.HasCommonMarks(inst_map.AddrMap_); 95 } 96 template <typename PtrType> GetFirstConflictingJump(const InstructionsMap & inst_map,PtrType * pc_jump_ptr,PtrType * pc_target_ptr)97 bool GetFirstConflictingJump(const InstructionsMap &inst_map, PtrType *pc_jump_ptr, PtrType *pc_target_ptr) const 98 { 99 if (!AddrMap_.GetFirstCommonMark(inst_map.AddrMap_, pc_target_ptr)) { 100 return false; 101 } 102 *pc_jump_ptr = nullptr; 103 EnumerateAllJumpsToTarget<PtrType>(*pc_target_ptr, [&pc_jump_ptr](PtrType jmp_ptr) { 104 *pc_jump_ptr = jmp_ptr; 105 return false; 106 }); 107 ASSERT(*pc_jump_ptr != nullptr); 108 return true; 109 } 110 111 private: 112 AddrMap AddrMap_; 113 PandaVector<const void *> Target_; 114 PandaVector<FromTo> FromTo_; 115 }; 116 } // namespace panda::verifier 117 118 #endif // PANDA_VERIFICATION_CFLOW_JUMPS_MAP_H_ 119