├── llvm ├── .gitignore └── build-llvm.sh ├── analyzer ├── .gitignore ├── src │ ├── lib │ │ ├── CallGraph.h │ │ ├── PointerAnalysis.h │ │ ├── CMakeLists.txt │ │ ├── LRSan.h │ │ ├── Common.h │ │ ├── LRSan.cc │ │ ├── PointerAnalysis.cc │ │ ├── CallGraph.cc │ │ ├── CriticalVar.h │ │ └── CriticalVar.cc │ └── CMakeLists.txt └── Makefile ├── encoded-errno └── include │ ├── linux │ └── errno.h │ └── uapi │ └── asm-generic │ ├── errno-base.h │ └── errno.h └── README.md /llvm/.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | -------------------------------------------------------------------------------- /analyzer/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | TAGS 3 | tags 4 | log* 5 | -------------------------------------------------------------------------------- /llvm/build-llvm.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # binary choices 4 | BASE="http://releases.llvm.org" 5 | VERN="7.0.0" 6 | 7 | # platform specifics 8 | case "$OSTYPE" in 9 | linux*) 10 | DIST="x86_64-linux-gnu-ubuntu-16.04" 11 | ;; 12 | darwin*) 13 | DIST="x86_64-apple-darwin" 14 | ;; 15 | bsd*) 16 | DIST="amd64-unknown-freebsd10" 17 | ;; 18 | *) 19 | echo "Unknown OS ($OSTYPE)"; exit 20 | ;; 21 | esac 22 | 23 | # download pre-built package 24 | PKGN=clang+llvm-$VERN-$DIST 25 | TARF=$PKGN.tar.xz 26 | 27 | LINK=$BASE/$VERN/$TARF 28 | wget $LINK 29 | 30 | # extract to location 31 | tar xvf $TARF 32 | mv $PKGN build 33 | 34 | # remove file 35 | rm $TARF 36 | -------------------------------------------------------------------------------- /analyzer/src/lib/CallGraph.h: -------------------------------------------------------------------------------- 1 | #ifndef _CALL_GRAPH_H 2 | #define _CALL_GRAPH_H 3 | 4 | #include "LRSan.h" 5 | 6 | class CallGraphPass : public IterativeModulePass { 7 | 8 | private: 9 | const DataLayout *DL; 10 | // char * or void * 11 | Type *Int8PtrTy; 12 | // long interger type 13 | Type *IntPtrTy; 14 | 15 | // Use type-based analysis to find targets of indirect calls 16 | void findCalleesByType(llvm::CallInst*, FuncSet&); 17 | 18 | public: 19 | CallGraphPass(GlobalContext *Ctx_) 20 | : IterativeModulePass(Ctx_, "CallGraph") { } 21 | virtual bool doInitialization(llvm::Module *); 22 | virtual bool doFinalization(llvm::Module *); 23 | virtual bool doModulePass(llvm::Module *); 24 | }; 25 | 26 | #endif 27 | -------------------------------------------------------------------------------- /analyzer/src/lib/PointerAnalysis.h: -------------------------------------------------------------------------------- 1 | #ifndef _POINTER_ANALYSIS_H 2 | #define _POINTER_ANALYSIS_H 3 | 4 | #include "LRSan.h" 5 | 6 | class PointerAnalysisPass : public IterativeModulePass { 7 | typedef std::pair AddrMemPair; 8 | 9 | private: 10 | TargetLibraryInfo *TLI; 11 | 12 | void detectAliasPointers(Function *, AAResults &, 13 | PointerAnalysisMap &); 14 | 15 | public: 16 | PointerAnalysisPass(GlobalContext *Ctx_) 17 | : IterativeModulePass(Ctx_, "PointerAnalysis") { } 18 | virtual bool doInitialization(llvm::Module *); 19 | virtual bool doFinalization(llvm::Module *); 20 | virtual bool doModulePass(llvm::Module *); 21 | }; 22 | 23 | #endif 24 | -------------------------------------------------------------------------------- /analyzer/Makefile: -------------------------------------------------------------------------------- 1 | CUR_DIR = $(shell pwd) 2 | LLVM_BUILD := ${CUR_DIR}/../llvm/build 3 | SRC_DIR := ${CURDIR}/src 4 | SRC_BUILD := ${CURDIR}/build 5 | 6 | NPROC := ${shell nproc} 7 | 8 | build_src_func = \ 9 | (mkdir -p ${2} \ 10 | && cd ${2} \ 11 | && PATH=${LLVM_BUILD}/bin:${PATH} \ 12 | LLVM_ROOT_DIR=${LLVM_BUILD}/bin \ 13 | LLVM_LIBRARY_DIRS=${LLVM_BUILD}/lib \ 14 | LLVM_INCLUDE_DIRS=${LLVM_BUILD}/include \ 15 | CC=clang CXX=clang++ \ 16 | cmake ${1} \ 17 | -DCMAKE_BUILD_TYPE=Release \ 18 | -DCMAKE_CXX_FLAGS_RELEASE="-std=c++11 -fno-rtti -fpic -g" \ 19 | && make -j${NPROC}) 20 | 21 | all: lrsan 22 | 23 | lrsan: 24 | echo ${LLVM_BUILD} 25 | $(call build_src_func, ${SRC_DIR}, ${SRC_BUILD}) 26 | 27 | clean: 28 | rm -rf ${SRC_BUILD} 29 | -------------------------------------------------------------------------------- /analyzer/src/lib/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | set (LRSanSourceCodes 2 | Common.h 3 | LRSan.h 4 | LRSan.cc 5 | CallGraph.h 6 | CallGraph.cc 7 | CriticalVar.h 8 | CriticalVar.cc 9 | PointerAnalysis.h 10 | PointerAnalysis.cc 11 | ) 12 | 13 | # Build libraries. 14 | add_library (LRSanObj OBJECT ${LRSanSourceCodes}) 15 | add_library (LRSan SHARED $) 16 | add_library (LRSanStatic STATIC $) 17 | 18 | # Build executable lrsan. 19 | set (EXECUTABLE_OUTPUT_PATH ${UNISAN_BINARY_DIR}) 20 | link_directories (${UNISAN_BINARY_DIR}/lib) 21 | add_executable(lrsan ${LRSanSourceCodes}) 22 | target_link_libraries(lrsan 23 | LLVMAsmParser 24 | LLVMSupport 25 | LLVMCore 26 | LLVMAnalysis 27 | LLVMIRReader 28 | LRSanStatic 29 | ) 30 | -------------------------------------------------------------------------------- /analyzer/src/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required(VERSION 3.5.1) 2 | project(LRSAN) 3 | 4 | find_package(LLVM REQUIRED CONFIG) 5 | 6 | message(STATUS "Found LLVM ${LLVM_PACKAGE_VERSION}") 7 | message(STATUS "Using LLVMConfig.cmake in: ${LLVM_DIR}") 8 | 9 | # Set your project compile flags. 10 | # E.g. if using the C++ header files 11 | # you will need to enable C++14 support 12 | # for your compiler. 13 | # Check for C++14 support and set the compilation flag 14 | include(CheckCXXCompilerFlag) 15 | #CHECK_CXX_COMPILER_FLAG("-std=c++14" COMPILER_SUPPORTS_CXX14) 16 | # if(COMPILER_SUPPORTS_CXX14) 17 | # set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14 -fno-rtti -fPIC -Wall") 18 | # else() 19 | # message(STATUS "The compiler ${CMAKE_CXX_COMPILER} has no C++14 support. Please use a different C++ compiler.") 20 | # endif() 21 | 22 | include_directories(${LLVM_INCLUDE_DIRS}) 23 | add_definitions(${LLVM_DEFINITIONS}) 24 | 25 | add_subdirectory (lib) 26 | -------------------------------------------------------------------------------- /encoded-errno/include/linux/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef _LINUX_ERRNO_H 2 | #define _LINUX_ERRNO_H 3 | 4 | #include 5 | 6 | 7 | /* 8 | * These should never be seen by user programs. To return one of ERESTART* 9 | * codes, signal_pending() MUST be set. Note that ptrace can observe these 10 | * at syscall exit tracing, but they will never be left for the debugged user 11 | * process to see. 12 | */ 13 | #define ERESTARTSYS errno_encode(512) 14 | #define ERESTARTNOINTR errno_encode(513) 15 | #define ERESTARTNOHAND errno_encode(514) /* restart if no handler.. */ 16 | #define ENOIOCTLCMD errno_encode(515) /* No ioctl command */ 17 | #define ERESTART_RESTARTBLOCK errno_encode(516) /* restart by calling sys_restart_syscall */ 18 | #define EPROBE_DEFER errno_encode(517) /* Driver requests probe retry */ 19 | #define EOPENSTALE errno_encode(518) /* open found a stale dentry */ 20 | 21 | /* Defined for the NFSv3 protocol */ 22 | #define EBADHANDLE errno_encode(521) /* Illegal NFS file handle */ 23 | #define ENOTSYNC errno_encode(522) /* Update synchronization mismatch */ 24 | #define EBADCOOKIE errno_encode(523) /* Cookie is stale */ 25 | #define ENOTSUPP errno_encode(524) /* Operation is not supported */ 26 | #define ETOOSMALL errno_encode(525) /* Buffer or request is too small */ 27 | #define ESERVERFAULT errno_encode(526) /* An untranslatable error occurred */ 28 | #define EBADTYPE errno_encode(527) /* Type not supported by server */ 29 | #define EJUKEBOX errno_encode(528) /* Request initiated, but will not complete before timeout */ 30 | #define EIOCBQUEUED errno_encode(529) /* iocb queued, will get completion event */ 31 | #define ERECALLCONFLICT errno_encode(530) /* conflict with recalled state */ 32 | 33 | #endif 34 | -------------------------------------------------------------------------------- /encoded-errno/include/uapi/asm-generic/errno-base.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_ERRNO_BASE_H 2 | #define _ASM_GENERIC_ERRNO_BASE_H 3 | 4 | /* Reserve 12 bits for real errno */ 5 | #define ERRNO_PREFIX 0x4cedb000 6 | #define errno_encode(x) (ERRNO_PREFIX | (x)) 7 | #define errno_decode(x) ((~ERRNO_PREFIX) & (x)) 8 | 9 | #define EPERM errno_encode(1) /* Operation not permitted */ 10 | #define ENOENT errno_encode(2) /* No such file or directory */ 11 | #define ESRCH errno_encode(3) /* No such process */ 12 | #define EINTR errno_encode(4) /* Interrupted system call */ 13 | #define EIO errno_encode(5) /* I/O error */ 14 | #define ENXIO errno_encode(6) /* No such device or address */ 15 | #define E2BIG errno_encode(7) /* Argument list too long */ 16 | #define ENOEXEC errno_encode(8) /* Exec format error */ 17 | #define EBADF errno_encode(9) /* Bad file number */ 18 | #define ECHILD errno_encode(10) /* No child processes */ 19 | #define EAGAIN errno_encode(11) /* Try again */ 20 | #define ENOMEM errno_encode(12) /* Out of memory */ 21 | #define EACCES errno_encode(13) /* Permission denied */ 22 | #define EFAULT errno_encode(14) /* Bad address */ 23 | #define ENOTBLK errno_encode(15) /* Block device required */ 24 | #define EBUSY errno_encode(16) /* Device or resource busy */ 25 | #define EEXIST errno_encode(17) /* File exists */ 26 | #define EXDEV errno_encode(18) /* Cross-device link */ 27 | #define ENODEV errno_encode(19) /* No such device */ 28 | #define ENOTDIR errno_encode(20) /* Not a directory */ 29 | #define EISDIR errno_encode(21) /* Is a directory */ 30 | #define EINVAL errno_encode(22) /* Invalid argument */ 31 | #define ENFILE errno_encode(23) /* File table overflow */ 32 | #define EMFILE errno_encode(24) /* Too many open files */ 33 | #define ENOTTY errno_encode(25) /* Not a typewriter */ 34 | #define ETXTBSY errno_encode(26) /* Text file busy */ 35 | #define EFBIG errno_encode(27) /* File too large */ 36 | #define ENOSPC errno_encode(28) /* No space left on device */ 37 | #define ESPIPE errno_encode(29) /* Illegal seek */ 38 | #define EROFS errno_encode(30) /* Read-only file system */ 39 | #define EMLINK errno_encode(31) /* Too many links */ 40 | #define EPIPE errno_encode(32) /* Broken pipe */ 41 | #define EDOM errno_encode(33) /* Math argument out of domain of func */ 42 | #define ERANGE errno_encode(34) /* Math result not representable */ 43 | 44 | #endif 45 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LRSan: Detecting Lacking-Recheck Bugs in OS Kernels 2 | 3 | Operating system kernels carry a large number of security checks to 4 | validate security-sensitive variables and operations. 5 | Lacking-recheck bugs (LRC) are cases in which security-checked 6 | variables are further modified, and no recheck is enforced. LRC bugs 7 | invalidate the intended checks and thus may lead to attacks such as 8 | out-of-bound memory access or privilege escalation. LRSan is a 9 | static analysis tool that detects LRC bugs in OS kernels. LRSan first 10 | automatically identifies security checks, critical variables, and 11 | uses of the checked variables, and then reasons about whether a 12 | modification is present after a security check. A case in which a 13 | modification is present but a recheck is lacking is identified as an 14 | LRC bug. 15 | 16 | ## How to use LRSan 17 | (Tested on Ubuntu 16.04 64-bit) 18 | 19 | ### Build LLVM 20 | ```sh 21 | $ cd llvm 22 | $ ./build-llvm.sh 23 | # The installed LLVM is of version 7.0.0 24 | ``` 25 | 26 | ### Build LRSan analyzer 27 | ```sh 28 | # Build the analysis pass of analyzer 29 | $ cd ../analyzer 30 | $ make 31 | # Now, you can find the "lrsan" binary in build/lib/lrsan 32 | ``` 33 | 34 | ### Prepare LLVM bitcode files of OS kernels 35 | 36 | * Replace error-code definition files of the Linux kernel with the ones 37 | in "encoded-errno" 38 | * The code should be compiled with the built LLVM 39 | * Compile the code with options: -O0 or -O2, -g, -fno-inline 40 | * Generate bitcode files 41 | - We have our own tool to generate bitcode files: https://github.com/sslab-gatech/deadline/tree/release/work. Note that files (typically less than 10) with compilation errors are simply discarded 42 | - There are multiple alternative tools such as LLVMLinux 43 | 44 | ### Run lrsan 45 | ```sh 46 | # To analyze a single bitcode file, say "test.bc", run: 47 | $ ./build/lib/lrsan -lrc test.bc 48 | # To analyze a list of bitcode files, put the absolute paths of the bitcode files in a file, say "bc.list", then run: 49 | $ ./lrsan -lrc @bc.list 50 | ``` 51 | 52 | ## More details 53 | * [LRSan paper (ACM CCS'18)](https://www-users.cs.umn.edu/~kjlu/papers/lrsan.pdf) 54 | * Contact: [Wenwen Wang](https://www-users.cs.umn.edu/~wang6495) and [Kangjie Lu](https://www-users.cs.umn.edu/~kjlu) 55 | ```sh 56 | @inproceedings{lrsan-ccs18, 57 | title = {{Check it Again: Detecting Lacking-Recheck Bugs in OS Kernels}}, 58 | author = {Wenwen Wang and Kangjie Lu and Pen-Chung Yew}, 59 | booktitle = {Proceedings of the 25th ACM Conference on Computer and Communications Security (CCS)}, 60 | month = oct, 61 | year = 2018, 62 | address = {Toronto, Canada}, 63 | } 64 | ``` 65 | -------------------------------------------------------------------------------- /analyzer/src/lib/LRSan.h: -------------------------------------------------------------------------------- 1 | #ifndef _LRSAN_GLOBAL_H 2 | #define _LRSAN_GLOBAL_H 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "llvm/Support/CommandLine.h" 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | 23 | #include "Common.h" 24 | 25 | 26 | // 27 | // typedefs 28 | // 29 | typedef std::vector< std::pair > ModuleList; 30 | // Mapping module to its file name. 31 | typedef std::unordered_map ModuleNameMap; 32 | // The set of all functions. 33 | typedef llvm::SmallPtrSet FuncSet; 34 | // Mapping from function name to function. 35 | typedef std::unordered_map NameFuncMap; 36 | typedef llvm::SmallPtrSet CallInstSet; 37 | typedef llvm::DenseMap CallerMap; 38 | typedef llvm::DenseMap CalleeMap; 39 | // Pointer analysis types. 40 | typedef std::map> PointerAnalysisMap; 41 | typedef std::map FuncPointerAnalysisMap; 42 | typedef std::map FuncAAResultsMap; 43 | 44 | struct GlobalContext { 45 | 46 | GlobalContext() { 47 | NumFunctions = 0; 48 | } 49 | 50 | unsigned NumFunctions; 51 | 52 | // Map global function name to function defination. 53 | NameFuncMap Funcs; 54 | 55 | // Functions whose addresses are taken. 56 | FuncSet AddressTakenFuncs; 57 | 58 | // Map a callsite to all potential callee functions. 59 | CalleeMap Callees; 60 | 61 | // Map a function to all potential caller instructions. 62 | CallerMap Callers; 63 | 64 | // Indirect call instructions. 65 | std::vectorIndirectCallInsts; 66 | 67 | // Modules. 68 | ModuleList Modules; 69 | ModuleNameMap ModuleMaps; 70 | std::set InvolvedModules; 71 | 72 | std::map MemWriteFuncs; 73 | std::set CriticalFuncs; 74 | 75 | // Pinter analysis results. 76 | FuncPointerAnalysisMap FuncPAResults; 77 | FuncAAResultsMap FuncAAResults; 78 | }; 79 | 80 | class IterativeModulePass { 81 | protected: 82 | GlobalContext *Ctx; 83 | const char * ID; 84 | public: 85 | IterativeModulePass(GlobalContext *Ctx_, const char *ID_) 86 | : Ctx(Ctx_), ID(ID_) { } 87 | 88 | // Run on each module before iterative pass. 89 | virtual bool doInitialization(llvm::Module *M) 90 | { return true; } 91 | 92 | // Run on each module after iterative pass. 93 | virtual bool doFinalization(llvm::Module *M) 94 | { return true; } 95 | 96 | // Iterative pass. 97 | virtual bool doModulePass(llvm::Module *M) 98 | { return false; } 99 | 100 | virtual void run(ModuleList &modules); 101 | }; 102 | 103 | #endif 104 | -------------------------------------------------------------------------------- /analyzer/src/lib/Common.h: -------------------------------------------------------------------------------- 1 | #ifndef _COMMON_H_ 2 | #define _COMMON_H_ 3 | 4 | #include 5 | #include 6 | #include 7 | #include 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | using namespace llvm; 14 | using namespace std; 15 | 16 | #define LOG(lv, stmt) \ 17 | do { \ 18 | if (VerboseLevel >= lv) \ 19 | errs() << stmt; \ 20 | } while(0) 21 | 22 | 23 | #define OP llvm::errs() 24 | 25 | #define WARN(stmt) LOG(1, "\n[WARN] " << stmt); 26 | 27 | #define ERR(stmt) \ 28 | do { \ 29 | errs() << "ERROR (" << __FUNCTION__ << "@" << __LINE__ << ")"; \ 30 | errs() << ": " << stmt; \ 31 | exit(-1); \ 32 | } while(0) 33 | 34 | /// Different colors for output 35 | #define KNRM "\x1B[0m" /* Normal */ 36 | #define KRED "\x1B[31m" /* Red */ 37 | #define KGRN "\x1B[32m" /* Green */ 38 | #define KYEL "\x1B[33m" /* Yellow */ 39 | #define KBLU "\x1B[34m" /* Blue */ 40 | #define KMAG "\x1B[35m" /* Magenta */ 41 | #define KCYN "\x1B[36m" /* Cyan */ 42 | #define KWHT "\x1B[37m" /* White */ 43 | 44 | extern cl::opt VerboseLevel; 45 | 46 | class ModuleOracle { 47 | public: 48 | ModuleOracle(Module &m) : 49 | dl(m.getDataLayout()), 50 | tli(TargetLibraryInfoImpl(Triple(Twine(m.getTargetTriple())))) 51 | {} 52 | 53 | ~ModuleOracle() {} 54 | 55 | // Getter 56 | const DataLayout &getDataLayout() { 57 | return dl; 58 | } 59 | 60 | TargetLibraryInfo &getTargetLibraryInfo() { 61 | return tli; 62 | } 63 | 64 | // Data layout 65 | uint64_t getBits() { 66 | return Bits; 67 | } 68 | 69 | uint64_t getPointerWidth() { 70 | return dl.getPointerSizeInBits(); 71 | } 72 | 73 | uint64_t getPointerSize() { 74 | return dl.getPointerSize(); 75 | } 76 | 77 | uint64_t getTypeSize(Type *ty) { 78 | return dl.getTypeAllocSize(ty); 79 | } 80 | 81 | uint64_t getTypeWidth(Type *ty) { 82 | return dl.getTypeSizeInBits(ty); 83 | } 84 | 85 | uint64_t getTypeOffset(Type *type, unsigned idx) { 86 | assert(isa(type)); 87 | return dl.getStructLayout(cast(type)) 88 | ->getElementOffset(idx); 89 | } 90 | 91 | bool isReintPointerType(Type *ty) { 92 | return (ty->isPointerTy() || 93 | (ty->isIntegerTy() && 94 | ty->getIntegerBitWidth() == getPointerWidth())); 95 | } 96 | 97 | protected: 98 | // Info provide 99 | const DataLayout &dl; 100 | TargetLibraryInfo tli; 101 | 102 | // Consts 103 | const uint64_t Bits = 8; 104 | }; 105 | 106 | class Helper { 107 | public: 108 | // LLVM value 109 | static string getValueName(Value *v) { 110 | if (!v->hasName()) { 111 | return to_string(reinterpret_cast(v)); 112 | } else { 113 | return v->getName().str(); 114 | } 115 | } 116 | 117 | static string getValueType(Value *v) { 118 | if (Instruction *inst = dyn_cast(v)) { 119 | return string(inst->getOpcodeName()); 120 | } else { 121 | return string("value " + to_string(v->getValueID())); 122 | } 123 | } 124 | 125 | static string getValueRepr(Value *v) { 126 | string str; 127 | raw_string_ostream stm(str); 128 | 129 | v->print(stm); 130 | stm.flush(); 131 | 132 | return str; 133 | } 134 | 135 | }; 136 | 137 | class Dumper { 138 | public: 139 | Dumper() {} 140 | ~Dumper() {} 141 | 142 | // LLVM value 143 | void valueName(Value *val) { 144 | errs() << Helper::getValueName(val) << "\n"; 145 | } 146 | 147 | void typedValue(Value *val) { 148 | errs() << "[" << Helper::getValueType(val) << "]" 149 | << Helper::getValueRepr(val) 150 | << "\n"; 151 | } 152 | 153 | }; 154 | 155 | extern Dumper DUMP; 156 | 157 | #endif 158 | -------------------------------------------------------------------------------- /analyzer/src/lib/LRSan.cc: -------------------------------------------------------------------------------- 1 | //===-- LRSan.cc - the LRSan framework------------------------===// 2 | // 3 | // This file implemets the LRSan framework. It calls the pass for 4 | // building call-graph and the pass for finding lacking-recheck bugs. 5 | // 6 | //===-----------------------------------------------------------===// 7 | 8 | #include "llvm/IR/LLVMContext.h" 9 | #include "llvm/IR/PassManager.h" 10 | #include "llvm/IR/Module.h" 11 | #include "llvm/IR/Verifier.h" 12 | #include "llvm/Bitcode/BitcodeReader.h" 13 | #include "llvm/Bitcode/BitcodeWriter.h" 14 | #include "llvm/Support/ManagedStatic.h" 15 | #include "llvm/Support/PrettyStackTrace.h" 16 | #include "llvm/Support/ToolOutputFile.h" 17 | #include "llvm/Support/SystemUtils.h" 18 | #include "llvm/Support/FileSystem.h" 19 | #include "llvm/IRReader/IRReader.h" 20 | #include "llvm/Support/SourceMgr.h" 21 | #include "llvm/Support/Signals.h" 22 | #include "llvm/Support/Path.h" 23 | 24 | #include 25 | #include 26 | #include 27 | #include 28 | 29 | #include "LRSan.h" 30 | #include "CallGraph.h" 31 | #include "Config.h" 32 | #include "CriticalVar.h" 33 | #include "PointerAnalysis.h" 34 | 35 | using namespace llvm; 36 | 37 | // Command line parameters. 38 | cl::list InputFilenames( 39 | cl::Positional, cl::OneOrMore, cl::desc("")); 40 | 41 | cl::opt VerboseLevel( 42 | "verbose-level", cl::desc("Print information at which verbose level"), 43 | cl::init(0)); 44 | 45 | cl::opt CriticalVar( 46 | "lrc", 47 | cl::desc("Identify lacking-recheck bugs"), 48 | cl::NotHidden, cl::init(false)); 49 | 50 | 51 | GlobalContext GlobalCtx; 52 | 53 | 54 | void IterativeModulePass::run(ModuleList &modules) { 55 | 56 | ModuleList::iterator i, e; 57 | OP << "[" << ID << "] Initializing " << modules.size() << " modules "; 58 | bool again = true; 59 | while (again) { 60 | again = false; 61 | for (i = modules.begin(), e = modules.end(); i != e; ++i) { 62 | again |= doInitialization(i->first); 63 | OP << "."; 64 | } 65 | } 66 | OP << "\n"; 67 | 68 | unsigned iter = 0, changed = 1; 69 | while (changed) { 70 | ++iter; 71 | changed = 0; 72 | unsigned counter_modules = 0; 73 | unsigned total_modules = modules.size(); 74 | for (i = modules.begin(), e = modules.end(); i != e; ++i) { 75 | OP << "[" << ID << " / " << iter << "] "; 76 | OP << "[" << ++counter_modules << " / " << total_modules << "] "; 77 | OP << "[" << i->second << "]\n"; 78 | 79 | bool ret = doModulePass(i->first); 80 | if (ret) { 81 | ++changed; 82 | OP << "\t [CHANGED]\n"; 83 | } else 84 | OP << "\n"; 85 | } 86 | OP << "[" << ID << "] Updated in " << changed << " modules.\n"; 87 | } 88 | 89 | OP << "[" << ID << "] Postprocessing ...\n"; 90 | again = true; 91 | while (again) { 92 | again = false; 93 | for (i = modules.begin(), e = modules.end(); i != e; ++i) { 94 | // TODO: Dump the results. 95 | again |= doFinalization(i->first); 96 | } 97 | } 98 | 99 | OP << "[" << ID << "] Done!\n\n"; 100 | } 101 | 102 | void LoadStaticData(GlobalContext *GCtx) { 103 | 104 | // load critical functions 105 | SetCriticalFuncs(GCtx->CriticalFuncs); 106 | } 107 | 108 | int main(int argc, char **argv) 109 | { 110 | // Print a stack trace if we signal out. 111 | sys::PrintStackTraceOnErrorSignal(argv[0]); 112 | PrettyStackTraceProgram X(argc, argv); 113 | 114 | llvm_shutdown_obj Y; // Call llvm_shutdown() on exit. 115 | 116 | cl::ParseCommandLineOptions(argc, argv, "global analysis\n"); 117 | SMDiagnostic Err; 118 | 119 | // Loading modules 120 | OP << "Total " << InputFilenames.size() << " file(s)\n"; 121 | 122 | for (unsigned i = 0; i < InputFilenames.size(); ++i) { 123 | 124 | LLVMContext *LLVMCtx = new LLVMContext(); 125 | std::unique_ptr M = parseIRFile(InputFilenames[i], Err, *LLVMCtx); 126 | 127 | if (M == NULL) { 128 | OP << argv[0] << ": error loading file '" 129 | << InputFilenames[i] << "'\n"; 130 | continue; 131 | } 132 | 133 | Module *Module = M.release(); 134 | StringRef MName = StringRef(strdup(InputFilenames[i].data())); 135 | GlobalCtx.Modules.push_back(std::make_pair(Module, MName)); 136 | GlobalCtx.ModuleMaps[Module] = InputFilenames[i]; 137 | } 138 | 139 | // Main workflow 140 | // Build global callgraph. 141 | CallGraphPass CGPass(&GlobalCtx); 142 | CGPass.run(GlobalCtx.Modules); 143 | 144 | // Identify critical variables and functions 145 | if (CriticalVar) { 146 | // Pointer analysis 147 | PointerAnalysisPass PAPass(&GlobalCtx); 148 | PAPass.run(GlobalCtx.Modules); 149 | 150 | LoadStaticData(&GlobalCtx); 151 | CriticalVarPass CVPass(&GlobalCtx); 152 | CVPass.run(GlobalCtx.Modules); 153 | } 154 | 155 | return 0; 156 | } 157 | 158 | -------------------------------------------------------------------------------- /analyzer/src/lib/PointerAnalysis.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | #include "PointerAnalysis.h" 7 | 8 | /// Alias types used to do pointer analysis. 9 | #define MUST_ALIAS 10 | 11 | bool PointerAnalysisPass::doInitialization(Module *M) { 12 | return false; 13 | } 14 | 15 | bool PointerAnalysisPass::doFinalization(Module *M) { 16 | return false; 17 | } 18 | 19 | /// Detect aliased pointers in this function. 20 | void PointerAnalysisPass::detectAliasPointers(Function *F, 21 | AAResults &AAR, 22 | PointerAnalysisMap &aliasPtrs) { 23 | std::set addrSet; 24 | Value *Addr1, *Addr2; 25 | MemoryLocation *MemLoc1, *MemLoc2; 26 | std::set DstSet, LPSet; 27 | 28 | DstSet.clear(); 29 | LPSet.clear(); 30 | addrSet.clear(); 31 | aliasPtrs.clear(); 32 | 33 | // Scan instructions to extract all pointers. 34 | for (inst_iterator i = inst_begin(F), ei = inst_end(F); 35 | i != ei; ++i) { 36 | Instruction *iInst = dyn_cast(&*i); 37 | 38 | LoadInst *LI = dyn_cast(iInst); 39 | StoreInst *SI = dyn_cast(iInst); 40 | CallInst *CI = dyn_cast(iInst); 41 | 42 | if (LI) { 43 | MemLoc1 = new MemoryLocation(); 44 | *MemLoc1 = MemoryLocation::get(LI); 45 | addrSet.insert(std::make_pair(LI->getPointerOperand(), 46 | MemLoc1)); 47 | LPSet.insert(LI->getPointerOperand()); 48 | } else if (SI) { 49 | MemLoc1 = new MemoryLocation(); 50 | *MemLoc1 = MemoryLocation::get(SI); 51 | addrSet.insert(std::make_pair(SI->getPointerOperand(), 52 | MemLoc1)); 53 | } else if (CI) { 54 | ImmutableCallSite CS(CI); 55 | for (unsigned j = 0, ej = CI->getNumArgOperands(); 56 | j < ej; ++j) { 57 | Value *Arg = CI->getArgOperand(j); 58 | 59 | if (!Arg->getType()->isPointerTy()) 60 | continue; 61 | 62 | MemLoc1 = new MemoryLocation(); 63 | *MemLoc1 = MemoryLocation::getForArgument(CS, j, *TLI); 64 | addrSet.insert(std::make_pair(Arg, MemLoc1)); 65 | 66 | Function *CF = CI->getCalledFunction(); 67 | if (CF && CF->getName() == "copy_from_user" && j < 2) 68 | DstSet.insert(Arg); 69 | } 70 | } 71 | } 72 | 73 | for (std::set::iterator it1 = addrSet.begin(), 74 | it1e = addrSet.end(); it1 != it1e; ++it1) { 75 | Addr1 = it1->first; 76 | MemLoc1 = it1->second; 77 | 78 | for (std::set::iterator it2 = addrSet.begin(), 79 | it2e = addrSet.end(); it2 != it2e; ++it2) { 80 | if (it2 == it1) 81 | continue; 82 | 83 | Addr2 = it2->first; 84 | MemLoc2 = it2->second; 85 | 86 | if (Addr1 == Addr2) 87 | continue; 88 | 89 | AliasResult AResult = AAR.alias(*MemLoc1, *MemLoc2); 90 | 91 | #ifdef MUST_ALIAS 92 | if (AResult != MustAlias && AResult != PartialAlias) { 93 | #else 94 | if (AResult == NoAlias) { 95 | #endif 96 | bool flag = true; 97 | 98 | if (AResult == MayAlias) { 99 | CallInst *CI; 100 | Function *CF; 101 | StringRef CFName; 102 | 103 | CI = dyn_cast(Addr1); 104 | if (CI) { 105 | CF = CI->getCalledFunction(); 106 | if (CF) { 107 | CFName = CF->getName(); 108 | if (CFName.contains("kmalloc")) 109 | flag = false; 110 | } 111 | } 112 | CI = dyn_cast(Addr2); 113 | if (CI) { 114 | CF = CI->getCalledFunction(); 115 | if (CF) { 116 | CFName = CF->getName(); 117 | if (CFName.contains("kmalloc")) 118 | flag = false; 119 | } 120 | } 121 | //Hack for copy_from_user - dst and SCheck 122 | if (DstSet.find(Addr1) != DstSet.end() && 123 | LPSet.find(Addr2) != LPSet.end()) 124 | flag = false; 125 | if (DstSet.find(Addr2) != DstSet.end() && 126 | LPSet.find(Addr1) != LPSet.end()) 127 | flag = false; 128 | if (DstSet.find(Addr1) != DstSet.end() && 129 | DstSet.find(Addr2) != DstSet.end()) 130 | flag = false; 131 | } 132 | 133 | if (flag) 134 | continue; 135 | } 136 | 137 | auto as = aliasPtrs.find(Addr1); 138 | if (as == aliasPtrs.end()) { 139 | std::set sv; 140 | sv.clear(); 141 | sv.insert(Addr2); 142 | aliasPtrs[Addr1] = sv; 143 | } else if (as->second.count(Addr2) == 0) { 144 | as->second.insert(Addr2); 145 | } 146 | } 147 | } 148 | } 149 | 150 | bool PointerAnalysisPass::doModulePass(Module *M) { 151 | // Save TargetLibraryInfo. 152 | Triple ModuleTriple(M->getTargetTriple()); 153 | TargetLibraryInfoImpl TLII(ModuleTriple); 154 | TLI = new TargetLibraryInfo(TLII); 155 | 156 | // Run BasicAliasAnalysis pass on each function in this module. 157 | // XXX: more complicated alias analyses may be required. 158 | legacy::FunctionPassManager *FPasses = new legacy::FunctionPassManager(M); 159 | AAResultsWrapperPass *AARPass = new AAResultsWrapperPass(); 160 | 161 | FPasses->add(AARPass); 162 | 163 | FPasses->doInitialization(); 164 | for (Function &F : *M) { 165 | if (F.isDeclaration()) 166 | continue; 167 | FPasses->run(F); 168 | } 169 | FPasses->doFinalization(); 170 | 171 | // Basic alias analysis result. 172 | AAResults &AAR = AARPass->getAAResults(); 173 | 174 | for (Module::iterator f = M->begin(), fe = M->end(); 175 | f != fe; ++f) { 176 | Function *F = &*f; 177 | PointerAnalysisMap aliasPtrs; 178 | 179 | if (F->empty()) 180 | continue; 181 | 182 | detectAliasPointers(F, AAR, aliasPtrs); 183 | 184 | // Save pointer analysis result. 185 | Ctx->FuncPAResults[F] = aliasPtrs; 186 | Ctx->FuncAAResults[F] = &AAR; 187 | } 188 | 189 | return false; 190 | } 191 | -------------------------------------------------------------------------------- /analyzer/src/lib/CallGraph.cc: -------------------------------------------------------------------------------- 1 | //===-- CallGraph.cc - Build global call-graph------------------===// 2 | // 3 | // This pass builds a global call-graph. The targets of an indirect 4 | // call are identified based on type-analysis, i.e., matching the 5 | // number and type of function parameters. 6 | // 7 | //===-----------------------------------------------------------===// 8 | 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | 19 | #include "CallGraph.h" 20 | #include "Config.h" 21 | 22 | using namespace llvm; 23 | 24 | 25 | // Find targets of indirect calls based on type analysis: as long as 26 | // the number and type of parameters of a function matches with the 27 | // ones of the callsite, we say the function is a possible target of 28 | // this call. 29 | void CallGraphPass::findCalleesByType(CallInst *CI, FuncSet &S) { 30 | 31 | if (CI->isInlineAsm()) 32 | return; 33 | 34 | CallSite CS(CI); 35 | for (Function *F : Ctx->AddressTakenFuncs) { 36 | 37 | // VarArg 38 | if (F->getFunctionType()->isVarArg()) { 39 | // Compare only known args in VarArg. 40 | } 41 | // otherwise, the numbers of args should be equal. 42 | else if (F->arg_size() != CS.arg_size()) { 43 | continue; 44 | } 45 | 46 | if (F->isIntrinsic()) { 47 | continue; 48 | } 49 | 50 | // Type matching on args. 51 | bool Matched = true; 52 | CallSite::arg_iterator AI = CS.arg_begin(); 53 | for (Function::arg_iterator FI = F->arg_begin(), 54 | FE = F->arg_end(); 55 | FI != FE; ++FI, ++AI) { 56 | // Check type mis-matches. 57 | // Get defined type on callee side. 58 | Type *DefinedTy = FI->getType(); 59 | // Get actual type on caller side. 60 | Type *ActualTy = (*AI)->getType(); 61 | 62 | if (DefinedTy == ActualTy) 63 | continue; 64 | 65 | // FIXME: this is a tricky solution for disjoint 66 | // types in different modules. A more reliable 67 | // solution is required to evaluate the equality 68 | // of two types from two different modules. 69 | // Since each module has its own type table, same 70 | // types are duplicated in different modules. This 71 | // makes the equality evaluation of two types from 72 | // two modules very hard, which is actually done 73 | // at link time by the linker. 74 | while (DefinedTy->isPointerTy() && ActualTy->isPointerTy()) { 75 | DefinedTy = DefinedTy->getPointerElementType(); 76 | ActualTy = ActualTy->getPointerElementType(); 77 | } 78 | if (DefinedTy->isStructTy() && ActualTy->isStructTy() && 79 | (DefinedTy->getStructName().equals(ActualTy->getStructName()))) 80 | continue; 81 | if (DefinedTy->isIntegerTy() && ActualTy->isIntegerTy() && 82 | DefinedTy->getIntegerBitWidth() == ActualTy->getIntegerBitWidth()) 83 | continue; 84 | // TODO: more types to be supported. 85 | 86 | // Make the type analysis conservative: assume universal 87 | // pointers, i.e., "void *" and "char *", are equivalent to 88 | // any pointer type and integer type. 89 | if ( 90 | (DefinedTy == Int8PtrTy && 91 | (ActualTy->isPointerTy() || ActualTy == IntPtrTy)) 92 | || 93 | (ActualTy == Int8PtrTy && 94 | (DefinedTy->isPointerTy() || DefinedTy == IntPtrTy)) 95 | ) 96 | continue; 97 | else { 98 | #if 0 // for debugging 99 | if (F->getName().compare("nfs_fs_mount") == 0) { 100 | OP << "DefinedTy @ " << DefinedTy << ": " << *DefinedTy << "\n"; 101 | OP << "ActualTy @ " << ActualTy << ": " << *ActualTy << "\n"; 102 | } 103 | #endif 104 | Matched = false; 105 | break; 106 | } 107 | } 108 | 109 | if (Matched) 110 | S.insert(F); 111 | } 112 | } 113 | 114 | bool CallGraphPass::doInitialization(Module *M) { 115 | 116 | DL = &(M->getDataLayout()); 117 | Int8PtrTy = Type::getInt8PtrTy(M->getContext()); 118 | IntPtrTy = DL->getIntPtrType(M->getContext()); 119 | 120 | for (Function &F : *M) { 121 | // Collect address-taken functions. 122 | if (F.hasAddressTaken()) 123 | Ctx->AddressTakenFuncs.insert(&F); 124 | 125 | // Collect global function definitions. 126 | if (F.hasExternalLinkage() && !F.empty()) { 127 | // External linkage always ends up with the function name. 128 | StringRef FName = F.getName(); 129 | // Special case: make the names of syscalls consistent. 130 | if (FName.startswith("SyS_")) 131 | FName = StringRef("sys_" + FName.str().substr(4)); 132 | 133 | // Map functions to their names. 134 | Ctx->Funcs[FName] = &F; 135 | } 136 | } 137 | 138 | return false; 139 | } 140 | 141 | bool CallGraphPass::doFinalization(Module *M) { 142 | 143 | // Do nothing here. 144 | return false; 145 | } 146 | 147 | bool CallGraphPass::doModulePass(Module *M) { 148 | 149 | // Use type-analysis to concervatively find possible targets of 150 | // indirect calls. 151 | for (Module::iterator f = M->begin(), fe = M->end(); 152 | f != fe; ++f) { 153 | 154 | Function *F = &*f; 155 | for (inst_iterator i = inst_begin(F), e = inst_end(F); 156 | i != e; ++i) { 157 | // Map callsite to possible callees. 158 | if (CallInst *CI = dyn_cast(&*i)) { 159 | FuncSet FS; 160 | Function *CF = CI->getCalledFunction(); 161 | if (!CF) { 162 | #ifdef SOUND_MODE 163 | findCalleesByType(CI, FS); 164 | #endif 165 | Ctx->Callees[CI] = FS; 166 | 167 | for (Function *Callee : FS) 168 | Ctx->Callers[Callee].insert(CI); 169 | 170 | // Save called values for future uses. 171 | Ctx->IndirectCallInsts.push_back(CI); 172 | } 173 | else { 174 | if (CF->empty()) { 175 | StringRef FName = CF->getName(); 176 | if (FName.startswith("SyS_")) 177 | FName = StringRef("sys_" + FName.str().substr(4)); 178 | CF = Ctx->Funcs[FName]; 179 | } 180 | FS.insert(CF); 181 | Ctx->Callees[CI] = FS; 182 | Ctx->Callers[CF].insert(CI); 183 | } 184 | } 185 | } 186 | } 187 | 188 | return false; 189 | } 190 | -------------------------------------------------------------------------------- /analyzer/src/lib/CriticalVar.h: -------------------------------------------------------------------------------- 1 | #ifndef _CRITICAL_VAR_H 2 | #define _CRITICAL_VAR_H 3 | 4 | #include 5 | 6 | #include "LRSan.h" 7 | 8 | class CriticalVarPass : public IterativeModulePass { 9 | 10 | typedef std::pair CFGEdge; 11 | typedef std::pair EdgeValue; 12 | 13 | enum ErrnoFlag { 14 | Reserved, 15 | Must_Return_Errno, 16 | May_Return_Errno 17 | }; 18 | 19 | enum UseDefFlag { 20 | Reserverd, 21 | Used, 22 | Defined, 23 | }; 24 | 25 | typedef std::map EdgeErrnoFlag; 26 | typedef std::pair InstructionUseDef; 27 | 28 | private: 29 | 30 | unsigned int sc_counter; // counter of security checks 31 | unsigned int cuc_counter; // counter of check-use chains 32 | unsigned int lcc_counter; // counter of lacking-check cases 33 | std::set cv_set; // set of critical variables 34 | 35 | std::set TrackedAddr; 36 | 37 | // pairs for values and their checks; a value may correspond 38 | // multiple checks? 39 | std::mapvalueCheckPairs; 40 | 41 | // Map function name to function definition. 42 | NameFuncMap AllFuncs; 43 | 44 | // check if the value is a constant. 45 | bool isConstant(Value *V); 46 | 47 | // Check if the value is an errno. 48 | bool isValueErrno(Value *V); 49 | 50 | // Check if the value is a parameter of the function. 51 | bool isFunctionParameter(Value *V, Function *F); 52 | 53 | // Make the given edge with errno flag. 54 | void markEdge(CFGEdge &CE, ErrnoFlag flag, EdgeErrnoFlag &errnoEdges); 55 | 56 | // Mark the edge from predBB to succBB with errno flag. 57 | void markEdgeBlockToBlock(BasicBlock *predBB, BasicBlock *succBB, ErrnoFlag flag, 58 | EdgeErrnoFlag &errnoEdges); 59 | 60 | // Mark all edges from BB with errno flag. 61 | void markAllEdgesFromBlock(BasicBlock *BB, ErrnoFlag flag, EdgeErrnoFlag &errnoEdges); 62 | 63 | // Mark all edges to BB with errno flag. 64 | void markAllEdgesToBlock(BasicBlock *BB, ErrnoFlag flag, EdgeErrnoFlag &errnoEdges); 65 | 66 | // Add edges to analyze for a phinode. 67 | void addPHINodeEdges(PHINode *PN, std::list &EV); 68 | 69 | // Recursively do errno check. 70 | void recurCheckValueErrno(Function *F, std::list &EV, 71 | std::set &PV, EdgeErrnoFlag &errnoEdges); 72 | 73 | // Check if the value must or may be an errno. This function is called recursively, 74 | void checkValueErrno(Function *F, Value *V, EdgeErrnoFlag &errnoEdges); 75 | 76 | // Check if the returned value must be or may be an errno. 77 | void checkReturnValue(Function *F, BasicBlock *BB, Value *V, EdgeErrnoFlag &errnoEdges); 78 | 79 | // Dump marked edges. 80 | void dumpEdges(EdgeErrnoFlag &errnoEdges); 81 | 82 | // Find security checks. 83 | void findSecurityChecks(Function *F, EdgeErrnoFlag &errnoEdges, 84 | std::set &securityChecks); 85 | 86 | // Find critical variables. 87 | void findCriticalVariable(Function *, Value *, Value *, 88 | std::map> &, std::set &); 89 | 90 | // Identify critical variables. 91 | void identifyCriticalVariables(Function *, std::set &, 92 | std::map> &); 93 | 94 | void filterNonGlobalVariables(std::map> &); 95 | 96 | // Check alias result of two values. 97 | bool checkAlias(Value *, Value *, 98 | PointerAnalysisMap &); 99 | 100 | // Get aliased pointers for the pointer. 101 | void getAliasPointers(Value *, std::set &, 102 | PointerAnalysisMap &); 103 | 104 | // Get called function name. 105 | StringRef getCalledFuncName(Value *); 106 | 107 | // Track aliased address after modification. 108 | void trackAliasAddrAfterModification(Value *, 109 | std::set &, 110 | Instruction *, 111 | std::set &, 112 | PointerAnalysisMap &aliasPtrs); 113 | 114 | // Check whether the value is exploitable. 115 | bool isExploitable(Value *, Value *, std::map &, 116 | std::set &); 117 | 118 | // Find modifications by function calls. 119 | void findUseDefFromCVAddr(Function *, Value *, 120 | std::set &, 121 | std::set &, 122 | PointerAnalysisMap &); 123 | 124 | // Check if it is possible to use the value stored 125 | // by the store instruction. 126 | bool possibleUseStResult(Instruction *, Instruction *); 127 | 128 | // Find uses of the critical variable. 129 | void findUseDefOfCriticalVar(Value *CV, Value *cvAddr, 130 | std::set &pSet, 131 | std::set &udSet, 132 | PointerAnalysisMap &aliasPtrs); 133 | 134 | // Filter out uses before definition. 135 | void filterUseBeforeDef(std::set &); 136 | 137 | // Filter definition before security check. 138 | void filterDefBeforeCheck(Value *, std::set &, 139 | Value *); 140 | 141 | void filterDefFromCheckedValue(Value *, std::set &, 142 | Value *); 143 | 144 | void trackCalledFunc(Function *, Value *, std::set &, 145 | std::list &, 146 | std::map> &); 147 | 148 | Value *trackSrcOfVal(Function *, Value *, std::set &); 149 | 150 | void trackSrc(Function *, Instruction *, Value *, 151 | std::set &, 152 | std::list &, 153 | std::map> &); 154 | 155 | // Find out where the source comes from for the modification. 156 | void findSrcForModification(Function *, Instruction *, 157 | std::list &, 158 | std::map> &); 159 | 160 | // Print out source code information. 161 | void printSourceCodeInfo(Instruction *); 162 | void printSourceCodeInfo(Value *); 163 | 164 | // Find the dominating check 165 | Instruction * findDominatingCheck(Value *RV); 166 | 167 | // Find the checked variable or function 168 | Value * findCheckedValue(Instruction *CI); 169 | 170 | // Check if lacking-check issues may occur 171 | bool findLackingChecks(Value *V, Instruction *CI); 172 | 173 | public: 174 | CriticalVarPass(GlobalContext *Ctx_) 175 | : IterativeModulePass(Ctx_, "CriticalVar") { } 176 | virtual bool doInitialization(llvm::Module *); 177 | virtual bool doFinalization(llvm::Module *); 178 | virtual bool doModulePass(llvm::Module *); 179 | }; 180 | 181 | #endif 182 | -------------------------------------------------------------------------------- /encoded-errno/include/uapi/asm-generic/errno.h: -------------------------------------------------------------------------------- 1 | #ifndef _ASM_GENERIC_ERRNO_H 2 | #define _ASM_GENERIC_ERRNO_H 3 | 4 | #include 5 | 6 | #define EDEADLK errno_encode(35) /* Resource deadlock would occur */ 7 | #define ENAMETOOLONG errno_encode(36) /* File name too long */ 8 | #define ENOLCK errno_encode(37) /* No record locks available */ 9 | 10 | /* 11 | * This error code is special: arch syscall entry code will return 12 | * -ENOSYS if users try to call a syscall that doesn't exist. To keep 13 | * failures of syscalls that really do exist distinguishable from 14 | * failures due to attempts to use a nonexistent syscall, syscall 15 | * implementations should refrain from returning -ENOSYS. 16 | */ 17 | #define ENOSYS errno_encode(38) /* Invalid system call number */ 18 | 19 | #define ENOTEMPTY errno_encode(39) /* Directory not empty */ 20 | #define ELOOP errno_encode(40) /* Too many symbolic links encountered */ 21 | #define EWOULDBLOCK EAGAIN /* Operation would block */ 22 | #define ENOMSG errno_encode(42) /* No message of desired type */ 23 | #define EIDRM errno_encode(43) /* Identifier removed */ 24 | #define ECHRNG errno_encode(44) /* Channel number out of range */ 25 | #define EL2NSYNC errno_encode(45) /* Level 2 not synchronized */ 26 | #define EL3HLT errno_encode(46) /* Level 3 halted */ 27 | #define EL3RST errno_encode(47) /* Level 3 reset */ 28 | #define ELNRNG errno_encode(48) /* Link number out of range */ 29 | #define EUNATCH errno_encode(49) /* Protocol driver not attached */ 30 | #define ENOCSI errno_encode(50) /* No CSI structure available */ 31 | #define EL2HLT errno_encode(51) /* Level 2 halted */ 32 | #define EBADE errno_encode(52) /* Invalid exchange */ 33 | #define EBADR errno_encode(53) /* Invalid request descriptor */ 34 | #define EXFULL errno_encode(54) /* Exchange full */ 35 | #define ENOANO errno_encode(55) /* No anode */ 36 | #define EBADRQC errno_encode(56) /* Invalid request code */ 37 | #define EBADSLT errno_encode(57) /* Invalid slot */ 38 | 39 | #define EDEADLOCK EDEADLK 40 | 41 | #define EBFONT errno_encode(59) /* Bad font file format */ 42 | #define ENOSTR errno_encode(60) /* Device not a stream */ 43 | #define ENODATA errno_encode(61) /* No data available */ 44 | #define ETIME errno_encode(62) /* Timer expired */ 45 | #define ENOSR errno_encode(63) /* Out of streams resources */ 46 | #define ENONET errno_encode(64) /* Machine is not on the network */ 47 | #define ENOPKG errno_encode(65) /* Package not installed */ 48 | #define EREMOTE errno_encode(66) /* Object is remote */ 49 | #define ENOLINK errno_encode(67) /* Link has been severed */ 50 | #define EADV errno_encode(68) /* Advertise error */ 51 | #define ESRMNT errno_encode(69) /* Srmount error */ 52 | #define ECOMM errno_encode(70) /* Communication error on send */ 53 | #define EPROTO errno_encode(71) /* Protocol error */ 54 | #define EMULTIHOP errno_encode(72) /* Multihop attempted */ 55 | #define EDOTDOT errno_encode(73) /* RFS specific error */ 56 | #define EBADMSG errno_encode(74) /* Not a data message */ 57 | #define EOVERFLOW errno_encode(75) /* Value too large for defined data type */ 58 | #define ENOTUNIQ errno_encode(76) /* Name not unique on network */ 59 | #define EBADFD errno_encode(77) /* File descriptor in bad state */ 60 | #define EREMCHG errno_encode(78) /* Remote address changed */ 61 | #define ELIBACC errno_encode(79) /* Can not access a needed shared library */ 62 | #define ELIBBAD errno_encode(80) /* Accessing a corrupted shared library */ 63 | #define ELIBSCN errno_encode(81) /* .lib section in a.out corrupted */ 64 | #define ELIBMAX errno_encode(82) /* Attempting to link in too many shared libraries */ 65 | #define ELIBEXEC errno_encode(83) /* Cannot exec a shared library directly */ 66 | #define EILSEQ errno_encode(84) /* Illegal byte sequence */ 67 | #define ERESTART errno_encode(85) /* Interrupted system call should be restarted */ 68 | #define ESTRPIPE errno_encode(86) /* Streams pipe error */ 69 | #define EUSERS errno_encode(87) /* Too many users */ 70 | #define ENOTSOCK errno_encode(88) /* Socket operation on non-socket */ 71 | #define EDESTADDRREQ errno_encode(89) /* Destination address required */ 72 | #define EMSGSIZE errno_encode(90) /* Message too long */ 73 | #define EPROTOTYPE errno_encode(91) /* Protocol wrong type for socket */ 74 | #define ENOPROTOOPT errno_encode(92) /* Protocol not available */ 75 | #define EPROTONOSUPPORT errno_encode(93) /* Protocol not supported */ 76 | #define ESOCKTNOSUPPORT errno_encode(94) /* Socket type not supported */ 77 | #define EOPNOTSUPP errno_encode(95) /* Operation not supported on transport endpoint */ 78 | #define EPFNOSUPPORT errno_encode(96) /* Protocol family not supported */ 79 | #define EAFNOSUPPORT errno_encode(97) /* Address family not supported by protocol */ 80 | #define EADDRINUSE errno_encode(98) /* Address already in use */ 81 | #define EADDRNOTAVAIL errno_encode(99) /* Cannot assign requested address */ 82 | #define ENETDOWN errno_encode(100) /* Network is down */ 83 | #define ENETUNREACH errno_encode(101) /* Network is unreachable */ 84 | #define ENETRESET errno_encode(102) /* Network dropped connection because of reset */ 85 | #define ECONNABORTED errno_encode(103) /* Software caused connection abort */ 86 | #define ECONNRESET errno_encode(104) /* Connection reset by peer */ 87 | #define ENOBUFS errno_encode(105) /* No buffer space available */ 88 | #define EISCONN errno_encode(106) /* Transport endpoint is already connected */ 89 | #define ENOTCONN errno_encode(107) /* Transport endpoint is not connected */ 90 | #define ESHUTDOWN errno_encode(108) /* Cannot send after transport endpoint shutdown */ 91 | #define ETOOMANYREFS errno_encode(109) /* Too many references: cannot splice */ 92 | #define ETIMEDOUT errno_encode(110) /* Connection timed out */ 93 | #define ECONNREFUSED errno_encode(111) /* Connection refused */ 94 | #define EHOSTDOWN errno_encode(112) /* Host is down */ 95 | #define EHOSTUNREACH errno_encode(113) /* No route to host */ 96 | #define EALREADY errno_encode(114) /* Operation already in progress */ 97 | #define EINPROGRESS errno_encode(115) /* Operation now in progress */ 98 | #define ESTALE errno_encode(116) /* Stale file handle */ 99 | #define EUCLEAN errno_encode(117) /* Structure needs cleaning */ 100 | #define ENOTNAM errno_encode(118) /* Not a XENIX named type file */ 101 | #define ENAVAIL errno_encode(119) /* No XENIX semaphores available */ 102 | #define EISNAM errno_encode(120) /* Is a named type file */ 103 | #define EREMOTEIO errno_encode(121) /* Remote I/O error */ 104 | #define EDQUOT errno_encode(122) /* Quota exceeded */ 105 | 106 | #define ENOMEDIUM errno_encode(123) /* No medium found */ 107 | #define EMEDIUMTYPE errno_encode(124) /* Wrong medium type */ 108 | #define ECANCELED errno_encode(125) /* Operation Canceled */ 109 | #define ENOKEY errno_encode(126) /* Required key not available */ 110 | #define EKEYEXPIRED errno_encode(127) /* Key has expired */ 111 | #define EKEYREVOKED errno_encode(128) /* Key has been revoked */ 112 | #define EKEYREJECTED errno_encode(129) /* Key was rejected by service */ 113 | 114 | /* for robust mutexes */ 115 | #define EOWNERDEAD errno_encode(130) /* Owner died */ 116 | #define ENOTRECOVERABLE errno_encode(131) /* State not recoverable */ 117 | 118 | #define ERFKILL errno_encode(132) /* Operation not possible due to RF-kill */ 119 | 120 | #define EHWPOISON errno_encode(133) /* Memory page has hardware error */ 121 | 122 | #endif 123 | -------------------------------------------------------------------------------- /analyzer/src/lib/CriticalVar.cc: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #include "CriticalVar.h" 17 | #include "Config.h" 18 | 19 | // don't check critical function 20 | #define VARIABLE_ONLY 1 21 | 22 | #define ENABLE_SOURCE_TRACKING 0 23 | 24 | // Number of addresses to track for each identified 25 | // modification of a critical variable 26 | #define NUM_ADDRESSES_TO_TRACK 50 27 | 28 | // Number of functions to track for each address 29 | #define NUM_FUNCTIONS_TO_TRACK 50 30 | 31 | #define DETECT_MEMFUNC_MODIFICATIONS true 32 | 33 | #define DETECT_STORE_MODIFICATIONS true 34 | 35 | //#define DEBUG_PRINT 1 36 | 37 | 38 | using namespace llvm; 39 | 40 | /// Check if the value is a constant. 41 | bool CriticalVarPass::isConstant(Value *V) { 42 | // Invalid input. 43 | if (!V) 44 | return false; 45 | 46 | // The value is a constant. 47 | Constant *Ct = dyn_cast(V); 48 | if (Ct) 49 | return true; 50 | 51 | return false; 52 | } 53 | 54 | /// Check if the value is an errno. 55 | bool CriticalVarPass::isValueErrno(Value *V) { 56 | // Invalid input. 57 | if (!V) 58 | return false; 59 | 60 | // The value is a constant integer. 61 | ConstantInt *CI = dyn_cast(V); 62 | if (CI && (CI->getType()->getBitWidth() == 32 || 63 | CI->getType()->getBitWidth() == 64)) { 64 | const APInt &value = CI->getValue(); 65 | // The value is an errno (negative or positive). 66 | if (is_errno(-value) || is_errno(value)) 67 | return true; 68 | } 69 | 70 | // The value is a constant expression. 71 | ConstantExpr *CE = dyn_cast(V); 72 | if (CE) { 73 | for (unsigned i = 0, e = CE->getNumOperands(); 74 | i != e; ++i) { 75 | if (isValueErrno(CE->getOperand(i))) 76 | return true; 77 | } 78 | } 79 | 80 | return false; 81 | } 82 | 83 | /// Check if the value is a parameter of the function. 84 | /// The current analysis is limited to a scope of a function. 85 | bool CriticalVarPass::isFunctionParameter(Value *V, Function *F) { 86 | for (Function::arg_iterator arg = F->arg_begin(); 87 | arg != F->arg_end(); arg++) { 88 | if (arg == V) 89 | return true; 90 | } 91 | return false; 92 | } 93 | 94 | /// Dump the marked CFG edges. 95 | void CriticalVarPass::dumpEdges(EdgeErrnoFlag &errnoEdges) { 96 | for (auto it = errnoEdges.begin(); it != errnoEdges.end(); ++it) { 97 | CFGEdge edge = it->first; 98 | ErrnoFlag flag = it->second; 99 | TerminatorInst *TI = edge.first; 100 | 101 | if (NULL == TI) { 102 | OP << " An errno "; 103 | OP << (flag == Must_Return_Errno ? "must" : "may"); 104 | OP << " be returned.\n"; 105 | continue; 106 | } 107 | 108 | BasicBlock *predBB = TI->getParent(); 109 | BasicBlock *succBB = TI->getSuccessor(edge.second); 110 | 111 | OP << " "; 112 | predBB->printAsOperand(OP, false); 113 | OP << " -> "; 114 | succBB->printAsOperand(OP, false); 115 | OP << ": "; 116 | OP << (flag == Must_Return_Errno ? "Must" : "May"); 117 | OP << '\n'; 118 | } 119 | } 120 | 121 | /// Make the given edge with errno flag. 122 | void CriticalVarPass::markEdge(CFGEdge &CE, 123 | ErrnoFlag flag, EdgeErrnoFlag &errnoEdges) { 124 | errnoEdges[CE] = flag; 125 | } 126 | 127 | /// Mark the edge from predBB to succBB with errno flag. 128 | void CriticalVarPass::markEdgeBlockToBlock(BasicBlock *predBB, 129 | BasicBlock *succBB, 130 | ErrnoFlag flag, EdgeErrnoFlag &errnoEdges) { 131 | TerminatorInst *TI; 132 | 133 | // Invalid inputs. 134 | if (!predBB || !succBB) 135 | return; 136 | 137 | TI = predBB->getTerminator(); 138 | for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i) { 139 | BasicBlock *BB = TI->getSuccessor(i); 140 | if (BB != succBB) 141 | continue; 142 | 143 | // Mark the edge 144 | CFGEdge CE = std::make_pair(TI, i); 145 | markEdge(CE, flag, errnoEdges); 146 | } 147 | } 148 | 149 | /// Recursively mark all edges from this BB with errno flag. 150 | void CriticalVarPass::markAllEdgesFromBlock( 151 | BasicBlock *BB, ErrnoFlag flag, 152 | EdgeErrnoFlag &errnoEdges) { 153 | TerminatorInst *TI; 154 | 155 | // Invalid input. 156 | if (!BB) 157 | return; 158 | 159 | std::set PB; 160 | std::list EB; 161 | PB.clear(); 162 | EB.clear(); 163 | 164 | EB.push_back(BB); 165 | while (!EB.empty()) { 166 | 167 | BasicBlock *TB = EB.front(); 168 | EB.pop_front(); 169 | if (PB.count(TB) != 0) 170 | continue; 171 | PB.insert(TB); 172 | 173 | // Iterate on each successor basic block. 174 | TI = TB->getTerminator(); 175 | for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i) { 176 | CFGEdge CE = std::make_pair(TI, i); 177 | // FIXME: this is a backward tracking, so do not overwrite 178 | // previously marked flags 179 | if (errnoEdges.count(CE) > 0 && flag != errnoEdges[CE]) 180 | markEdge(CE, May_Return_Errno, errnoEdges); 181 | else 182 | markEdge(CE, flag, errnoEdges); 183 | 184 | EB.push_back(TI->getSuccessor(i)); 185 | } 186 | } 187 | } 188 | 189 | /// Mark all edges to this BB with errno flag. 190 | void CriticalVarPass::markAllEdgesToBlock( 191 | BasicBlock *BB, ErrnoFlag flag, 192 | EdgeErrnoFlag &errnoEdges) { 193 | 194 | // Invalid input. 195 | if (!BB) 196 | return; 197 | 198 | std::set PB; 199 | std::list EB; 200 | PB.clear(); 201 | EB.clear(); 202 | 203 | EB.push_back(BB); 204 | while (!EB.empty()) { 205 | 206 | BasicBlock *TB = EB.front(); 207 | EB.pop_front(); 208 | if (PB.count(TB) != 0) 209 | continue; 210 | PB.insert(TB); 211 | // Iterate on each predecessor basic block. 212 | for (BasicBlock *predBB : predecessors(TB)) { 213 | TerminatorInst *TI = predBB->getTerminator(); 214 | 215 | for (unsigned i = 0, e = TI->getNumSuccessors(); i != e; ++i) { 216 | if (TB != TI->getSuccessor(i)) 217 | continue; 218 | 219 | CFGEdge CE = std::make_pair(TI, i); 220 | if (errnoEdges.count(CE) > 0 && flag != errnoEdges[CE]) 221 | markEdge(CE, May_Return_Errno, errnoEdges); 222 | else 223 | markEdge(CE, flag, errnoEdges); 224 | break; 225 | } 226 | EB.push_back(predBB); 227 | } 228 | } 229 | } 230 | 231 | /// Add edges to analyze for a phinode. 232 | void CriticalVarPass::addPHINodeEdges(PHINode *PN, 233 | std::list &EV) { 234 | BasicBlock *BB = PN->getParent(); 235 | 236 | for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { 237 | Value *IV = PN->getIncomingValue(i); 238 | BasicBlock *inBB = PN->getIncomingBlock(i); 239 | TerminatorInst *TI = inBB->getTerminator(); 240 | 241 | for (unsigned j = 0, f = TI->getNumSuccessors(); j != f; ++j) { 242 | if (BB != TI->getSuccessor(j)) 243 | continue; 244 | EV.push_back(std::make_pair(std::make_pair(TI, j), IV)); 245 | } 246 | } 247 | } 248 | 249 | /// Recursively do errno check for this value. 250 | void CriticalVarPass::recurCheckValueErrno( 251 | Function *F, std::list &EV, 252 | std::set &PV, 253 | EdgeErrnoFlag &errnoEdges) { 254 | 255 | EdgeValue E = EV.front(); 256 | CFGEdge CE = E.first; 257 | Value *V = E.second; 258 | 259 | EV.pop_front(); 260 | 261 | // Invalid input. 262 | if (!V) 263 | return; 264 | 265 | // Check if the value was checked before. 266 | if (PV.count(V) != 0) 267 | return; 268 | PV.insert(V); 269 | 270 | // The value is a load. Let's find out the previous stores. 271 | if (auto LI = dyn_cast(V)) { 272 | Value *LPO = LI->getPointerOperand(); 273 | 274 | list> RList; 275 | set PSet; 276 | 277 | RList.clear(); 278 | PSet.clear(); 279 | RList.push_back(make_pair(CE, LI->getParent())); 280 | 281 | while (!RList.empty()) { 282 | auto REL = RList.front(); 283 | RList.pop_front(); 284 | 285 | CFGEdge RCE = REL.first; 286 | BasicBlock *BB = REL.second; 287 | if (PSet.find(BB) != PSet.end()) 288 | continue; 289 | PSet.insert(BB); 290 | 291 | BasicBlock::reverse_iterator rit; 292 | if (BB == LI->getParent()) 293 | rit = ++LI->getIterator().getReverse(); 294 | else 295 | rit = BB->rbegin(); 296 | BasicBlock::reverse_iterator rie = BB->rend(); 297 | 298 | bool found = false; 299 | for (; rit != rie; ++rit) { 300 | auto SI = dyn_cast(&*rit); 301 | if (SI && SI->getPointerOperand() == LPO) { 302 | Value *SVO = SI->getValueOperand(); 303 | if (isConstant(SVO)) { 304 | if (isValueErrno(SVO)) { 305 | markAllEdgesFromBlock(BB, Must_Return_Errno, errnoEdges); 306 | markAllEdgesToBlock(BB, Must_Return_Errno, errnoEdges); 307 | } 308 | else { 309 | // likely not error code 310 | markAllEdgesFromBlock(BB, May_Return_Errno, errnoEdges); 311 | markAllEdgesToBlock(BB, May_Return_Errno, errnoEdges); 312 | } 313 | } else { 314 | EV.push_back(make_pair(RCE, SVO)); 315 | } 316 | found = true; 317 | break; 318 | } 319 | } 320 | if (found) 321 | continue; 322 | 323 | pred_iterator pi = pred_begin(BB), pe = pred_end(BB); 324 | for (; pi != pe; ++pi) { 325 | BasicBlock *PBB = *pi; 326 | TerminatorInst *TI = PBB->getTerminator(); 327 | unsigned num = TI->getNumSuccessors(); 328 | for (unsigned i = 0; i < num; ++i) { 329 | if (BB != TI->getSuccessor(i)) 330 | continue; 331 | RList.push_back(make_pair(make_pair(TI, i), PBB)); 332 | } 333 | } 334 | } 335 | 336 | return; 337 | } 338 | 339 | // The value is a phinode. 340 | PHINode *PN = dyn_cast(V); 341 | if (PN) { 342 | BasicBlock *BB = PN->getParent(); 343 | 344 | // Check each incoming value. 345 | for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { 346 | Value *IV = PN->getIncomingValue(i); 347 | BasicBlock *inBB = PN->getIncomingBlock(i); 348 | 349 | // The incoming value is a constant. 350 | if (isConstant(IV)) { 351 | if (isValueErrno(IV)) { 352 | markEdgeBlockToBlock(inBB, BB, Must_Return_Errno, errnoEdges); 353 | } 354 | } else { 355 | // Add the incoming value and the corresponding edge to the list. 356 | TerminatorInst *TI = inBB->getTerminator(); 357 | for (unsigned j = 0, f = TI->getNumSuccessors(); j != f; ++j) { 358 | if (BB != TI->getSuccessor(j)) 359 | continue; 360 | EV.push_back(std::make_pair(std::make_pair(TI, j), IV)); 361 | } 362 | } 363 | } 364 | 365 | return; 366 | } 367 | 368 | // The value is a select instruction. 369 | SelectInst *SI = dyn_cast(V); 370 | if (SI) { 371 | Value *Cond = SI->getCondition(); 372 | Value *SV; 373 | bool flag1 = false; 374 | bool flag2 = false; 375 | 376 | SV = SI->getTrueValue(); 377 | if (isConstant(SV)) { 378 | if(isValueErrno(SV)) 379 | flag1 = true; 380 | } else { 381 | EV.push_back(std::make_pair(CE, SV)); 382 | } 383 | 384 | SV = SI->getFalseValue(); 385 | if (isConstant(SV)) { 386 | if (isValueErrno(SV)) 387 | flag2 = true; 388 | } else { 389 | EV.push_back(std::make_pair(CE, SV)); 390 | } 391 | 392 | if (flag1 && flag2) { 393 | markEdge(CE, Must_Return_Errno, errnoEdges); 394 | } 395 | else if (flag1 || flag2) { 396 | markEdge(CE, May_Return_Errno, errnoEdges); 397 | } 398 | return; 399 | } 400 | 401 | // The value is a getelementptr instruction. 402 | GetElementPtrInst *GEP = dyn_cast(V); 403 | if (GEP) { 404 | Value *PO = GEP->getPointerOperand(); 405 | 406 | if (isConstant(PO)) { 407 | if (isValueErrno(PO)) { 408 | markEdge(CE, Must_Return_Errno, errnoEdges); 409 | } 410 | } else 411 | EV.push_back(std::make_pair(CE, PO)); 412 | return; 413 | } 414 | 415 | // The value is an unary instruction. 416 | UnaryInstruction *UI = dyn_cast(V); 417 | if (UI) { 418 | Value *UO = UI->getOperand(0); 419 | if (isConstant(UO)) { 420 | if (isValueErrno(UO)) { 421 | markEdge(CE, Must_Return_Errno, errnoEdges); 422 | } 423 | } 424 | else 425 | EV.push_back(std::make_pair(CE, UO)); 426 | return; 427 | } 428 | 429 | // The value is a binary operator. 430 | BinaryOperator *BO = dyn_cast(V); 431 | if (BO) { 432 | for (unsigned i = 0, e = BO->getNumOperands(); 433 | i != e; ++i) { 434 | Value *Opd = BO->getOperand(i); 435 | if (isConstant(Opd)) { 436 | if (isValueErrno(Opd)) { 437 | markEdge(CE, May_Return_Errno, errnoEdges); 438 | return; 439 | } 440 | } else 441 | EV.push_back(std::make_pair(CE, Opd)); 442 | } 443 | return; 444 | } 445 | 446 | // The value is an insertvalue instruction. 447 | InsertValueInst *IV = dyn_cast(V); 448 | if (IV) { 449 | Value *AO = IV->getAggregateOperand(); 450 | Value *IVO = IV->getInsertedValueOperand(); 451 | bool flag1 = false; 452 | bool flag2 = false; 453 | 454 | if (isConstant(AO)) { 455 | if (isValueErrno(AO)) 456 | flag1 = true; 457 | } else 458 | EV.push_back(std::make_pair(CE, AO)); 459 | 460 | if (isConstant(IVO)) { 461 | if (isValueErrno(IVO)) 462 | flag2 = true; 463 | } else 464 | EV.push_back(std::make_pair(CE, IVO)); 465 | 466 | if (flag1 && flag2) { 467 | markEdge(CE, Must_Return_Errno, errnoEdges); 468 | } 469 | else if (flag1 || flag2) { 470 | markEdge(CE, May_Return_Errno, errnoEdges); 471 | } 472 | 473 | return; 474 | } 475 | 476 | // The value is a icmp instruction. Skip it. 477 | ICmpInst *ICI = dyn_cast(V); 478 | if (ICI) 479 | return; 480 | 481 | // The value is a call instruction. 482 | CallInst *CaI = dyn_cast(V); 483 | if (CaI) { 484 | // FIXME: should be handled 485 | return; 486 | } 487 | 488 | // The value is a parameter of the fucntion. Skip it. 489 | if (isFunctionParameter(V, F)) 490 | return; 491 | 492 | // TODO: support more LLVM IR types. 493 | #ifdef DEBUG_PRINT 494 | OP << "== Warning: unsupported LLVM IR:" 495 | << *V << '\n'; 496 | #endif 497 | } 498 | 499 | 500 | 501 | /// Check if the value must or may be an errno. 502 | void CriticalVarPass::checkValueErrno(Function *F, 503 | Value *V, EdgeErrnoFlag &errnoEdges) { 504 | std::list EV; 505 | std::set PV; 506 | 507 | // Invalid input. 508 | if (!V) 509 | return; 510 | 511 | EV.clear(); 512 | PV.clear(); 513 | 514 | // Construct the list. 515 | EV.push_back(std::make_pair(std::make_pair((TerminatorInst *)NULL, 0), V)); 516 | 517 | #ifdef DEBUG_PRINT 518 | if (EV.empty()) 519 | OP << "== Warning: unsupported LLVM IR:" 520 | << *V << '\n'; 521 | #endif 522 | 523 | // Iterate each value in the list. 524 | while (!EV.empty()) { 525 | // Recursively do errno check for this value. 526 | recurCheckValueErrno(F, EV, PV, errnoEdges); 527 | } 528 | } 529 | 530 | /// Check if the returned value must be or may be an errno. 531 | /// And mark the traversed edges in the CFG. 532 | void CriticalVarPass::checkReturnValue(Function *F, 533 | BasicBlock *BB, Value *V, 534 | EdgeErrnoFlag &errnoEdges) { 535 | 536 | std::list> EV; 537 | 538 | // Invalid input. 539 | if (!V) 540 | return; 541 | 542 | // The returned value is not a constant. Further check is required. 543 | checkValueErrno(F, V, errnoEdges); 544 | } 545 | 546 | /// Traverse the CFG and find security checks. 547 | void CriticalVarPass::findSecurityChecks( 548 | Function *F, 549 | EdgeErrnoFlag &errnoEdges, 550 | std::set &securityChecks) { 551 | 552 | // Find blocks that contain security checks. 553 | for (Function::iterator b = F->begin(), e = F->end(); 554 | b != e; ++b) { 555 | BasicBlock *BB = &*b; 556 | TerminatorInst *TI = BB->getTerminator(); 557 | bool SecureCond1 = false; /* One path must return an errno. */ 558 | bool SecureCond2 = false; /* One path must have possibility not to return any errno. */ 559 | 560 | int NumSucc = TI->getNumSuccessors(); 561 | if (NumSucc < 2) 562 | continue; 563 | 564 | // Query marked edge graph to determine security checks 565 | int errFlag = 0; 566 | int NumMayErr = 0, NumMustErr = 0; 567 | for (unsigned i = 0; i < NumSucc; ++i) { 568 | errFlag = errnoEdges[std::make_pair(TI, i)]; 569 | if (errFlag == Must_Return_Errno) 570 | ++NumMustErr; 571 | else 572 | ++NumMayErr; 573 | } 574 | 575 | // not a security check 576 | if (!(NumMustErr && NumMayErr)) { 577 | continue; 578 | } 579 | 580 | 581 | // This BB has security check, try to find it. 582 | Value *Cond = NULL; 583 | BranchInst *BI; 584 | SwitchInst *SI; 585 | 586 | BI = dyn_cast(TI); 587 | if (BI) 588 | Cond = BI->getCondition(); 589 | else { 590 | SI = dyn_cast(TI); 591 | if (SI) 592 | Cond = SI->getCondition(); 593 | } 594 | 595 | if (!Cond) 596 | OP << "Warnning: cannot find the check.\n"; 597 | else { 598 | //OP << "Condition of the check is: " << *Cond << "\n"; 599 | securityChecks.insert(Cond); 600 | } 601 | } 602 | } 603 | 604 | /// Backtrack to find critical variables/functions. 605 | void CriticalVarPass::findCriticalVariable( 606 | Function *F, Value *SCheck, Value *V, 607 | std::map> &CheckToVars, 608 | std::set &PSet) { 609 | 610 | if (isConstant(V)) 611 | return; 612 | 613 | if (PSet.count(V) != 0) 614 | return; 615 | PSet.insert(V); 616 | 617 | if (isFunctionParameter(V, F)) { 618 | #ifdef DEBUG_PRINT 619 | OP << "== A critical variable is identified (function parameter):\n"; 620 | OP << "\033[31m" << *V << "\033[0m" << "\n"; 621 | #endif 622 | CheckToVars[SCheck].insert(V); 623 | return; 624 | } 625 | 626 | CallInst *CI = dyn_cast(V); 627 | if (CI) { 628 | #ifndef VARIABLE_ONLY 629 | CheckToVars[SCheck].insert(CI); 630 | #endif 631 | return; 632 | } 633 | 634 | LoadInst *LI = dyn_cast(V); 635 | if (LI) { 636 | // XXX: we may need to save the memory address for future analysis. 637 | // XXX: we may also need to save the type of the loaded value, pointer or non-pointer. 638 | CheckToVars[SCheck].insert(LI); 639 | return; 640 | } 641 | 642 | SelectInst *SI = dyn_cast(V); 643 | if (SI) { 644 | findCriticalVariable(F, SCheck, SI->getTrueValue(), CheckToVars, PSet); 645 | findCriticalVariable(F, SCheck, SI->getFalseValue(), CheckToVars, PSet); 646 | return; 647 | } 648 | 649 | GetElementPtrInst *GEP = dyn_cast(V); 650 | if (GEP) 651 | return findCriticalVariable(F, SCheck, GEP->getPointerOperand(), CheckToVars, PSet); 652 | 653 | PHINode *PN = dyn_cast(V); 654 | if (PN) { 655 | for (unsigned i = 0, e = PN->getNumIncomingValues(); i != e; ++i) { 656 | Value *IV = PN->getIncomingValue(i); 657 | 658 | findCriticalVariable(F, SCheck, IV, CheckToVars, PSet); 659 | } 660 | return; 661 | } 662 | 663 | ICmpInst *ICmp = dyn_cast(V); 664 | if (ICmp) { 665 | for (unsigned i = 0; i < ICmp->getNumOperands(); ++i) { 666 | Value *Opd = ICmp->getOperand(i); 667 | 668 | findCriticalVariable(F, SCheck, Opd, CheckToVars, PSet); 669 | } 670 | return; 671 | } 672 | 673 | BinaryOperator *BO = dyn_cast(V); 674 | if (BO) { 675 | for (unsigned i = 0, e = BO->getNumOperands(); 676 | i != e; ++i) { 677 | Value *Opd = BO->getOperand(i); 678 | if (isConstant(Opd)) 679 | continue; 680 | 681 | findCriticalVariable(F, SCheck, Opd, CheckToVars, PSet); 682 | } 683 | return; 684 | } 685 | 686 | UnaryInstruction *UI = dyn_cast(V); 687 | if (UI) { 688 | Value *UO = UI->getOperand(0); 689 | findCriticalVariable(F, SCheck, UO, CheckToVars, PSet); 690 | return; 691 | } 692 | 693 | // TODO: more analyses are required. 694 | #ifdef DEBUG_PRINT 695 | OP << "== Warning: unsupported LLVM IR when find critical variables/functions:"; 696 | OP << "\033[31m" << *V << "\033[0m\n"; 697 | #endif 698 | } 699 | 700 | /// Identify critical variables/functions used in each security check. 701 | void CriticalVarPass::identifyCriticalVariables( 702 | Function *F, 703 | std::set &securityChecks, 704 | std::map> &CheckToVars) { 705 | 706 | for (std::set::iterator it = securityChecks.begin(); 707 | it != securityChecks.end(); ++it) { 708 | Value *Cond = *it; 709 | std::set PSet; 710 | 711 | PSet.clear(); 712 | 713 | CheckToVars[Cond].clear(); 714 | 715 | findCriticalVariable(F, Cond, Cond, CheckToVars, PSet); 716 | } 717 | } 718 | 719 | void CriticalVarPass::filterNonGlobalVariables( 720 | std::map> &CheckToVars) { 721 | for (std::map>::iterator it = CheckToVars.begin(); 723 | it != CheckToVars.end(); ++it) { 724 | 725 | std::set cvSet = it->second; 726 | 727 | for (std::set::iterator cit = cvSet.begin(); cit != cvSet.end(); cit++) { 728 | Value *CV = *cit; 729 | 730 | if (dyn_cast(CV)) { 731 | cvSet.erase(cit); 732 | continue; 733 | } 734 | 735 | LoadInst *LI = dyn_cast(CV); 736 | if (LI) { 737 | Value *Addr = LI->getPointerOperand(); 738 | 739 | if (dyn_cast(Addr)) { 740 | cvSet.erase(cit); 741 | continue; 742 | } 743 | } 744 | } 745 | } 746 | } 747 | 748 | /// Check alias result of two values. 749 | /// True: alias, False: not alias. 750 | bool CriticalVarPass::checkAlias(Value *Addr1, Value *Addr2, 751 | PointerAnalysisMap &aliasPtrs) { 752 | 753 | if (Addr1 == Addr2) 754 | return true; 755 | 756 | auto it = aliasPtrs.find(Addr1); 757 | if (it != aliasPtrs.end()) { 758 | if (it->second.count(Addr2) != 0) 759 | return true; 760 | } 761 | 762 | // May not need to do this further check. 763 | it = aliasPtrs.find(Addr2); 764 | if (it != aliasPtrs.end()) { 765 | if (it->second.count(Addr1) != 0) 766 | return true; 767 | } 768 | 769 | return false; 770 | } 771 | 772 | /// Get aliased pointers for this pointer. 773 | void CriticalVarPass::getAliasPointers( 774 | Value *Addr, 775 | std::set &aliasAddr, 776 | PointerAnalysisMap &aliasPtrs) { 777 | 778 | aliasAddr.clear(); 779 | aliasAddr.insert(Addr); 780 | 781 | auto it = aliasPtrs.find(Addr); 782 | if (it == aliasPtrs.end()) 783 | return; 784 | 785 | for (auto itt : it->second) 786 | aliasAddr.insert(itt); 787 | } 788 | 789 | /// Get called function name of V. 790 | StringRef CriticalVarPass::getCalledFuncName(Value *V) { 791 | assert(V); 792 | 793 | InlineAsm *IA = dyn_cast(V); 794 | if (IA) 795 | return StringRef(IA->getAsmString()); 796 | 797 | User *UV = dyn_cast(V); 798 | if (UV) { 799 | if (UV->getNumOperands() == 0) 800 | return UV->getName(); 801 | Value *VUV = UV->getOperand(0); 802 | return VUV->getName(); 803 | } 804 | 805 | return V->getName(); 806 | } 807 | 808 | /// Check if it is possible for an instruction Inst to use 809 | /// the value stored by the store instruction St. 810 | /// If yes, there exists a path on the CFG from St to Inst. 811 | /// Return value: true -> possible, false -> impossible. 812 | bool CriticalVarPass::possibleUseStResult( 813 | Instruction *Inst, 814 | Instruction *St) { 815 | 816 | BasicBlock *InstBB = Inst->getParent(); 817 | BasicBlock *StBB = St->getParent(); 818 | std::set PB; 819 | std::list EB; 820 | 821 | if (!InstBB || !StBB) 822 | return false; 823 | 824 | // Inst and St are in the same basic block. 825 | // Iterate over each instruction see which 826 | // one is seen firstly. 827 | if (InstBB == StBB) { 828 | for (BasicBlock::iterator I = InstBB->begin(), 829 | IE = InstBB->end(); I != IE; ++I) { 830 | Instruction *II = dyn_cast(&*I); 831 | if (II == St) 832 | return true; 833 | if (II == Inst) 834 | return false; 835 | } 836 | return false; 837 | } 838 | 839 | // See if there exists a path from StBB to LdBB. 840 | PB.clear(); 841 | EB.clear(); 842 | 843 | EB.push_back(StBB); 844 | while (!EB.empty()) { 845 | BasicBlock *TB = EB.front(); 846 | TerminatorInst *TI; 847 | 848 | EB.pop_front(); 849 | if (PB.count(TB) != 0) 850 | continue; 851 | PB.insert(TB); 852 | 853 | if (TB == InstBB) 854 | return true; 855 | 856 | TI = TB->getTerminator(); 857 | for (unsigned i = 0, e = TI->getNumSuccessors(); 858 | i != e; ++i) { 859 | EB.push_back(TI->getSuccessor(i)); 860 | } 861 | } 862 | 863 | return false; 864 | } 865 | 866 | void CriticalVarPass::trackAliasAddrAfterModification( 867 | Value *Addr, 868 | std::set &pSet, 869 | Instruction *StInst, 870 | std::set &udSet, 871 | PointerAnalysisMap &aliasPtrs) { 872 | 873 | std::set aliasAddr; 874 | 875 | getAliasPointers(Addr, aliasAddr, aliasPtrs); 876 | for (auto it : aliasAddr) { 877 | for (User *UA : it->users()) { 878 | Instruction *UAInst = dyn_cast(UA); 879 | 880 | if (!UAInst) 881 | continue; 882 | 883 | // Check if it is possible for this instruciton to 884 | // use the value stored by the store instruction. 885 | // It is possible that the instruction may happen before 886 | // the store instruction on the CFG. 887 | if (!possibleUseStResult(UAInst, StInst)) 888 | continue; 889 | 890 | LoadInst *UALoad = dyn_cast(UA); 891 | if (UALoad) { 892 | findUseDefOfCriticalVar(dyn_cast(UA), 893 | UALoad->getPointerOperand(), 894 | pSet, udSet, aliasPtrs); 895 | continue; 896 | } 897 | 898 | #if DETECT_MEMFUNC_MODIFICATIONS 899 | CallInst *UACall = dyn_cast(UA); 900 | if (UACall) { 901 | Value *CaV = UACall->getCalledValue(); 902 | StringRef FuncName = getCalledFuncName(CaV); 903 | auto FIter = Ctx->MemWriteFuncs.find(FuncName.str()); 904 | if (FIter == Ctx->MemWriteFuncs.end()) 905 | continue; 906 | if (UACall->getNumArgOperands() < FIter->second) 907 | continue; 908 | if (UACall->getArgOperand(FIter->second) != it) 909 | continue; 910 | udSet.insert(std::make_pair(UACall, Defined)); 911 | } 912 | #endif 913 | } 914 | } 915 | } 916 | 917 | /// Check whether a value is exploitable. Intuitively, 918 | /// the following cases are unexploitable and will be 919 | /// filtered out: 920 | /// 1. The operation result of the orignal value of a 921 | /// critical variable and a constant. 922 | /// 2. The return value of a function call (???). 923 | /// 3. More cases to be added here ... 924 | /// 925 | /// Return value: 926 | /// false: the value is unexploitable. 927 | /// true: the value may be exploitable. 928 | bool CriticalVarPass::isExploitable( 929 | Value *V, Value *Addr, 930 | std::map &Expt, 931 | std::set &PV) { 932 | 933 | if (Expt.count(V) > 0) 934 | return Expt[V]; 935 | 936 | // This value was checked before. 937 | if (PV.count(V) > 0) { 938 | Expt[V] = true; 939 | return Expt[V]; 940 | } 941 | PV.insert(V); 942 | 943 | if (isConstant(V)) { 944 | Expt[V] = false; 945 | return Expt[V]; 946 | } 947 | 948 | CallInst *CI = dyn_cast(V); 949 | if (CI) { 950 | Expt[V] = false; 951 | return Expt[V]; 952 | } 953 | 954 | LoadInst *LI = dyn_cast(V); 955 | if (LI) { 956 | if (LI->getPointerOperand() == Addr) 957 | Expt[V] = false; 958 | else 959 | Expt[V] = true; 960 | return Expt[V]; 961 | } 962 | 963 | UnaryInstruction *UI = dyn_cast(V); 964 | if (UI) { 965 | Expt[V] = isExploitable(UI->getOperand(0), Addr, 966 | Expt, PV); 967 | return Expt[V]; 968 | } 969 | 970 | PHINode *PN = dyn_cast(V); 971 | if (PN) { 972 | bool flag = false; 973 | for (unsigned i = 0, e = PN->getNumIncomingValues(); 974 | i != e; ++i) { 975 | if (isExploitable(PN->getIncomingValue(i), 976 | Addr, Expt, PV)) { 977 | flag = true; 978 | break; 979 | } 980 | } 981 | Expt[V] = flag; 982 | return Expt[V]; 983 | } 984 | 985 | BinaryOperator *BO = dyn_cast(V); 986 | if (BO) { 987 | if (BO->getNumOperands() != 2) 988 | Expt[V] = true; 989 | else { 990 | Value *Opd0 = BO->getOperand(0); 991 | Value *Opd1 = BO->getOperand(1); 992 | Expt[V] = (isExploitable(Opd0, Addr, Expt, PV) || 993 | isExploitable(Opd1, Addr, Expt, PV)); 994 | } 995 | return Expt[V]; 996 | } 997 | 998 | Expt[V] = true; 999 | 1000 | return Expt[V]; 1001 | } 1002 | 1003 | /// Find modifications by function calls. 1004 | void CriticalVarPass::findUseDefFromCVAddr( 1005 | Function *F, 1006 | Value *cvAddr, 1007 | std::set &pSet, 1008 | std::set &udSet, 1009 | PointerAnalysisMap &aliasPtrs) { 1010 | 1011 | for (inst_iterator i = inst_begin(F), ei = inst_end(F); 1012 | i != ei; ++i) { 1013 | Instruction *Inst = dyn_cast(&*i); 1014 | StringRef FName; 1015 | Value *CaV; 1016 | unsigned ej; 1017 | 1018 | StoreInst *SI = dyn_cast(Inst); 1019 | if (SI) { 1020 | CaV = SI->getPointerOperand(); 1021 | if (!checkAlias(cvAddr, CaV, aliasPtrs)) 1022 | continue; 1023 | 1024 | // This store may modify a critical variable. 1025 | #if DETECT_STORE_MODIFICATIONS 1026 | std::map Expt; 1027 | std::set PV; 1028 | Expt.clear(); 1029 | PV.clear(); 1030 | if (isExploitable(SI->getValueOperand(), 1031 | SI->getPointerOperand(), 1032 | Expt, PV)) 1033 | udSet.insert(std::make_pair(Inst, Defined)); 1034 | #endif 1035 | 1036 | // We need to continue to track address aliased with this address. 1037 | trackAliasAddrAfterModification(CaV, pSet, Inst, udSet, aliasPtrs); 1038 | 1039 | // We also need to track the value stored. 1040 | // TODO: further analysis is required to find the source of this value. 1041 | findUseDefOfCriticalVar(SI->getValueOperand(), NULL, pSet, udSet, aliasPtrs); 1042 | 1043 | continue; 1044 | } 1045 | 1046 | CallInst *CI = dyn_cast(Inst); 1047 | InvokeInst *II = dyn_cast(Inst); 1048 | if (CI) { 1049 | CaV = CI->getCalledValue(); 1050 | ej = CI->getNumArgOperands(); 1051 | } else if (II) { 1052 | CaV = II->getCalledValue(); 1053 | ej = II->getNumArgOperands(); 1054 | } else 1055 | continue; 1056 | 1057 | FName = getCalledFuncName(CaV); 1058 | if (FName.contains("llvm") && FName.contains("lifetime")) 1059 | continue; 1060 | 1061 | for (unsigned j = 0; j != ej; ++j) { 1062 | Value *Arg; 1063 | 1064 | if (CI) 1065 | Arg = CI->getArgOperand(j); 1066 | else 1067 | Arg = II->getArgOperand(j); 1068 | 1069 | if (!checkAlias(cvAddr, Arg, aliasPtrs)) 1070 | continue; 1071 | 1072 | #if DETECT_MEMFUNC_MODIFICATIONS 1073 | StringRef FuncName = getCalledFuncName(CaV); 1074 | auto FIter = Ctx->MemWriteFuncs.find(FuncName.str()); 1075 | if (FIter != Ctx->MemWriteFuncs.end() && FIter->second == j) { 1076 | udSet.insert(std::make_pair(Inst, Defined)); 1077 | break; 1078 | } 1079 | #endif 1080 | 1081 | // We need to continue to track address aliased with this address. 1082 | trackAliasAddrAfterModification(Arg, pSet, Inst, udSet, aliasPtrs); 1083 | 1084 | break; 1085 | } 1086 | } 1087 | } 1088 | 1089 | /// Find all instructions that use the critical variable. 1090 | /// Note: a use can be a direct use or an indirect use. 1091 | /// XXX: the definition of critical use: 1092 | /// 1. A critical variable is used as a memory address 1093 | /// in memory access instructions, e.g., load and store. 1094 | /// 2. A critical variable is used as a parameter of a 1095 | /// critical function, e.g., kmalloc, memcpy, and memset. 1096 | /// 3. A critical variable is used as a function pointer. 1097 | /// 4. A critical varialbe is used as an index in GEP. 1098 | /// 5. More??? 1099 | /// XXX: the definition of modification: 1100 | /// 1. An updated value of a critical variable is stored 1101 | /// to the address that is aliased with the address of 1102 | /// the critical variable. That is a store instruction 1103 | /// is required for this type of modification. 1104 | /// 2. Stack variable??? 1105 | void CriticalVarPass::findUseDefOfCriticalVar( 1106 | Value *CV, 1107 | Value *cvAddr, 1108 | std::set &pSet, 1109 | std::set &udSet, 1110 | PointerAnalysisMap &aliasPtrs) { 1111 | 1112 | if (!CV || isConstant(CV)) 1113 | return; 1114 | 1115 | if (pSet.count(CV) != 0) 1116 | return; 1117 | pSet.insert(CV); 1118 | 1119 | for (User *U : CV->users()) { 1120 | if (Instruction *Inst = dyn_cast(U)) { 1121 | /* For the following types of instructions, we continue to 1122 | find their uses. */ 1123 | // XXX: typical use instructions: BinaryOperator, CallInst, 1124 | // ExtractElementInst, GetElementInst, InsertElementInst, 1125 | // InsertValueInst, PHINode, SelectInst, ShuffleVectorInst, 1126 | // StoreInst, ReturnInst, CastInst, ExtractValueInst, LoadInst. 1127 | // 1128 | // XXX: typical define instructions: StoreInst, 1129 | // BinaryOperator, CallInst, InvokeInst, InsertElementInst, 1130 | // InsertValueInst, ShuffleVectorInst, and CastInst. 1131 | 1132 | SelectInst *SI = dyn_cast(Inst); 1133 | if (SI) { 1134 | Value *V = dyn_cast(SI); 1135 | findUseDefOfCriticalVar(V, cvAddr, pSet, udSet, aliasPtrs); 1136 | continue; 1137 | } 1138 | 1139 | PHINode *PN = dyn_cast(Inst); 1140 | if (PN) { 1141 | Value *V = dyn_cast(PN); 1142 | findUseDefOfCriticalVar(V, cvAddr, pSet, udSet, aliasPtrs); 1143 | continue; 1144 | } 1145 | 1146 | CastInst *CI = dyn_cast(Inst); 1147 | if (CI) { 1148 | Value *V = dyn_cast(CI); 1149 | findUseDefOfCriticalVar(V, cvAddr, pSet, udSet, aliasPtrs); 1150 | continue; 1151 | } 1152 | 1153 | GetElementPtrInst *GEP = dyn_cast(Inst); 1154 | if (GEP) { 1155 | // If used as an index, mark it as a critical use. 1156 | for (Value *Index : make_range(GEP->idx_begin(), 1157 | GEP->idx_end())) { 1158 | if (Index == CV) { 1159 | //udSet.insert(std::make_pair(Inst, Used)); 1160 | break; 1161 | } 1162 | } 1163 | continue; 1164 | } 1165 | 1166 | BinaryOperator *BO = dyn_cast(Inst); 1167 | if (BO) { 1168 | // The result of BO may be used for modification, 1169 | // we should continue to track. 1170 | Value *V = dyn_cast(BO); 1171 | findUseDefOfCriticalVar(V, cvAddr, pSet, udSet, aliasPtrs); 1172 | continue; 1173 | } 1174 | 1175 | LoadInst *LI = dyn_cast(Inst); 1176 | if (LI) { 1177 | // used for memory read, a critical use 1178 | udSet.insert(std::make_pair(Inst, Used)); 1179 | continue; 1180 | } 1181 | 1182 | StoreInst *STI = dyn_cast(Inst); 1183 | if (STI) { 1184 | Value *Addr = STI->getPointerOperand(); 1185 | if (Addr == CV) { 1186 | // Used as an address to write, a critical use ??? 1187 | udSet.insert(std::make_pair(Inst, Used)); 1188 | continue; 1189 | } 1190 | 1191 | // Used as a value to write to memory address Addr. 1192 | // If Addr is aliased to the memory address of CV, 1193 | // we need mark this store as a modification. 1194 | #if DETECT_STORE_MODIFICATIONS 1195 | if (cvAddr) { 1196 | std::map Expt; 1197 | std::set PV; 1198 | Expt.clear(); 1199 | PV.clear(); 1200 | if (checkAlias(Addr, cvAddr, aliasPtrs) && 1201 | isExploitable(STI->getValueOperand(), 1202 | Addr, Expt, PV)) 1203 | udSet.insert(std::make_pair(Inst, Defined)); 1204 | } 1205 | #endif 1206 | 1207 | // Try to find all addresses that are aliased with Addr 1208 | // and continue to track all values loaded from the 1209 | // aliased addresses. 1210 | trackAliasAddrAfterModification(Addr, pSet, Inst, 1211 | udSet, aliasPtrs); 1212 | continue; 1213 | } 1214 | 1215 | ExtractElementInst *EEI = dyn_cast(Inst); 1216 | if (EEI) { 1217 | Value *V = dyn_cast(EEI); 1218 | // TODO 1219 | findUseDefOfCriticalVar(V, cvAddr, pSet, udSet, aliasPtrs); 1220 | continue; 1221 | } 1222 | 1223 | InsertElementInst *IEI = dyn_cast(Inst); 1224 | if (IEI) { 1225 | Value *V = dyn_cast(IEI); 1226 | // TODO 1227 | findUseDefOfCriticalVar(V, cvAddr, pSet, udSet, aliasPtrs); 1228 | continue; 1229 | } 1230 | 1231 | InsertValueInst *IVI = dyn_cast(Inst); 1232 | if (IVI) { 1233 | // TODO 1234 | //Value *V = dyn_cast(IVI); 1235 | //findUseDefOfCriticalVar(V, pSet, udSet); 1236 | continue; 1237 | } 1238 | 1239 | ShuffleVectorInst *SVI = dyn_cast(Inst); 1240 | if (SVI) { 1241 | // TODO 1242 | //Value *V = dyn_cast(SVI); 1243 | //findUseDefOfCriticalVar(V, pSet, udSet); 1244 | continue; 1245 | } 1246 | 1247 | ExtractValueInst *EVI = dyn_cast(Inst); 1248 | if (EVI) { 1249 | // TODO 1250 | //Value *V = dyn_cast(EVI); 1251 | //findUseDefOfCriticalVar(V, pSet, udSet); 1252 | continue; 1253 | } 1254 | 1255 | ReturnInst *RI = dyn_cast(Inst); 1256 | if (RI) { 1257 | // TODO: continue tracking caller? 1258 | continue; 1259 | } 1260 | 1261 | CallInst *CLI = dyn_cast(Inst); 1262 | InvokeInst *II = dyn_cast(Inst); 1263 | if (CLI || II) { 1264 | Value *CaV; 1265 | unsigned numArgCall; 1266 | Value *Arg0; 1267 | 1268 | if (CLI) { 1269 | CaV = CLI->getCalledValue(); 1270 | numArgCall = CLI->getNumArgOperands(); 1271 | if (numArgCall > 0) 1272 | Arg0 = CLI->getArgOperand(0); 1273 | } else { 1274 | CaV = II->getCalledValue(); 1275 | numArgCall = II->getNumArgOperands(); 1276 | if (numArgCall > 0) 1277 | Arg0 = II->getArgOperand(0); 1278 | } 1279 | 1280 | assert(CaV); 1281 | if (CaV == CV) { 1282 | // Used for indirect call, a critical use 1283 | udSet.insert(std::make_pair(Inst, Used)); 1284 | } else { 1285 | // Used as a parameter of the function. 1286 | // We need to further check if this function 1287 | // is a predefined critical function. 1288 | StringRef FName = getCalledFuncName(CaV); 1289 | 1290 | #if DETECT_MEMFUNC_MODIFICATIONS 1291 | auto FIter = Ctx->CriticalFuncs.find(FName.str()); 1292 | if (FIter != Ctx->CriticalFuncs.end()) { 1293 | udSet.insert(std::make_pair(Inst, Used)); 1294 | } else { 1295 | if ((FName.str().compare("get_user") == 0 1296 | || FName.str().compare("__get_user") == 0) 1297 | && Arg0 == CV) { 1298 | udSet.insert(std::make_pair(Inst, Defined)); 1299 | } 1300 | else { 1301 | auto Filter = Ctx->MemWriteFuncs.find(FName.str()); 1302 | if (Filter != Ctx->MemWriteFuncs.end()) 1303 | udSet.insert(std::make_pair(Inst, Used)); 1304 | } 1305 | } 1306 | #endif 1307 | 1308 | // Continue to track CV in callee function. 1309 | // Inter-procedural analysis. 1310 | Function *Callee = AllFuncs[FName]; 1311 | Argument *ArgCV; 1312 | unsigned argNo; 1313 | 1314 | if (!Callee) 1315 | continue; 1316 | 1317 | for (argNo = 0; argNo < numArgCall; argNo++) { 1318 | Value *Arg; 1319 | if (CLI) 1320 | Arg = CLI->getArgOperand(argNo); 1321 | else 1322 | Arg = II->getArgOperand(argNo); 1323 | if (Arg == CV) 1324 | break; 1325 | } 1326 | 1327 | for (Function::arg_iterator AI = Callee->arg_begin(), 1328 | E = Callee->arg_end(); AI != E; ++AI) { 1329 | ArgCV = &*AI; 1330 | if (ArgCV->getArgNo() == argNo) 1331 | break; 1332 | } 1333 | 1334 | findUseDefOfCriticalVar(dyn_cast(ArgCV), NULL, 1335 | pSet, udSet, Ctx->FuncPAResults[Callee]); 1336 | } 1337 | continue; 1338 | } 1339 | 1340 | // TODO: more analyses are required. 1341 | //OP << "== Warning: unsupported LLVM IR when handling uses/defines"; 1342 | //OP << *Inst << "\n"; 1343 | } 1344 | } 1345 | } 1346 | 1347 | static void printSourceCode(unsigned lineno, std::string &src_file) { 1348 | std::ifstream sourcefile(src_file); 1349 | 1350 | unsigned cl = 0; 1351 | 1352 | while(1) { 1353 | std::string line; 1354 | std::getline(sourcefile, line); 1355 | cl++; 1356 | if (cl != lineno) 1357 | continue; 1358 | while(line[0] == ' ' || line[0] == '\t') 1359 | line.erase(line.begin()); 1360 | OP << " [" 1361 | << "\033[34m" << "Src Code" << "\033[0m" << "] " 1362 | << src_file.replace(0, 19, "") << ":" << lineno << ": " 1363 | << "\033[35m" << line << "\033[0m" <<'\n'; 1364 | break; 1365 | } 1366 | } 1367 | 1368 | /// Print out source code information to facilitate manual analyses. 1369 | void CriticalVarPass::printSourceCodeInfo(Instruction *I) { 1370 | if (!I) 1371 | return; 1372 | 1373 | MDNode *N = I->getMetadata("dbg"); 1374 | if (!N) 1375 | return; 1376 | 1377 | DILocation *Loc = dyn_cast(N); 1378 | if (!Loc || Loc->getLine() < 1) 1379 | return; 1380 | 1381 | std::string FN = Loc->getFilename().str(); 1382 | if (FN.find(LINUX_BC_DIR) == 0) { 1383 | FN.replace(0, strlen(LINUX_BC_DIR), LINUX_SOURCE_DIR); 1384 | } 1385 | printSourceCode(Loc->getLine(), FN); 1386 | } 1387 | 1388 | /// Filter out uses before definition. 1389 | void CriticalVarPass::filterUseBeforeDef(std::set &udSet) { 1390 | for (std::set::iterator it_use = udSet.begin(); 1391 | it_use != udSet.end(); ++it_use) { 1392 | InstructionUseDef IUD_U = *it_use; 1393 | if (IUD_U.second == Defined) 1394 | continue; 1395 | 1396 | bool flag = false; 1397 | for (std::set::iterator it_def = udSet.begin(); 1398 | it_def != udSet.end(); ++it_def) { 1399 | InstructionUseDef IUD_D = *it_def; 1400 | if (IUD_D.second == Used) 1401 | continue; 1402 | 1403 | if (possibleUseStResult(IUD_U.first, IUD_D.first)) { 1404 | flag = true; 1405 | break; 1406 | } 1407 | } 1408 | if (!flag) 1409 | udSet.erase(it_use); 1410 | } 1411 | } 1412 | 1413 | void CriticalVarPass::filterDefBeforeCheck(Value *CV, 1414 | std::set &udSet, 1415 | Value *SCheck) { 1416 | Instruction *SCheckInst = dyn_cast(SCheck); 1417 | if (!SCheckInst) 1418 | return; 1419 | 1420 | for (std::set::iterator it_def = udSet.begin(); 1421 | it_def != udSet.end(); ++it_def) { 1422 | InstructionUseDef IUD_D = *it_def; 1423 | if (IUD_D.second == Used) 1424 | continue; 1425 | 1426 | if (possibleUseStResult(SCheckInst, IUD_D.first) || 1427 | !possibleUseStResult(IUD_D.first, SCheckInst)) { 1428 | udSet.erase(it_def); 1429 | } 1430 | } 1431 | } 1432 | 1433 | /// Filter out definitions from the value checked in the 1434 | /// security check. An example: 1435 | /// 1436 | /// if (st->addr_prev == address) 1437 | /// return -EINVAL; 1438 | /// ... /* address is not changed */ 1439 | /// st->addr_prev = address; 1440 | /// 1441 | void CriticalVarPass::filterDefFromCheckedValue( 1442 | Value *CV, 1443 | std::set &udSet, 1444 | Value *SeCheck) { 1445 | 1446 | ICmpInst *ICmp = dyn_cast(SeCheck); 1447 | if (!ICmp) 1448 | return; 1449 | 1450 | for (std::set::iterator it_def = udSet.begin(); 1451 | it_def != udSet.end(); ++it_def) { 1452 | InstructionUseDef IUD_D = *it_def; 1453 | if (IUD_D.second == Used) 1454 | continue; 1455 | 1456 | StoreInst *SI = dyn_cast(IUD_D.first); 1457 | if (!SI) 1458 | continue; 1459 | 1460 | Value *SV = SI->getValueOperand(); 1461 | bool flag = false; 1462 | for (unsigned i = 0; i < ICmp->getNumOperands(); ++i) { 1463 | if (SV == ICmp->getOperand(i)) { 1464 | flag = true; 1465 | break; 1466 | } 1467 | } 1468 | if (flag) 1469 | udSet.erase(it_def); 1470 | } 1471 | } 1472 | 1473 | void CriticalVarPass::trackCalledFunc( 1474 | Function *F, 1475 | Value *SrcAddr, 1476 | std::set &TrackedFunc, 1477 | std::list &ContextInfo, 1478 | std::map> &TrackResults) { 1479 | 1480 | if (!F) 1481 | return; 1482 | 1483 | if (TrackedFunc.count(F) != 0) 1484 | return; 1485 | TrackedFunc.insert(F); 1486 | 1487 | AAResults *AAR = Ctx->FuncAAResults[F]; 1488 | for (inst_iterator i = inst_begin(F), e = inst_end(F); 1489 | i != e; ++i) { 1490 | StoreInst *SI = dyn_cast(&*i); 1491 | if (SI) { 1492 | Value *StAddr = SI->getPointerOperand(); 1493 | Value *StVal = SI->getValueOperand(); 1494 | if (!isConstant(StVal) && 1495 | AAR->alias(MemoryLocation(SrcAddr, 1), 1496 | MemoryLocation(StAddr, 1))) { 1497 | // Continue to track the source of this store. 1498 | std::set TV; 1499 | TV.clear(); 1500 | Value *SrcVal = trackSrcOfVal(F, StVal, TV); 1501 | if (SrcVal) { 1502 | // Save context information. 1503 | ContextInfo.push_back(&*i); 1504 | findSrcForModification(F, SI, ContextInfo, TrackResults); 1505 | ContextInfo.pop_back(); 1506 | } 1507 | } 1508 | } 1509 | CallInst *CI = dyn_cast(&*i); 1510 | if (CI) { 1511 | StringRef FuncName = getCalledFuncName(CI->getCalledValue()); 1512 | auto FIter = Ctx->MemWriteFuncs.find(FuncName.str()); 1513 | if (FIter != Ctx->MemWriteFuncs.end()) { 1514 | Value *Arg = CI->getArgOperand(FIter->second); 1515 | if (AAR->alias(MemoryLocation(SrcAddr, 1), 1516 | MemoryLocation(Arg, 1))) { 1517 | // Save this tracking result. 1518 | if (FuncName.contains("get_user") || 1519 | FuncName.contains("copy_from_user") || 1520 | FuncName.contains("strncpy_from_user")) { 1521 | TrackResults[&*i] = ContextInfo; 1522 | } else { 1523 | // Save context information. 1524 | ContextInfo.push_back(&*i); 1525 | // Continue to track the src address. 1526 | findSrcForModification(F, CI, ContextInfo, TrackResults); 1527 | ContextInfo.pop_back(); 1528 | } 1529 | } 1530 | } else { 1531 | Function *CF = CI->getCalledFunction(); 1532 | 1533 | ContextInfo.push_back(&*i); 1534 | 1535 | if (CF) { 1536 | trackCalledFunc(CF, SrcAddr, TrackedFunc, ContextInfo, TrackResults); 1537 | } else { 1538 | for (Function *Callee : Ctx->Callees[CI]) 1539 | trackCalledFunc(Callee, SrcAddr, TrackedFunc, ContextInfo, TrackResults); 1540 | } 1541 | 1542 | ContextInfo.pop_back(); 1543 | } 1544 | } 1545 | // TODO: support more IR types. 1546 | } 1547 | } 1548 | 1549 | Value *CriticalVarPass::trackSrcOfVal( 1550 | Function *F, 1551 | Value *V, 1552 | std::set &trackedVal) { 1553 | 1554 | if (!V) 1555 | return NULL; 1556 | 1557 | if (trackedVal.count(V) != 0) 1558 | return NULL; 1559 | trackedVal.insert(V); 1560 | 1561 | if (isConstant(V)) 1562 | return NULL; 1563 | 1564 | CallInst *CI = dyn_cast(V); 1565 | if (CI) 1566 | return NULL; 1567 | 1568 | ICmpInst *ICI = dyn_cast(V); 1569 | if (ICI) 1570 | return NULL; 1571 | 1572 | if (isFunctionParameter(V, F)) 1573 | return NULL; 1574 | 1575 | LoadInst *LI = dyn_cast(V); 1576 | if (LI) 1577 | return LI; 1578 | 1579 | UnaryInstruction *UI = dyn_cast(V); 1580 | if (UI) 1581 | return trackSrcOfVal(F, UI->getOperand(0), trackedVal); 1582 | 1583 | GetElementPtrInst *GEP = dyn_cast(V); 1584 | if (GEP) 1585 | return trackSrcOfVal(F, GEP->getPointerOperand(), trackedVal); 1586 | 1587 | InsertValueInst *IVI = dyn_cast(V); 1588 | if (IVI) { 1589 | Value *IV = trackSrcOfVal(F, IVI->getInsertedValueOperand(), 1590 | trackedVal); 1591 | if (IV) 1592 | return IV; 1593 | return NULL; 1594 | } 1595 | 1596 | PHINode *PN = dyn_cast(V); 1597 | if (PN) { 1598 | // TODO: support all of them. 1599 | for (unsigned i = 0, e = PN->getNumIncomingValues(); 1600 | i != e; ++i) { 1601 | Value *SV = trackSrcOfVal(F, PN->getIncomingValue(i), trackedVal); 1602 | if (SV) 1603 | return SV; 1604 | } 1605 | return NULL; 1606 | } 1607 | 1608 | SelectInst *SI = dyn_cast(V); 1609 | if (SI) { 1610 | Value *TV = trackSrcOfVal(F, SI->getTrueValue(), trackedVal); 1611 | Value *FV = trackSrcOfVal(F, SI->getFalseValue(), trackedVal); 1612 | 1613 | // TODO: support both of them. 1614 | if (TV) 1615 | return TV; 1616 | if (FV) 1617 | return FV; 1618 | 1619 | return NULL; 1620 | } 1621 | 1622 | BinaryOperator *BO = dyn_cast(V); 1623 | if (BO) { 1624 | // TODO: support all of them. 1625 | for (unsigned i = 0, e = BO->getNumOperands(); 1626 | i != e; ++i) { 1627 | Value *SV = trackSrcOfVal(F, BO->getOperand(i), trackedVal); 1628 | if (SV) 1629 | return SV; 1630 | } 1631 | return NULL; 1632 | } 1633 | 1634 | OP << "== Warning: unsupported LLVM IR in trackSrcOfVal:" 1635 | << *V << "\n"; 1636 | 1637 | return NULL; 1638 | } 1639 | 1640 | void CriticalVarPass::trackSrc( 1641 | Function *F, 1642 | Instruction *Inst, 1643 | Value *SrcAddr, 1644 | std::set &TrackedFunc, 1645 | std::list &ContextInfo, 1646 | std::map> &TrackResults) { 1647 | 1648 | if (!Inst || !SrcAddr) 1649 | return; 1650 | 1651 | if (TrackedFunc.count(F) != 0) 1652 | return; 1653 | TrackedFunc.insert(F); 1654 | 1655 | Instruction *TI = Inst->getPrevNode(); 1656 | AAResults *AAR = Ctx->FuncAAResults[F]; 1657 | std::set TrackedBB; 1658 | std::list ToBeTrackedBB; 1659 | 1660 | TrackedBB.clear(); 1661 | ToBeTrackedBB.clear(); 1662 | 1663 | TrackedBB.insert(Inst->getParent()); 1664 | for (BasicBlock *Pred : predecessors(Inst->getParent())) 1665 | ToBeTrackedBB.push_back(Pred); 1666 | 1667 | while (TI || !ToBeTrackedBB.empty()) { 1668 | while(TI) { 1669 | // This is a store instruction. 1670 | // Check if it writes the source address. 1671 | StoreInst *TSI = dyn_cast(TI); 1672 | if (TSI) { 1673 | Value *StAddr = TSI->getPointerOperand(); 1674 | Value *StVal = TSI->getValueOperand(); 1675 | if (!isConstant(StVal) && 1676 | AAR->alias(MemoryLocation(SrcAddr, 1), 1677 | MemoryLocation(StAddr, 1))) { 1678 | // Continue to track the source of this store. 1679 | std::set TV; 1680 | TV.clear(); 1681 | Value *SrcVal = trackSrcOfVal(F, StVal, TV); 1682 | if (SrcVal) { 1683 | // Save context information. 1684 | ContextInfo.push_back(TI); 1685 | findSrcForModification(F, dyn_cast(SrcVal), 1686 | ContextInfo, TrackResults); 1687 | ContextInfo.pop_back(); 1688 | } 1689 | } 1690 | } 1691 | 1692 | // This is a call instruction. 1693 | // Check whether the called function writes the SrcAddr. 1694 | // If yes, we report it. Otherwise, we should continue 1695 | // to track the called function. 1696 | CallInst *TCI = dyn_cast(TI); 1697 | if (TCI) { 1698 | StringRef FuncName = getCalledFuncName(TCI->getCalledValue()); 1699 | auto FIter = Ctx->MemWriteFuncs.find(FuncName.str()); 1700 | if (FIter != Ctx->MemWriteFuncs.end()) { 1701 | Value *Arg = TCI->getArgOperand(FIter->second); 1702 | if (AAR->alias(MemoryLocation(SrcAddr, 1), 1703 | MemoryLocation(Arg, 1))) { 1704 | // Save this tracking result. 1705 | if (FuncName.contains("get_user") || 1706 | FuncName.contains("copy_from_user") || 1707 | FuncName.contains("strncpy_from_user")) { 1708 | TrackResults[TCI] = ContextInfo; 1709 | } else { 1710 | // Save context information. 1711 | ContextInfo.push_back(TI); 1712 | // Continue to track the src address. 1713 | findSrcForModification(F, TCI, ContextInfo, TrackResults); 1714 | ContextInfo.pop_back(); 1715 | } 1716 | } 1717 | } else { 1718 | Function *TCF = TCI->getCalledFunction(); 1719 | 1720 | ContextInfo.push_back(TI); 1721 | 1722 | if (TCF) { 1723 | trackCalledFunc(TCF, SrcAddr, TrackedFunc, ContextInfo, TrackResults); 1724 | } else { 1725 | for (Function *Callee : Ctx->Callees[TCI]) { 1726 | trackCalledFunc(Callee, SrcAddr, TrackedFunc, ContextInfo, TrackResults); 1727 | } 1728 | } 1729 | 1730 | ContextInfo.pop_back(); 1731 | } 1732 | } 1733 | 1734 | // Check the previous instruction. 1735 | TI = TI->getPrevNode(); 1736 | } 1737 | 1738 | // Continue to track predecessor blocks. 1739 | while (!ToBeTrackedBB.empty()) { 1740 | BasicBlock *TBB = ToBeTrackedBB.front(); 1741 | 1742 | ToBeTrackedBB.pop_front(); 1743 | if (TrackedBB.count(TBB) != 0) 1744 | continue; 1745 | TrackedBB.insert(TBB); 1746 | 1747 | for (BasicBlock *Pred : predecessors(TBB)) 1748 | ToBeTrackedBB.push_back(Pred); 1749 | 1750 | TI = &(TBB->back()); 1751 | break; 1752 | } 1753 | } 1754 | } 1755 | 1756 | /// Try to find out where the source come from for this modification. 1757 | /// Inst is a modification to a critical variable in F. 1758 | void CriticalVarPass::findSrcForModification( 1759 | Function *F, 1760 | Instruction *Inst, 1761 | std::list &ContextInfo, 1762 | std::map> &TrackResults) { 1763 | 1764 | Value *SrcAddr = NULL; 1765 | 1766 | // FIXME: Limit the number of tracked addresses?? 1767 | if (TrackedAddr.size() > NUM_ADDRESSES_TO_TRACK) 1768 | return; 1769 | 1770 | CallInst *CI = dyn_cast(Inst); 1771 | if (CI) { 1772 | StringRef FuncName = getCalledFuncName(CI->getCalledValue()); 1773 | unsigned SrcIndex = 1; 1774 | 1775 | // If the function is bcopy, the index of the source argument is 0. 1776 | if (FuncName.str().compare("bcopy") == 0) 1777 | SrcIndex = 0; 1778 | 1779 | SrcAddr = CI->getArgOperand(SrcIndex); 1780 | } 1781 | 1782 | StoreInst *SI = dyn_cast(Inst); 1783 | if (SI) { 1784 | SrcAddr = SI->getPointerOperand(); 1785 | } 1786 | 1787 | LoadInst *LI = dyn_cast(Inst); 1788 | if (LI) { 1789 | SrcAddr = LI->getPointerOperand(); 1790 | } 1791 | 1792 | if (!SrcAddr) { 1793 | OP << "== Warning: unsupported inst type of modification...\n"; 1794 | return; 1795 | } 1796 | 1797 | 1798 | if (TrackedAddr.count(SrcAddr) != 0) 1799 | return; 1800 | TrackedAddr.insert(SrcAddr); 1801 | 1802 | // Save context information. 1803 | ContextInfo.push_back(Inst); 1804 | 1805 | // Find the latest store to the source address. 1806 | // Firstly, try to find the latest store in the current function. 1807 | // If we cannot find it, we need to continue to track the caller 1808 | // function(s) of the current function. 1809 | std::list> CallerList; 1810 | std::set TrackedFunc; 1811 | 1812 | CallerList.clear(); 1813 | TrackedFunc.clear(); 1814 | 1815 | CallerList.push_back(std::make_pair(F, Inst)); 1816 | 1817 | while(!CallerList.empty()) { 1818 | std::pair FI = CallerList.front(); 1819 | 1820 | CallerList.pop_front(); 1821 | 1822 | trackSrc(FI.first, FI.second, SrcAddr, TrackedFunc, 1823 | ContextInfo, TrackResults); 1824 | 1825 | // FIXME: what is the termination condition?? 1826 | if (TrackedFunc.size() > NUM_FUNCTIONS_TO_TRACK) 1827 | break; 1828 | 1829 | // Continue to track caller functions. 1830 | for (auto CIS : Ctx->Callers[FI.first]) { 1831 | Function *CallerFunc = CIS->getFunction(); 1832 | if (!CallerFunc) 1833 | continue; 1834 | 1835 | CallerList.push_back(std::make_pair(CallerFunc, CIS)); 1836 | } 1837 | } 1838 | } 1839 | 1840 | void CriticalVarPass::printSourceCodeInfo(Value *V) { 1841 | Instruction *Inst = dyn_cast(V); 1842 | 1843 | if (Inst) 1844 | printSourceCodeInfo(Inst); 1845 | } 1846 | 1847 | /// Find the dominating check that, upon failures, will always 1848 | /// result in an error code in the returned value 1849 | Instruction * CriticalVarPass::findDominatingCheck(Value *RV) { 1850 | 1851 | return NULL; 1852 | } 1853 | 1854 | /// Find the checked variable or function 1855 | Value * CriticalVarPass::findCheckedValue(Instruction *CI) { 1856 | 1857 | return NULL; 1858 | } 1859 | 1860 | bool CriticalVarPass::doInitialization(Module *M) { 1861 | // Collect function name to function definition map. 1862 | // XXX: different modules may have functions with same name. 1863 | for (Function &F : *M) { 1864 | StringRef FName = F.getName(); 1865 | if (!F.empty()) 1866 | AllFuncs[FName] = &F; 1867 | } 1868 | 1869 | sc_counter = 0; 1870 | cuc_counter = 0; 1871 | lcc_counter = 0; 1872 | cv_set.clear(); 1873 | 1874 | return false; 1875 | } 1876 | 1877 | bool CriticalVarPass::doFinalization(Module *M) { 1878 | return false; 1879 | } 1880 | 1881 | bool CriticalVarPass::doModulePass(Module *M) { 1882 | for(Module::iterator f = M->begin(), fe = M->end(); 1883 | f != fe; ++f) { 1884 | Function *F = &*f; 1885 | 1886 | if (F->empty()) 1887 | continue; 1888 | 1889 | // Marked edges in the CFG. It tells if an errno is sure or maybe returned 1890 | // on this edge. The index is the edge, i.e., the terminator instruction and 1891 | // the index of the successor of the terminator instruction. This data structure 1892 | // may need to be promoted to CriticalVarPass. 1893 | EdgeErrnoFlag errnoEdges; 1894 | std::set securityChecks; // Set of security checks. 1895 | std::map> CheckToVars; // Map from security checks to critical variables. 1896 | 1897 | errnoEdges.clear(); 1898 | securityChecks.clear(); 1899 | CheckToVars.clear(); 1900 | 1901 | // Check all return instructions in this function and mark 1902 | // edges that are sure to return an errno. 1903 | for (inst_iterator i = inst_begin(F), e = inst_end(F); 1904 | i != e; ++i) { 1905 | ReturnInst *RI = dyn_cast(&*i); 1906 | Value *RV; 1907 | 1908 | if (!RI) 1909 | continue; 1910 | 1911 | RV = RI->getReturnValue(); 1912 | if (!RV) 1913 | continue; 1914 | 1915 | #ifdef DEBUG_PRINT 1916 | OP << "\n== Working on function: " 1917 | << "\033[32m" << F->getName() << "\033[0m" << '\n'; 1918 | #endif 1919 | 1920 | checkReturnValue(F, RI->getParent(), RV, errnoEdges); 1921 | 1922 | if (errnoEdges.size() > 0) { 1923 | #ifdef DEBUG_PRINT 1924 | OP << "\n== An errno may be returned in function " 1925 | << "\033[32m" << F->getName() << "\033[0m" << '\n'; 1926 | #endif 1927 | 1928 | //dumpEdges(errnoEdges); 1929 | } 1930 | } 1931 | 1932 | // Skip this function if it does not return errno. 1933 | if (errnoEdges.empty()) 1934 | continue; 1935 | 1936 | // Traverse the CFG and find security checks for each errno. 1937 | findSecurityChecks(F, errnoEdges, securityChecks); 1938 | 1939 | // Skip this function if there is no security check. 1940 | if (securityChecks.empty()) 1941 | continue; 1942 | 1943 | sc_counter += securityChecks.size(); 1944 | //OP << "== number of security checks: " << sc_counter << "\n"; 1945 | 1946 | #ifdef DEBUG_PRINT 1947 | OP << "== number of security checks: " << securityChecks.size() << "\n"; 1948 | for (std::set::iterator it = securityChecks.begin(), 1949 | ie = securityChecks.end(); it != ie; ++it) { 1950 | Value *SC = *it; 1951 | OP << "\n== Security check: " << *SC << "\n"; 1952 | printSourceCodeInfo(dyn_cast(SC)); 1953 | } 1954 | #endif 1955 | 1956 | // Identify critical variables/functions used in each security check. 1957 | identifyCriticalVariables(F, securityChecks, CheckToVars); 1958 | 1959 | filterNonGlobalVariables(CheckToVars); 1960 | 1961 | // Skip this function if there is no critical variable. 1962 | if (CheckToVars.empty()) 1963 | continue; 1964 | 1965 | // Detect aliased pointers in this function. 1966 | PointerAnalysisMap &aliasPtrs = Ctx->FuncPAResults[F]; 1967 | 1968 | // Find out all instructions using the critical variables. 1969 | for (std::map>::iterator 1970 | it = CheckToVars.begin(), eit = CheckToVars.end(); 1971 | it != eit; ++it) { 1972 | Value *SCheck = it->first; 1973 | std::set cvSet = it->second; 1974 | 1975 | // Find defs (motifications) to the critical variables 1976 | for (std::set::iterator cit = cvSet.begin(); 1977 | cit != cvSet.end(); ++cit) { 1978 | Value *CV = *cit; 1979 | Value *cvAddr = NULL; 1980 | std::set pSet; 1981 | std::set udSet; 1982 | 1983 | cv_set.insert(CV); 1984 | 1985 | pSet.clear(); 1986 | udSet.clear(); 1987 | 1988 | // Handle critical variables loaded from memory. 1989 | try { 1990 | LoadInst *LI = dyn_cast(CV); 1991 | if (LI) { 1992 | cvAddr = LI->getPointerOperand(); 1993 | findUseDefFromCVAddr(F, cvAddr, pSet, udSet, aliasPtrs); 1994 | } 1995 | 1996 | findUseDefOfCriticalVar(CV, cvAddr, pSet, udSet, aliasPtrs); 1997 | } 1998 | catch (const std::exception& e) { 1999 | std::cout << e.what(); 2000 | continue; 2001 | } 2002 | 2003 | #ifdef DEBUG_PRINT 2004 | OP << "== CV:" << *CV << '\n'; 2005 | OP << "== udSet size: " << udSet.size() << "\n"; 2006 | if (dyn_cast(CV)) 2007 | printSourceCodeInfo(dyn_cast(CV)); 2008 | #endif 2009 | 2010 | filterDefBeforeCheck(CV, udSet, SCheck); 2011 | 2012 | filterDefFromCheckedValue(CV, udSet, SCheck); 2013 | 2014 | bool hasUse = false, hasDefine = false; 2015 | for (std::set::iterator it = udSet.begin(); 2016 | it != udSet.end(); ++it) { 2017 | if (hasUse && hasDefine) 2018 | break; 2019 | InstructionUseDef IUD = *it; 2020 | if (IUD.second == Used) 2021 | hasUse = true; 2022 | else 2023 | hasDefine = true; 2024 | } 2025 | 2026 | cuc_counter++; 2027 | 2028 | if (!hasDefine) 2029 | continue; 2030 | 2031 | lcc_counter++; 2032 | 2033 | OP << "\n== Critical Variable [" << lcc_counter << " / " 2034 | << cuc_counter << "]: " << "\033[33m" << *CV << "\033[0m" 2035 | << " (in function: \033[32m" << F->getName() << "\033[0m)" << '\n'; 2036 | printSourceCodeInfo(CV); 2037 | OP << "== Security Check: " << "\033[33m" << *SCheck << "\033[0m\n"; 2038 | printSourceCodeInfo(SCheck); 2039 | for (std::set::iterator it = udSet.begin(); 2040 | it != udSet.end(); ++it) { 2041 | InstructionUseDef IUD = *it; 2042 | Instruction *Inst = IUD.first; 2043 | 2044 | OP << '\n' 2045 | << ((IUD.second == Used) ? " Used by " : " Defined by ") 2046 | << *Inst << '\n'; 2047 | if (Inst->getFunction()) { 2048 | OP << " [" 2049 | << "\033[34m" << "Func Name" << "\033[0m" << "] " 2050 | << "\033[32m" << Inst->getFunction()->getName() << "\033[0m"; 2051 | } 2052 | OP << '\n'; 2053 | printSourceCodeInfo(Inst); 2054 | 2055 | #if ENABLE_SOURCE_TRACKING 2056 | if (IUD.second != Defined) 2057 | continue; 2058 | 2059 | std::map> TrackResults; 2060 | std::list ContextInfo; 2061 | 2062 | TrackResults.clear(); 2063 | TrackedAddr.clear(); 2064 | ContextInfo.clear(); 2065 | 2066 | findSrcForModification(F, Inst, ContextInfo, TrackResults); 2067 | unsigned tcounter = 1; 2068 | for (std::map>::iterator 2069 | it = TrackResults.begin(); it != TrackResults.end(); ++it) { 2070 | Instruction *Inst = it->first; 2071 | std::list ConInfo = it->second; 2072 | OP << " ============= [" << tcounter++ 2073 | << "] Tracking Result =============\n"; 2074 | unsigned ccounter = 1; 2075 | for (std::list::iterator cit = ConInfo.begin(); 2076 | cit != ConInfo.end(); ++cit) { 2077 | Instruction *ConInst = *cit; 2078 | OP << " == ContextInfo [" << ccounter++ << "] " 2079 | << *ConInst << "\n"; 2080 | OP << " in function: " 2081 | << ConInst->getFunction()->getName() << "\n"; 2082 | printSourceCodeInfo(ConInst); 2083 | } 2084 | OP << " == The source is finally defined here: \033[33m" 2085 | << *Inst << "\033[0m\n"; 2086 | OP << " in function: " 2087 | << Inst->getFunction()->getName() << "\n"; 2088 | printSourceCodeInfo(Inst); 2089 | } 2090 | #endif 2091 | } 2092 | } 2093 | } 2094 | } 2095 | 2096 | #ifdef DEBUG_PRINT 2097 | OP << "== Number of critical variables: " << cv_set.size() << "\n"; 2098 | #endif 2099 | 2100 | return false; 2101 | } 2102 | --------------------------------------------------------------------------------