├── .clang-format ├── .github └── workflows │ ├── build.yml │ └── docker-publish-x86.yml ├── .gitignore ├── .vscode ├── c_cpp_properties.json ├── launch.json ├── settings.json └── tasks.json ├── Assignment-1 ├── CPP │ ├── Assignment_1.cpp │ ├── Assignment_1.h │ ├── CMakeLists.txt │ └── test.cpp ├── Python │ ├── Assignment_1.py │ ├── Assignment_1_Helper.py │ ├── CMakeLists.txt │ └── test.py └── Tests │ ├── SrcSnk.txt │ └── testcases │ ├── icfg │ ├── test1.c │ ├── test1.ll │ ├── test2.c │ └── test2.ll │ ├── pta │ ├── test1.c │ ├── test1.ll │ ├── test2.c │ ├── test2.ll │ ├── test3.c │ ├── test3.ll │ ├── test4.c │ └── test4.ll │ └── taint │ ├── test1.c │ ├── test1.ll │ ├── test2.c │ └── test2.ll ├── Assignment-2 ├── CPP │ ├── Assignment_2.cpp │ ├── Assignment_2.h │ ├── CMakeLists.txt │ ├── Z3SSEMgr.cpp │ ├── Z3SSEMgr.h │ └── test-sse.cpp ├── Python │ ├── Assignment_2.py │ ├── CMakeLists.txt │ ├── Z3SSEMgr.py │ └── test-sse.py └── Tests │ └── testcases │ └── sse │ ├── test1.c │ ├── test1.ll │ ├── test2.c │ ├── test2.ll │ ├── test3.c │ └── test3.ll ├── Assignment-3 ├── CPP │ ├── Assignment_3.cpp │ ├── Assignment_3.h │ ├── Assignment_3_Helper.cpp │ ├── Assignment_3_Helper.h │ ├── CMakeLists.txt │ └── test-ae.cpp ├── Python │ ├── Assignment_3.py │ ├── Assignment_3_Helper.py │ ├── CMakeLists.txt │ └── test-ae.py └── Tests │ ├── ae │ ├── test1.c │ ├── test1.ll │ ├── test2.c │ ├── test2.ll │ ├── test3.c │ ├── test3.ll │ ├── test4.c │ └── test4.ll │ └── buf │ ├── test1.c │ ├── test1.ll │ ├── test2.c │ ├── test2.ll │ ├── test3.c │ ├── test3.ll │ ├── test4.c │ ├── test4.ll │ ├── test5.c │ ├── test5.ll │ ├── test6.c │ └── test6.ll ├── CMakeLists.txt ├── Dockerfile ├── HelloWorld ├── CMakeLists.txt ├── hello.cpp └── hello.py ├── LICENSE ├── Lab-Exercise-1 ├── CMakeLists.txt ├── CPP │ ├── GraphAlgorithm.cpp │ ├── GraphAlgorithm.h │ └── test.cpp └── Python │ └── GraphAlgorithm.ipynb ├── Lab-Exercise-2 ├── CMakeLists.txt ├── CPP │ ├── Z3Examples.cpp │ ├── Z3Examples.h │ ├── Z3Mgr.cpp │ ├── Z3Mgr.h │ └── test.cpp └── Python │ └── Z3Examples.ipynb ├── Lab-Exercise-3 ├── CMakeLists.txt ├── CPP │ ├── AEMgr.cpp │ ├── AEMgr.h │ └── test.cpp └── Python │ └── AEMgr.ipynb ├── README.md ├── SVFIR ├── CMakeLists.txt ├── SVFIR.cpp ├── compile.sh ├── overflow │ ├── branch.c │ ├── branch_safe.c │ ├── interprocedural.c │ ├── interprocedural_safe.c │ ├── loop_1.c │ ├── loop_2.c │ ├── loop_3.c │ ├── struct_and_array_1.c │ ├── struct_and_array_2.c │ └── struct_and_array_safe.c └── src │ ├── andersen.c │ ├── branch.c │ ├── control-flow.c │ ├── demo.c │ ├── example.c │ ├── interprocedural.c │ └── swap.c ├── build.sh └── env.sh /.clang-format: -------------------------------------------------------------------------------- 1 | Language: Cpp 2 | Standard: Cpp11 3 | AccessModifierOffset: -3 4 | AlignAfterOpenBracket: Align 5 | AlignConsecutiveAssignments: false 6 | AlignConsecutiveDeclarations: false 7 | AlignConsecutiveMacros: false 8 | AlignEscapedNewlines: Right 9 | AlignOperands: true 10 | AlignTrailingComments: false 11 | AllowAllArgumentsOnNextLine: false 12 | AllowAllConstructorInitializersOnNextLine: false 13 | AllowAllParametersOfDeclarationOnNextLine: false 14 | AllowShortBlocksOnASingleLine: false 15 | AllowShortCaseLabelsOnASingleLine: true 16 | AllowShortFunctionsOnASingleLine: Empty 17 | AllowShortIfStatementsOnASingleLine: false 18 | AllowShortLambdasOnASingleLine: All 19 | AllowShortLoopsOnASingleLine: false 20 | AlwaysBreakAfterReturnType: None 21 | AlwaysBreakBeforeMultilineStrings: false 22 | AlwaysBreakTemplateDeclarations: Yes 23 | BinPackArguments: false 24 | BinPackParameters: false 25 | BreakBeforeBinaryOperators: NonAssignment 26 | BreakBeforeBraces: Custom 27 | BraceWrapping: 28 | AfterCaseLabel: false 29 | AfterClass: false 30 | AfterControlStatement: MultiLine 31 | AfterEnum: false 32 | AfterFunction: false 33 | AfterNamespace: false 34 | AfterStruct: false 35 | AfterUnion: false 36 | AfterExternBlock: false 37 | BeforeCatch: false 38 | BeforeElse: true 39 | BeforeLambdaBody: false 40 | IndentBraces: false 41 | SplitEmptyFunction: false 42 | SplitEmptyRecord: false 43 | SplitEmptyNamespace: false 44 | BreakBeforeTernaryOperators: true 45 | BreakConstructorInitializers: BeforeComma 46 | BreakInheritanceList: BeforeComma 47 | BreakStringLiterals: true 48 | ColumnLimit: 120 49 | CompactNamespaces: true 50 | ConstructorInitializerAllOnOneLineOrOnePerLine: false 51 | ConstructorInitializerIndentWidth: 0 52 | ContinuationIndentWidth: 4 53 | Cpp11BracedListStyle: true 54 | FixNamespaceComments: true 55 | IncludeBlocks: Preserve 56 | IncludeCategories: 57 | - Regex: "^<[[:alnum:].]+>" 58 | Priority: 2 59 | - Regex: '^"[[:alnum:].]"' 60 | Priority: 1 61 | IndentCaseBlocks: false 62 | IndentCaseLabels: false 63 | IndentGotoLabels: false 64 | IndentPPDirectives: AfterHash 65 | IndentWidth: 4 66 | IndentWrappedFunctionNames: false 67 | KeepEmptyLinesAtTheStartOfBlocks: false 68 | MaxEmptyLinesToKeep: 1 69 | NamespaceIndentation: All 70 | PenaltyBreakAssignment: 10 71 | PenaltyBreakBeforeFirstCallParameter: 10 72 | PenaltyBreakComment: 10 73 | PenaltyBreakFirstLessLess: 10 74 | PenaltyBreakString: 10 75 | PenaltyBreakTemplateDeclaration: 10 76 | PenaltyExcessCharacter: 10 77 | PenaltyReturnTypeOnItsOwnLine: 10 78 | PointerAlignment: Left 79 | ReflowComments: true 80 | SortIncludes: true 81 | SortUsingDeclarations: true 82 | SpaceAfterCStyleCast: false 83 | SpaceAfterLogicalNot: false 84 | SpaceAfterTemplateKeyword: false 85 | SpaceBeforeAssignmentOperators: true 86 | SpaceBeforeCpp11BracedList: false 87 | SpaceBeforeCtorInitializerColon: true 88 | SpaceBeforeInheritanceColon: true 89 | SpaceBeforeParens: ControlStatements 90 | SpaceBeforeRangeBasedForLoopColon: true 91 | SpaceBeforeSquareBrackets: false 92 | SpaceInEmptyBlock: false 93 | SpaceInEmptyParentheses: false 94 | SpacesBeforeTrailingComments: 1 95 | SpacesInAngles: false 96 | SpacesInCStyleCastParentheses: false 97 | SpacesInConditionalStatement: false 98 | SpacesInContainerLiterals: false 99 | SpacesInParentheses: false 100 | SpacesInSquareBrackets: false 101 | TabWidth: 4 102 | UseCRLF: false 103 | UseTab: ForIndentation -------------------------------------------------------------------------------- /.github/workflows/build.yml: -------------------------------------------------------------------------------- 1 | name: build 2 | 3 | # Triggers the workflow on push or pull request events 4 | on: [push, pull_request] 5 | 6 | jobs: 7 | build: 8 | runs-on: ${{ matrix.os }} 9 | strategy: 10 | matrix: 11 | os: [ubuntu-latest, macos-latest] 12 | env: 13 | XCODE_VERSION: '16.0.0' 14 | steps: 15 | # checkout the repo 16 | - uses: actions/checkout@v2 17 | - uses: actions/setup-node@v3 18 | with: 19 | node-version: 18 20 | 21 | # setup the mac/ubuntu environment 22 | - name: mac-setup 23 | if: runner.os == 'macOS' 24 | uses: maxim-lobanov/setup-xcode@v1 25 | with: 26 | xcode-version: ${{ env.XCODE_VERSION }} 27 | - name: mac-setup-workaround 28 | if: runner.os == 'macOS' 29 | run: ln -sfn /Applications/Xcode_${{ env.XCODE_VERSION }}.app /Applications/Xcode.app 30 | - name: ubuntu-setup 31 | if: runner.os == 'Linux' 32 | run: | 33 | sudo apt-get update 34 | sudo add-apt-repository -y ppa:ubuntu-toolchain-r/test 35 | sudo apt-get update 36 | sudo apt-get install cmake gcc g++ nodejs doxygen graphviz lcov libncurses5-dev libtinfo6 libzstd-dev 37 | 38 | # install llvm and svf 39 | - name: env-setup 40 | run: | 41 | npm install svf-lib 42 | # set SVF_DIR, LLVM_DIR and Z3_DIR and build 43 | - name: build 44 | run: | 45 | export SVF_DIR=$(npm root)/SVF 46 | export LLVM_DIR=$(npm root)/llvm-16.0.0.obj 47 | export Z3_DIR=$(npm root)/z3.obj 48 | echo "SVF_DIR="$SVF_DIR 49 | echo "LLVM_DIR="$LLVM_DIR 50 | echo "Z3_DIR="$Z3_DIR 51 | cmake . 52 | make 53 | -------------------------------------------------------------------------------- /.github/workflows/docker-publish-x86.yml: -------------------------------------------------------------------------------- 1 | name: Docker 2 | 3 | on: 4 | push: 5 | branches: [ main ] 6 | repository_dispatch: 7 | types: [ new-commit-from-SVF ] 8 | jobs: 9 | docker-image: 10 | if: github.repository == 'SVF-tools/Software-Security-Analysis' 11 | runs-on: ubuntu-latest 12 | 13 | steps: 14 | - name: Checkout 15 | uses: actions/checkout@v2 16 | - name: Login to Docker Hub 17 | uses: docker/login-action@v1 18 | with: 19 | username: ${{ secrets.DOCKER_USER }} 20 | password: ${{ secrets.DOCKER_PASSWD }} 21 | - name: Set up QEMU (Support ARM64) 22 | uses: docker/setup-qemu-action@v2 23 | - name: Set up Docker Buildx 24 | uses: docker/setup-buildx-action@v2 25 | - name: Build and push x86 and ARM64 images 26 | uses: docker/build-push-action@v2 27 | with: 28 | context: . 29 | file: ./Dockerfile 30 | push: true 31 | platforms: linux/amd64,linux/arm64 32 | tags: | 33 | ${{secrets.DOCKER_USER}}/software-security-analysis:latest 34 | ${{secrets.DOCKER_USER}}/software-security-analysis:latest-arm64 35 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | Release*/ 2 | Debug*/ 3 | build/ 4 | html/ 5 | Test-Suite 6 | Release+Asserts/ 7 | Debug+Asserts/ 8 | autoconf/ 9 | tests/result/ 10 | doxygen/ 11 | !.github/ 12 | !.vscode/ 13 | !.config.in 14 | !.config.cmake.in 15 | !.gitignore 16 | *~ 17 | *.o 18 | *.ll 19 | !Assignment-1/Tests/testcases/*/*.ll 20 | !Assignment-2/Tests/testcases/*.ll 21 | *.dot 22 | *.out 23 | *.bc 24 | *.opt 25 | *.log 26 | *.status 27 | *.obj 28 | *.svf 29 | *.cmake 30 | MakeFile 31 | CMakeFiles 32 | CMakeCache.txt 33 | *.tcl 34 | bin 35 | lib 36 | Testing 37 | *.sh 38 | cmake-build-debug/ 39 | compile_commands.json 40 | -------------------------------------------------------------------------------- /.vscode/c_cpp_properties.json: -------------------------------------------------------------------------------- 1 | { 2 | "configurations": [ 3 | { 4 | "name": "Linux", 5 | "includePath": [ 6 | "/usr/local/include/**", 7 | "${workspaceFolder}/**", 8 | "../SVF/**" 9 | ], 10 | "defines": [], 11 | "compilerPath": "/usr/bin/g++", 12 | "cStandard": "gnu11", 13 | "cppStandard": "gnu++17", 14 | "intelliSenseMode": "linux-gcc-x64" 15 | } 16 | ], 17 | "version": 4 18 | } -------------------------------------------------------------------------------- /.vscode/launch.json: -------------------------------------------------------------------------------- 1 | { 2 | "version": "0.2.0", 3 | "configurations": [ 4 | { 5 | "name": "(debug) Launch C++", 6 | "type": "cppdbg", 7 | "request": "launch", 8 | // Please change to the executable of your current lab or assignment 9 | // | Lab/Assignment | "program" | "args" | 10 | // | Lab-Exercise-1 | "${workspaceFolder}/bin/lab1" | "test1" | 11 | // | Lab-Exercise-2 | "${workspaceFolder}/bin/lab2" | "test1" | 12 | // | Lab-Exercise-3 | "${workspaceFolder}/bin/lab3" | "test1" | 13 | // | Assignment-1 | "${workspaceFolder}/bin/ass1" | "-icfg", "Assignment-1/Tests/testcases/icfg/test1.ll" | 14 | // | Assignment-2 | "${workspaceFolder}/bin/ass2" | "Assignment-2/Tests/testcases/sse/test1.ll" | 15 | // | Assignment-3 | "${workspaceFolder}/bin/ass3" | "Assignment-3/Tests/ae/test1.ll" | 16 | "program": "${workspaceFolder}/bin/hello", 17 | "args": [], // may input the test llvm bc file or other options and flags the program may use 18 | "cwd": "${workspaceFolder}", 19 | "preLaunchTask": "C/C++: cpp build active file", 20 | "MIMode": "lldb" // change to "gdb" if you are using non-macOS system 21 | }, 22 | { 23 | "name": "(debug) Launch Python", 24 | "type": "python", 25 | "request": "launch", 26 | // Please change to the executable of your current assignment. Python version of the lab exercises are using Jupyter Notebook. 27 | // | Assignment-1 | "${workspaceFolder}/Assignment-1/Python/test.py" | "-icfg", "Assignment-1/Tests/testcases/icfg/test1.ll" | 28 | // | Assignment-2 | "${workspaceFolder}/Assignment-2/Python/test-sse.py" | "Assignment-2/Tests/testcases/sse/test1.ll" | 29 | // | Assignment-3 | "${workspaceFolder}/Assignment-3/Python/test-ae.py" | "Assignment-3/Tests/ae/test1.ll" | 30 | "program": "${workspaceFolder}/HelloWorld/hello.py", 31 | "args": [], 32 | "cwd": "${workspaceFolder}", 33 | "console": "integratedTerminal" 34 | } 35 | ] 36 | } 37 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "C_Cpp.intelliSenseEngine": "Default" 3 | } -------------------------------------------------------------------------------- /.vscode/tasks.json: -------------------------------------------------------------------------------- 1 | { 2 | "tasks": [ 3 | { 4 | "label": "C/C++: cpp build active file", 5 | "type": "shell", 6 | // We assume that SVF is installed under the same folder as Software-Security-Analysis 7 | // You need to change LLVM_DIR, SVF_DIR and Z3_DIR to the correct paths if you installed SVF in a different location. 8 | "command": "cmake -DCMAKE_BUILD_TYPE=Debug -DSVF_DIR=../SVF -DLLVM_DIR=../SVF/llvm-16.0.0.obj -DZ3_DIR=../SVF/z3.obj . && make", 9 | "options": { 10 | "cwd": "${workspaceFolder}" 11 | }, 12 | "group": { 13 | "kind": "build", 14 | "isDefault": true 15 | }, 16 | "detail": "Task generated by Debugger." 17 | } 18 | ], 19 | "version": "2.0.0" 20 | } -------------------------------------------------------------------------------- /Assignment-1/CPP/Assignment_1.cpp: -------------------------------------------------------------------------------- 1 | //===- Assignment-1.cpp -- Taint analysis ------------------// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2022> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===----------------------------------------------------------------------===// 22 | /* 23 | * Graph reachability, Andersen's pointer analysis and taint analysis 24 | * 25 | * Created on: Feb 18, 2024 26 | */ 27 | 28 | #include "Assignment_1.h" 29 | #include "WPA/Andersen.h" 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | 36 | using namespace SVF; 37 | using namespace llvm; 38 | using namespace std; 39 | 40 | /// TODO: Implement your context-sensitive ICFG traversal here to traverse each program path 41 | /// by matching calls and returns while maintaining a `callstack`. 42 | /// Sources and sinks are identified by implementing and calling `readSrcSnkFromFile` 43 | /// Each path including loops, qualified by a `callstack`, should only be traversed once using a `visited` set. 44 | /// You will need to collect each path from src to snk and then add the path to the `paths` set. 45 | /// Add each path (a sequence of node IDs) as a string into std::set paths 46 | /// in the format "START->1->2->4->5->END", where -> indicate an ICFGEdge connects two ICFGNode IDs 47 | void ICFGTraversal::reachability(const ICFGNode* curNode, const ICFGNode* snk) { 48 | /// TODO: your code starts from here 49 | } 50 | 51 | /// TODO: Implement your code to parse the two lines to identify sources and sinks from `SrcSnk.txt` for your 52 | /// reachability analysis The format in SrcSnk.txt is in the form of 53 | /// line 1 for sources "{ api1 api2 api3 }" 54 | /// line 2 for sinks "{ api1 api2 api3 }" 55 | void ICFGTraversal::readSrcSnkFromFile(const string& filename) { 56 | /// TODO: your code starts from here 57 | } 58 | 59 | // TODO: Implement your Andersen's Algorithm here 60 | /// The solving rules are as follows: 61 | /// p <--Addr-- o => pts(p) = pts(p) ∪ {o} 62 | /// q <--COPY-- p => pts(q) = pts(q) ∪ pts(p) 63 | /// q <--LOAD-- p => for each o ∈ pts(p) : q <--COPY-- o 64 | /// q <--STORE-- p => for each o ∈ pts(q) : o <--COPY-- p 65 | /// q <--GEP, fld-- p => for each o ∈ pts(p) : pts(q) = pts(q) ∪ {o.fld} 66 | /// pts(q) denotes the points-to set of q 67 | void AndersenPTA::solveWorklist() { 68 | /// TODO: your code starts from here 69 | } 70 | 71 | /// TODO: Checking aliases of the two variables at source and sink. For example: 72 | /// src instruction: actualRet = source(); 73 | /// snk instruction: sink(actualParm,...); 74 | /// return true if actualRet is aliased with any parameter at the snk node (e.g., via ander->alias(..,..)) 75 | bool ICFGTraversal::aliasCheck(const CallICFGNode* src, const CallICFGNode* snk) { 76 | /// TODO: your code starts from here 77 | return false; 78 | } 79 | 80 | // Start taint checking. 81 | // There is a tainted flow from p@source to q@sink 82 | // if (1) alias(p,q)==true and (2) source reaches sink on ICFG. 83 | void ICFGTraversal::taintChecking() { 84 | const fs::path& config = CUR_DIR() / "../Tests/SrcSnk.txt"; 85 | // configure sources and sinks for taint analysis 86 | readSrcSnkFromFile(config); 87 | 88 | // Set file permissions to read-only for user, group and others 89 | if (chmod(config.string().c_str(), S_IRUSR | S_IRGRP | S_IROTH) == -1) { 90 | std::cerr << "Error setting file permissions for " << config << ": " << std::strerror(errno) << std::endl; 91 | abort(); 92 | } 93 | ander = new AndersenPTA(pag); 94 | ander->analyze(); 95 | for (const CallICFGNode* src : identifySources()) { 96 | for (const CallICFGNode* snk : identifySinks()) { 97 | if (aliasCheck(src, snk)) 98 | reachability(src, snk); 99 | } 100 | } 101 | } 102 | 103 | /*! 104 | * Andersen analysis 105 | */ 106 | void AndersenPTA::analyze() { 107 | initialize(); 108 | initWorklist(); 109 | do { 110 | reanalyze = false; 111 | solveWorklist(); 112 | if (updateCallGraph(getIndirectCallsites())) 113 | reanalyze = true; 114 | } while (reanalyze); 115 | finalize(); 116 | } 117 | -------------------------------------------------------------------------------- /Assignment-1/CPP/Assignment_1.h: -------------------------------------------------------------------------------- 1 | //===- Assignment-1.h -- Taint analysis ------------------// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2022> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===----------------------------------------------------------------------===// 22 | /* 23 | * Graph reachability, Andersen's pointer analysis and taint analysis 24 | * 25 | * Created on: Feb 18, 2024 26 | */ 27 | 28 | #ifndef SOFTWARE_SECURITY_ANALYSIS_ASSIGNMENT_1_H 29 | #define SOFTWARE_SECURITY_ANALYSIS_ASSIGNMENT_1_H 30 | 31 | #include "SVF-LLVM/LLVMUtil.h" 32 | #include "SVF-LLVM/SVFIRBuilder.h" 33 | #include "WPA/Andersen.h" 34 | #include 35 | namespace fs = std::filesystem; 36 | 37 | #define CUR_DIR() (fs::path(__FILE__).parent_path()) 38 | 39 | using namespace SVF; 40 | 41 | class AndersenPTA : public SVF::AndersenBase { 42 | public: 43 | // Constructor 44 | AndersenPTA(SVF::SVFIR* _pag) 45 | : AndersenBase(_pag){}; 46 | 47 | // dump constraint graph 48 | void dump_consCG(std::string name) { 49 | consCG->dump(name); 50 | }; 51 | 52 | void analyze() override; 53 | 54 | private: 55 | // To be implemented 56 | void solveWorklist() override; 57 | 58 | /// Add copy edge on constraint graph 59 | virtual bool addCopyEdge(SVF::NodeID src, SVF::NodeID dst) override { 60 | if (consCG->addCopyCGEdge(src, dst)) 61 | return true; 62 | else 63 | return false; 64 | } 65 | /// Return the field object (GepObjVar) given a struct object and a field index 66 | inline NodeID getGepObjVar(NodeID id, const APOffset& apOffset) { 67 | return consCG->getGepObjVar(id,apOffset); 68 | } 69 | }; 70 | 71 | class ICFGTraversal { 72 | public: 73 | typedef std::vector CallStack; 74 | typedef std::pair ICFGNodeCallStackPair; 75 | 76 | public: 77 | ICFGTraversal(SVFIR* p) 78 | : pag(p) {} 79 | 80 | /// TODO: to be implemented context sensitive reachability 81 | void reachability(const ICFGNode* curNode, const ICFGNode* sink); 82 | 83 | // Return true if two pointers are aliases 84 | bool aliasCheck(const CallICFGNode* src, const CallICFGNode* snk); 85 | 86 | // TODO: Source and sink function names read from SrcSnk.txt 87 | void readSrcSnkFromFile(const std::string& filename); 88 | 89 | // The driver method for taint checking 90 | void taintChecking(); 91 | 92 | // Identify source nodes on ICFG (i.e., call instruction with its callee function named 'src') 93 | virtual std::set& identifySources() { 94 | for (const CallICFGNode* cs : pag->getCallSiteSet()) { 95 | const FunObjVar* fun = cs->getCalledFunction(); 96 | if (checker_source_api.find(fun->getName()) != checker_source_api.end()) { 97 | sources.insert(cs); 98 | } 99 | } 100 | return sources; 101 | } 102 | 103 | // Identify sink nodes on ICFG (i.e., call instruction with its callee function named 'sink') 104 | virtual std::set& identifySinks() { 105 | for (const CallICFGNode* cs : pag->getCallSiteSet()) { 106 | const FunObjVar* fun = cs->getCalledFunction(); 107 | if (checker_sink_api.find(fun->getName()) != checker_sink_api.end()) { 108 | sinks.insert(cs); 109 | } 110 | } 111 | return sinks; 112 | } 113 | 114 | const std::set& getPaths() { 115 | return paths; 116 | } 117 | 118 | protected: 119 | std::set sources; 120 | std::set sinks; 121 | Set> visited; 122 | CallStack callstack; 123 | 124 | SVFIR* pag; 125 | std::set paths; 126 | std::vector path; 127 | 128 | private: 129 | AndersenPTA* ander; 130 | 131 | // default source and sink function name API if SrcSnk.txt is not added 132 | std::set checker_source_api; 133 | std::set checker_sink_api; 134 | }; 135 | 136 | #endif 137 | -------------------------------------------------------------------------------- /Assignment-1/CPP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(../ ${GTRAV_DIR}) 2 | file(GLOB SOURCES 3 | Assignment_1.cpp 4 | ) 5 | list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/test.cpp") 6 | set(LIB ${SVF_LIB} ${llvm_libs}) 7 | add_library(assign-1 ${SOURCES}) 8 | target_link_libraries(assign-1 ${LIB}) 9 | set_target_properties(assign-1 PROPERTIES 10 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 11 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 12 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 13 | ) 14 | add_executable(ass1 test.cpp) 15 | target_link_libraries(ass1 ${LIB} assign-1) 16 | set_target_properties(ass1 PROPERTIES 17 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 18 | 19 | # loops over pta_assert_files and run "ass1-pta $bc_file" 20 | message(STATUS "Adding test for pta_assert_files") 21 | file(GLOB pta_assert_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/testcases/pta/*.ll") 22 | foreach(filename ${pta_assert_files}) 23 | message(STATUS "Adding test for ${filename}") 24 | add_test( 25 | NAME ass1-pta-cpp/${filename} 26 | COMMAND ass1 -pta ${CMAKE_CURRENT_SOURCE_DIR}/${filename} 27 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin 28 | ) 29 | endforeach() 30 | 31 | message(STATUS "Adding test for icfg_assert_files") 32 | file(GLOB icfg_assert_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/testcases/icfg/*.ll") 33 | foreach(filename ${icfg_assert_files}) 34 | add_test( 35 | NAME ass1-icfg-cpp/${filename} 36 | COMMAND ass1 -icfg ${CMAKE_CURRENT_SOURCE_DIR}/${filename} 37 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin 38 | ) 39 | endforeach() 40 | 41 | message(STATUS "Adding test for taint_assert_files") 42 | file(GLOB taint_assert_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/testcases/taint/*.ll") 43 | foreach(filename ${taint_assert_files}) 44 | add_test( 45 | NAME ass1-taint-cpp/${filename} 46 | COMMAND ass1 -taint ${CMAKE_CURRENT_SOURCE_DIR}/${filename} 47 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin 48 | ) 49 | endforeach() 50 | 51 | -------------------------------------------------------------------------------- /Assignment-1/Python/Assignment_1.py: -------------------------------------------------------------------------------- 1 | import sys 2 | import os 3 | import pysvf 4 | from typing import Union 5 | from Assignment_1_Helper import * 6 | 7 | class Ass1_Andersen(AndersenPTA): 8 | def __init__(self, pag: pysvf.SVFIR): 9 | super().__init__(pag) 10 | 11 | ''' 12 | // TODO: Implement your Andersen's Algorithm here 13 | /// The solving rules are as follows: 14 | /// p <--Addr-- o => pts(p) = pts(p) ∪ {o} 15 | /// q <--COPY-- p => pts(q) = pts(q) ∪ pts(p) 16 | /// q <--LOAD-- p => for each o ∈ pts(p) : q <--COPY-- o 17 | /// q <--STORE-- p => for each o ∈ pts(q) : o <--COPY-- p 18 | /// q <--GEP, fld-- p => for each o ∈ pts(p) : pts(q) = pts(q) ∪ {o.fld} 19 | /// pts(q) denotes the points-to set of q 20 | ''' 21 | def solveWorklist(self): 22 | pass 23 | 24 | 25 | 26 | class Ass1_ICFGTraversal(ICFGTraversal): 27 | def __init__(self, pag): 28 | super().__init__(pag, Ass1_Andersen(pag)) 29 | 30 | ''' 31 | /// TODO: Implement your code to parse the two lines to identify sources and sinks from `SrcSnk.txt` for your 32 | /// reachability analysis The format in SrcSnk.txt is in the form of 33 | /// line 1 for sources "{ api1 api2 api3 }" 34 | /// line 2 for sinks "{ api1 api2 api3 }" 35 | ''' 36 | def readSrcSnkFromFile(self, filename): 37 | pass 38 | 39 | ''' 40 | /// TODO: Implement your context-sensitive ICFG traversal here to traverse each program path 41 | /// by matching calls and returns while maintaining a `callstack`. 42 | /// Sources and sinks are identified by implementing and calling `readSrcSnkFromFile` 43 | /// Each path including loops, qualified by a `callstack`, should only be traversed once using a `visited` set. 44 | /// You will need to collect each path from src to snk and then add the path to the `paths` set. 45 | /// Add each path (a sequence of node IDs) as a string into std::set paths 46 | /// in the format "START->1->2->4->5->END", where -> indicate an ICFGEdge connects two ICFGNode IDs 47 | ''' 48 | def reachability(self, cur_node, sink): 49 | assert isinstance(cur_node, pysvf.ICFGNode), "cur_node is not a valid ICFGNode object, the type of cur_node is {}".format(type(cur_node)) 50 | assert isinstance(sink, pysvf.ICFGNode), "sink is not a valid ICFGNode object, the type of sink is {}".format(type(sink)) 51 | pass 52 | 53 | 54 | ''' 55 | /// TODO: Checking aliases of the two variables at source and sink. For example: 56 | /// src instruction: actualRet = source(); 57 | /// snk instruction: sink(actualParm,...); 58 | /// return true if actualRet is aliased with any parameter at the snk node (e.g., via ander->alias(..,..)) 59 | ''' 60 | def aliasCheck(self, src, snk) -> bool: 61 | assert isinstance(src, pysvf.CallICFGNode), "src is not a valid CallICFGNode object, the type of src is {}".format(type(src)) 62 | assert isinstance(snk, pysvf.CallICFGNode), "snk is not a valid CallICFGNode object, the type of snk is {}".format(type(snk)) 63 | pass -------------------------------------------------------------------------------- /Assignment-1/Python/Assignment_1_Helper.py: -------------------------------------------------------------------------------- 1 | import pysvf 2 | from typing import Union 3 | import os 4 | class AndersenPTA: 5 | def __init__(self, pag: pysvf.SVFIR): 6 | assert isinstance(pag, pysvf.SVFIR), "pag is not a valid SVFIR object, the type of pag is {}".format(type(pag)) 7 | self.pag = pag 8 | self.ander_base = pysvf.AndersenBase(pag) 9 | self.consCG = None 10 | return 11 | 12 | def initialize(self): 13 | self.ander_base.initialize() 14 | self.consCG = self.ander_base.getConstraintGraph() 15 | 16 | def initWorklist(self): 17 | self.ander_base.initWorklist() 18 | 19 | def updateCallGraph(self): 20 | return self.ander_base.updateCallGraph() 21 | 22 | def pushIntoWorklist(self, node): 23 | assert isinstance(node, int), "node is not a valid int object, the type of node is {}".format(type(node)) 24 | self.ander_base.pushIntoWorklist(node) 25 | 26 | def finalize(self): 27 | self.ander_base.finalize() 28 | 29 | def addPts(self, id: int, ptd: int) -> bool: 30 | assert isinstance(ptd, int), "ptd is not a valid int object, the type of ptd is {}".format(type(ptd)) 31 | assert isinstance(id, int), "id is not a valid int object, the type of id is {}".format(type(id)) 32 | return self.ander_base.addPts(id, ptd) 33 | 34 | def unionPts(self, id: int, ptd: Union[int, pysvf.PointsTo, None]) -> bool: 35 | assert isinstance(id, int), "id is not a valid int object, the type of id is {}".format(type(id)) 36 | assert isinstance(ptd, (int, pysvf.PointsTo, type(None))), "ptd is not a valid int/PointsTo/None object, the type of ptd is {}".format(type(ptd)) 37 | if isinstance(ptd, pysvf.PointsTo): 38 | return self.ander_base.unionPts2(id, ptd) 39 | elif isinstance(ptd, int): 40 | return self.ander_base.unionPts(id, ptd) 41 | else: 42 | raise TypeError("Invalid type for ptd") 43 | 44 | def getPts(self, id: int): 45 | assert isinstance(id, int), "id is not a valid int object, the type of id is {}".format(type(id)) 46 | return self.ander_base.getPts(id) 47 | 48 | def isWorklistEmpty(self) -> bool: 49 | return self.ander_base.isWorklistEmpty() 50 | 51 | def popFromWorklist(self): 52 | return self.ander_base.popFromWorklist() 53 | 54 | def addCopyEdge(self, src_id, dst_id) -> bool: 55 | assert isinstance(src_id, int), "src_id is not a valid int object, the type of src_id is {}".format(type(src_id)) 56 | assert isinstance(dst_id, int), "dst_id is not a valid int object, the type of dst_id is {}".format(type(dst_id)) 57 | print(f"Adding copy edge from {src_id} to {dst_id}") 58 | return self.consCG.addCopyCGEdge(src_id, dst_id) 59 | 60 | def alias(self, node1: int, node2: int) -> bool: 61 | assert isinstance(node1, int), "node1 is not a valid int object, the type of node1 is {}".format(type(node1)) 62 | assert isinstance(node2, int), "node2 is not a valid int object, the type of node2 is {}".format(type(node2)) 63 | return self.ander_base.alias(node1, node2) 64 | 65 | def analyze(self): 66 | self.initialize() 67 | self.initWorklist() 68 | while True: 69 | reanalyze = False 70 | self.solveWorklist() 71 | if self.updateCallGraph(): 72 | reanalyze = True 73 | if not reanalyze: 74 | break 75 | self.finalize() 76 | 77 | 78 | class ICFGTraversal: 79 | def __init__(self, pag, ander): 80 | assert isinstance(pag, pysvf.SVFIR), "pag is not a valid SVFIR object, the type of pag is {}".format(type(pag)) 81 | self.pag = pag 82 | self.icfg = pag.getICFG() 83 | self.paths = set() 84 | self.path = [] 85 | self.visited = set() 86 | self.callstack = [] 87 | self.sources = set() 88 | self.sinks = set() 89 | self.source_names = set() 90 | self.sink_names = set() 91 | self.ander = ander 92 | 93 | 94 | def identifySources(self): 95 | for callsite in self.pag.getCallSites(): 96 | fun = callsite.getCalledFunction() 97 | if fun.getName() in self.source_names: 98 | self.sources.add(callsite) 99 | return self.sources 100 | 101 | def identifySinks(self): 102 | for callsite in self.pag.getCallSites(): 103 | fun = callsite.getCalledFunction() 104 | if fun.getName() in self.sink_names: 105 | self.sinks.add(callsite) 106 | return self.sinks 107 | 108 | 109 | 110 | ''' 111 | // Start taint checking. 112 | // There is a tainted flow from p@source to q@sink 113 | // if (1) alias(p,q)==true and (2) source reaches sink on ICFG. 114 | ''' 115 | def taintChecking(self): 116 | if os.path.exists("../Tests/SrcSnk.txt"): 117 | self.readSrcSnkFromFile("../Tests/SrcSnk.txt") 118 | elif os.path.exists("Assignment-1/Tests/SrcSnk.txt"): 119 | self.readSrcSnkFromFile("Assignment-1/Tests/SrcSnk.txt") 120 | else: 121 | raise FileNotFoundError("SrcSnk.txt not found") 122 | self.ander.analyze() 123 | for src in self.identifySources(): 124 | for snk in self.identifySinks(): 125 | if self.aliasCheck(src, snk): 126 | self.reachability(src, snk) 127 | 128 | 129 | 130 | def getPaths(self): 131 | return self.paths 132 | 133 | 134 | 135 | -------------------------------------------------------------------------------- /Assignment-1/Python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | 2 | # loops over pta_assert_files and run "ass1-pta $bc_file" 3 | message(STATUS "Adding python test for pta_assert_files") 4 | file(GLOB pta_assert_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/testcases/pta/*.ll") 5 | foreach(filename ${pta_assert_files}) 6 | message(STATUS "Adding test for ${filename}") 7 | add_test( 8 | NAME ass1-pta-py/${filename} 9 | COMMAND python3 test.py -pta ${CMAKE_CURRENT_SOURCE_DIR}/${filename} 10 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 11 | ) 12 | endforeach() 13 | 14 | message(STATUS "Adding python test for icfg_assert_files") 15 | file(GLOB icfg_assert_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/testcases/icfg/*.ll") 16 | foreach(filename ${icfg_assert_files}) 17 | add_test( 18 | NAME ass1-icfg-py/${filename} 19 | COMMAND python3 test.py -icfg ${CMAKE_CURRENT_SOURCE_DIR}/${filename} 20 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 21 | ) 22 | endforeach() 23 | 24 | message(STATUS "Adding python test for taint_assert_files") 25 | file(GLOB taint_assert_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/testcases/taint/*.ll") 26 | foreach(filename ${taint_assert_files}) 27 | add_test( 28 | NAME ass1-taint-py/${filename} 29 | COMMAND python3 test.py -taint ${CMAKE_CURRENT_SOURCE_DIR}/${filename} 30 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 31 | ) 32 | endforeach() 33 | 34 | -------------------------------------------------------------------------------- /Assignment-1/Python/test.py: -------------------------------------------------------------------------------- 1 | from Assignment_1 import * 2 | def check_icfg_case(module_name, result, expected): 3 | assert len(result) == len(expected), f"Wrong paths generated - {module_name} failed!" 4 | for path in result: 5 | assert path in expected, f"Wrong paths generated - {module_name} failed!" 6 | print(f"Test case {module_name} passed!") 7 | 8 | 9 | def test_icfg(argv): 10 | pysvf.buildSVFModule(argv) # Build Program Assignment Graph (SVFIR) 11 | pag = pysvf.getPAG() 12 | icfg = pag.getICFG() # Get ICFG 13 | gt = Ass1_ICFGTraversal(pag) # Create ICFG Traversal object 14 | 15 | config_path = os.path.join(os.path.dirname(__file__), "../Tests/SrcSnk.txt") 16 | gt.readSrcSnkFromFile(config_path) 17 | 18 | for src in gt.identifySources(): 19 | for snk in gt.identifySinks(): 20 | gt.reachability(src, snk) 21 | for arg in argv: 22 | # not start with - 23 | if not arg.startswith('-'): 24 | module_name_vec = arg 25 | 26 | module_name = os.path.basename(module_name_vec) 27 | if module_name == "test1.ll": 28 | expected = { 29 | "START->6->7->8->9->10->1->5->2->11->14->END", 30 | "START->6->7->8->9->12->1->5->2->13->16->END" 31 | } 32 | check_icfg_case(module_name, gt.getPaths(), expected) 33 | 34 | elif module_name == "test2.ll": 35 | expected = {"START->17->1->7->END"} 36 | actual_paths = gt.getPaths() 37 | assert len(actual_paths) == len(expected), " \n wrong paths generated - test2 failed !" 38 | for path in actual_paths: 39 | assert path in expected, " \n wrong paths generated - test2 failed !" 40 | 41 | else: 42 | print(f"Test case {module_name} not found!") 43 | 44 | 45 | def test_pta(argv): 46 | pysvf.buildSVFModule(argv) # Build Program Assignment Graph (SVFIR) 47 | pag = pysvf.getPAG() 48 | andersen_pta = Ass1_Andersen(pag) 49 | andersen_pta.analyze() # Run Andersen pointer analysis 50 | del andersen_pta 51 | 52 | 53 | def test_taint(argv): 54 | pysvf.buildSVFModule(argv) # Build Program Assignment Graph (SVFIR) 55 | pag = pysvf.getPAG() 56 | taint = Ass1_ICFGTraversal(pag) 57 | taint.taintChecking() # Perform taint analysis 58 | 59 | for arg in argv: 60 | # not start with - 61 | if not arg.startswith('-'): 62 | module_name_vec = arg 63 | module_name_vec = os.path.basename(module_name_vec) 64 | print(taint.getPaths()) 65 | if module_name_vec == "test1.ll": 66 | expected = {"START->6->1->5->2->7->8->9->10->END"} 67 | assert taint.getPaths() == expected, " \n wrong paths generated - test1 failed !" 68 | print("\n test1 passed !") 69 | elif module_name_vec == "test2.ll": 70 | expected = {"START->6->1->5->2->7->8->9->10->11->13->14->END"} 71 | assert taint.getPaths() == expected, " \n wrong paths generated - test2 failed !" 72 | print("\n test2 passed !") 73 | elif module_name_vec == "test2.ll" or module_name_vec == "test3.ll": 74 | expected = set() 75 | assert taint.getPaths() == expected, " \n wrong paths generated - test3 or test4 failed !" 76 | print("\n test3 or test4 passed !") 77 | 78 | 79 | print(f"###################### Tainted Information Flow ({len(taint.getPaths())} found) ######################") 80 | print("---------------------------------------------") 81 | for path in taint.getPaths(): 82 | origin_path = path 83 | prefix = "START->" 84 | suffix = "->END" 85 | 86 | if path.startswith(prefix): 87 | path = path[len(prefix):] 88 | if path.endswith(suffix): 89 | path = path[:-len(suffix)] 90 | 91 | tokens = path.split("->") 92 | src_id = int(tokens[0]) 93 | dst_id = int(tokens[-1]) 94 | src_node = pag.getICFG().getGNode(src_id) 95 | dst_node = pag.getICFG().getGNode(dst_id) 96 | 97 | 98 | print( 99 | f"{origin_path}\nSource: {src_node.toString()}\nSink: {dst_node.toString()}\n---------------------------------------------") 100 | 101 | if not taint.getPaths(): 102 | print("No tainted information flow found") 103 | 104 | 105 | def main(): 106 | pta_enabled = False 107 | taint_enabled = False 108 | icfg_enabled = False 109 | module_name_vec = "" 110 | argv = [] 111 | 112 | args = sys.argv[1:] 113 | 114 | for arg in args: 115 | if arg == "-pta": 116 | pta_enabled = True 117 | elif arg == "-taint": 118 | taint_enabled = True 119 | elif arg == "-icfg": 120 | icfg_enabled = True 121 | else: 122 | argv.append(arg) 123 | 124 | # Default to taint analysis if none specified 125 | if not (pta_enabled or taint_enabled or icfg_enabled): 126 | assert False, "No analysis specified. Please specify -pta, -taint, or -icfg." 127 | 128 | assert (pta_enabled + taint_enabled + icfg_enabled) == 1, "Only one analysis can be enabled." 129 | 130 | if argv == []: 131 | assert False, "No module specified. Please specify a module to analyze." 132 | 133 | if pta_enabled: 134 | test_pta(argv) 135 | elif taint_enabled: 136 | test_taint(argv) 137 | elif icfg_enabled: 138 | test_icfg(argv) 139 | 140 | 141 | if __name__ == "__main__": 142 | main() 143 | -------------------------------------------------------------------------------- /Assignment-1/Tests/SrcSnk.txt: -------------------------------------------------------------------------------- 1 | source -> { source src set getname update getchar tgetstr } 2 | sink -> { sink mysql_query system require chmod broadcast } -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/icfg/test1.c: -------------------------------------------------------------------------------- 1 | extern int source(); 2 | extern void sink(int s); 3 | int bar(int s){ 4 | return s; 5 | } 6 | int main(){ 7 | int a = source(); 8 | if (a > 0){ 9 | int p = bar(a); 10 | sink(p); 11 | }else{ 12 | int q = bar(a); 13 | sink(q); 14 | } 15 | } -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/icfg/test1.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test1.ll' 2 | source_filename = "./test1.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define i32 @bar(i32 noundef %s) #0 !dbg !9 { 8 | entry: 9 | call void @llvm.dbg.value(metadata i32 %s, metadata !15, metadata !DIExpression()), !dbg !16 10 | ret i32 %s, !dbg !17 11 | } 12 | 13 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 14 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 15 | 16 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 17 | define i32 @main() #0 !dbg !18 { 18 | entry: 19 | %call = call i32 @source(), !dbg !21 20 | call void @llvm.dbg.value(metadata i32 %call, metadata !22, metadata !DIExpression()), !dbg !23 21 | %cmp = icmp sgt i32 %call, 0, !dbg !24 22 | br i1 %cmp, label %if.then, label %if.else, !dbg !26 23 | 24 | if.then: ; preds = %entry 25 | %call1 = call i32 @bar(i32 noundef %call), !dbg !27 26 | call void @llvm.dbg.value(metadata i32 %call1, metadata !29, metadata !DIExpression()), !dbg !30 27 | call void @sink(i32 noundef %call1), !dbg !31 28 | br label %if.end, !dbg !32 29 | 30 | if.else: ; preds = %entry 31 | %call2 = call i32 @bar(i32 noundef %call), !dbg !33 32 | call void @llvm.dbg.value(metadata i32 %call2, metadata !35, metadata !DIExpression()), !dbg !36 33 | call void @sink(i32 noundef %call2), !dbg !37 34 | br label %if.end 35 | 36 | if.end: ; preds = %if.else, %if.then 37 | ret i32 0, !dbg !38 38 | } 39 | 40 | declare i32 @source(...) #2 41 | 42 | declare void @sink(i32 noundef) #2 43 | 44 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 45 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 46 | 47 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 48 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 49 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 50 | 51 | !llvm.dbg.cu = !{!0} 52 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 53 | !llvm.ident = !{!8} 54 | 55 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 56 | !1 = !DIFile(filename: "test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/icfg") 57 | !2 = !{i32 7, !"Dwarf Version", i32 4} 58 | !3 = !{i32 2, !"Debug Info Version", i32 3} 59 | !4 = !{i32 1, !"wchar_size", i32 4} 60 | !5 = !{i32 8, !"PIC Level", i32 2} 61 | !6 = !{i32 7, !"uwtable", i32 1} 62 | !7 = !{i32 7, !"frame-pointer", i32 1} 63 | !8 = !{!"Homebrew clang version 16.0.6"} 64 | !9 = distinct !DISubprogram(name: "bar", scope: !10, file: !10, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) 65 | !10 = !DIFile(filename: "./test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/icfg") 66 | !11 = !DISubroutineType(types: !12) 67 | !12 = !{!13, !13} 68 | !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 69 | !14 = !{} 70 | !15 = !DILocalVariable(name: "s", arg: 1, scope: !9, file: !10, line: 3, type: !13) 71 | !16 = !DILocation(line: 0, scope: !9) 72 | !17 = !DILocation(line: 4, column: 5, scope: !9) 73 | !18 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 6, type: !19, scopeLine: 6, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) 74 | !19 = !DISubroutineType(types: !20) 75 | !20 = !{!13} 76 | !21 = !DILocation(line: 7, column: 13, scope: !18) 77 | !22 = !DILocalVariable(name: "a", scope: !18, file: !10, line: 7, type: !13) 78 | !23 = !DILocation(line: 0, scope: !18) 79 | !24 = !DILocation(line: 8, column: 11, scope: !25) 80 | !25 = distinct !DILexicalBlock(scope: !18, file: !10, line: 8, column: 9) 81 | !26 = !DILocation(line: 8, column: 9, scope: !18) 82 | !27 = !DILocation(line: 9, column: 17, scope: !28) 83 | !28 = distinct !DILexicalBlock(scope: !25, file: !10, line: 8, column: 15) 84 | !29 = !DILocalVariable(name: "p", scope: !28, file: !10, line: 9, type: !13) 85 | !30 = !DILocation(line: 0, scope: !28) 86 | !31 = !DILocation(line: 10, column: 9, scope: !28) 87 | !32 = !DILocation(line: 11, column: 5, scope: !28) 88 | !33 = !DILocation(line: 12, column: 17, scope: !34) 89 | !34 = distinct !DILexicalBlock(scope: !25, file: !10, line: 11, column: 10) 90 | !35 = !DILocalVariable(name: "q", scope: !34, file: !10, line: 12, type: !13) 91 | !36 = !DILocation(line: 0, scope: !34) 92 | !37 = !DILocation(line: 13, column: 9, scope: !34) 93 | !38 = !DILocation(line: 15, column: 1, scope: !18) 94 | -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/icfg/test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | void sink(); 3 | void source(int *s){ 4 | sink(); 5 | }; 6 | void sink(){ 7 | }; 8 | 9 | int main(){ 10 | int a = 1; 11 | while ( a <=1){ 12 | source(&a); 13 | a++; 14 | } 15 | return 0; 16 | }; -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/icfg/test2.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test2.ll' 2 | source_filename = "./test2.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define void @source(ptr noundef %s) #0 !dbg !9 { 8 | entry: 9 | call void @llvm.dbg.value(metadata ptr %s, metadata !16, metadata !DIExpression()), !dbg !17 10 | call void @sink(), !dbg !18 11 | ret void, !dbg !19 12 | } 13 | 14 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 15 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 16 | 17 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 18 | define void @sink() #0 !dbg !20 { 19 | entry: 20 | ret void, !dbg !23 21 | } 22 | 23 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 24 | define i32 @main() #0 !dbg !24 { 25 | entry: 26 | %a = alloca i32, align 4 27 | call void @llvm.dbg.declare(metadata ptr %a, metadata !27, metadata !DIExpression()), !dbg !28 28 | store i32 1, ptr %a, align 4, !dbg !28 29 | br label %while.cond, !dbg !29 30 | 31 | while.cond: ; preds = %while.body, %entry 32 | %0 = load i32, ptr %a, align 4, !dbg !30 33 | %cmp = icmp sle i32 %0, 1, !dbg !31 34 | br i1 %cmp, label %while.body, label %while.end, !dbg !29 35 | 36 | while.body: ; preds = %while.cond 37 | call void @source(ptr noundef %a), !dbg !32 38 | %1 = load i32, ptr %a, align 4, !dbg !34 39 | %inc = add nsw i32 %1, 1, !dbg !34 40 | store i32 %inc, ptr %a, align 4, !dbg !34 41 | br label %while.cond, !dbg !29, !llvm.loop !35 42 | 43 | while.end: ; preds = %while.cond 44 | ret i32 0, !dbg !38 45 | } 46 | 47 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 48 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 49 | 50 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 51 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 52 | 53 | !llvm.dbg.cu = !{!0} 54 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 55 | !llvm.ident = !{!8} 56 | 57 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 58 | !1 = !DIFile(filename: "test2.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/icfg") 59 | !2 = !{i32 7, !"Dwarf Version", i32 4} 60 | !3 = !{i32 2, !"Debug Info Version", i32 3} 61 | !4 = !{i32 1, !"wchar_size", i32 4} 62 | !5 = !{i32 8, !"PIC Level", i32 2} 63 | !6 = !{i32 7, !"uwtable", i32 1} 64 | !7 = !{i32 7, !"frame-pointer", i32 1} 65 | !8 = !{!"Homebrew clang version 16.0.6"} 66 | !9 = distinct !DISubprogram(name: "source", scope: !10, file: !10, line: 3, type: !11, scopeLine: 3, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !15) 67 | !10 = !DIFile(filename: "./test2.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/icfg") 68 | !11 = !DISubroutineType(types: !12) 69 | !12 = !{null, !13} 70 | !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) 71 | !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 72 | !15 = !{} 73 | !16 = !DILocalVariable(name: "s", arg: 1, scope: !9, file: !10, line: 3, type: !13) 74 | !17 = !DILocation(line: 0, scope: !9) 75 | !18 = !DILocation(line: 4, column: 5, scope: !9) 76 | !19 = !DILocation(line: 5, column: 1, scope: !9) 77 | !20 = distinct !DISubprogram(name: "sink", scope: !10, file: !10, line: 6, type: !21, scopeLine: 6, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !15) 78 | !21 = !DISubroutineType(types: !22) 79 | !22 = !{null} 80 | !23 = !DILocation(line: 7, column: 1, scope: !20) 81 | !24 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 9, type: !25, scopeLine: 9, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !15) 82 | !25 = !DISubroutineType(types: !26) 83 | !26 = !{!14} 84 | !27 = !DILocalVariable(name: "a", scope: !24, file: !10, line: 10, type: !14) 85 | !28 = !DILocation(line: 10, column: 9, scope: !24) 86 | !29 = !DILocation(line: 11, column: 5, scope: !24) 87 | !30 = !DILocation(line: 11, column: 13, scope: !24) 88 | !31 = !DILocation(line: 11, column: 15, scope: !24) 89 | !32 = !DILocation(line: 12, column: 9, scope: !33) 90 | !33 = distinct !DILexicalBlock(scope: !24, file: !10, line: 11, column: 19) 91 | !34 = !DILocation(line: 13, column: 10, scope: !33) 92 | !35 = distinct !{!35, !29, !36, !37} 93 | !36 = !DILocation(line: 14, column: 5, scope: !24) 94 | !37 = !{!"llvm.loop.mustprogress"} 95 | !38 = !DILocation(line: 15, column: 5, scope: !24) 96 | -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/pta/test1.c: -------------------------------------------------------------------------------- 1 | extern void MAYALIAS(void* p, void* q); 2 | 3 | int global; 4 | int *p_global; 5 | 6 | void foo() { 7 | p_global = &global; 8 | } 9 | 10 | int main() { 11 | int *p_local; 12 | p_local = &global; 13 | foo(); 14 | MAYALIAS(p_local, p_global); 15 | return 0; 16 | } -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/pta/test1.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test1.ll' 2 | source_filename = "./test1.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | @global = global i32 0, align 4, !dbg !0 7 | @p_global = global ptr null, align 8, !dbg !5 8 | 9 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 10 | define void @foo() #0 !dbg !17 { 11 | entry: 12 | store ptr @global, ptr @p_global, align 8, !dbg !21 13 | ret void, !dbg !22 14 | } 15 | 16 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 17 | define i32 @main() #0 !dbg !23 { 18 | entry: 19 | call void @llvm.dbg.value(metadata ptr @global, metadata !26, metadata !DIExpression()), !dbg !27 20 | call void @foo(), !dbg !28 21 | %0 = load ptr, ptr @p_global, align 8, !dbg !29 22 | call void @MAYALIAS(ptr noundef @global, ptr noundef %0), !dbg !30 23 | ret i32 0, !dbg !31 24 | } 25 | 26 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 27 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 28 | 29 | declare void @MAYALIAS(ptr noundef, ptr noundef) #2 30 | 31 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 32 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 33 | 34 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 35 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 36 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 37 | 38 | !llvm.dbg.cu = !{!2} 39 | !llvm.module.flags = !{!10, !11, !12, !13, !14, !15} 40 | !llvm.ident = !{!16} 41 | 42 | !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) 43 | !1 = distinct !DIGlobalVariable(name: "global", scope: !2, file: !7, line: 3, type: !9, isLocal: false, isDefinition: true) 44 | !2 = distinct !DICompileUnit(language: DW_LANG_C11, file: !3, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !4, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 45 | !3 = !DIFile(filename: "test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/pta") 46 | !4 = !{!0, !5} 47 | !5 = !DIGlobalVariableExpression(var: !6, expr: !DIExpression()) 48 | !6 = distinct !DIGlobalVariable(name: "p_global", scope: !2, file: !7, line: 4, type: !8, isLocal: false, isDefinition: true) 49 | !7 = !DIFile(filename: "./test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/pta") 50 | !8 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !9, size: 64) 51 | !9 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 52 | !10 = !{i32 7, !"Dwarf Version", i32 4} 53 | !11 = !{i32 2, !"Debug Info Version", i32 3} 54 | !12 = !{i32 1, !"wchar_size", i32 4} 55 | !13 = !{i32 8, !"PIC Level", i32 2} 56 | !14 = !{i32 7, !"uwtable", i32 1} 57 | !15 = !{i32 7, !"frame-pointer", i32 1} 58 | !16 = !{!"Homebrew clang version 16.0.6"} 59 | !17 = distinct !DISubprogram(name: "foo", scope: !7, file: !7, line: 6, type: !18, scopeLine: 6, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !20) 60 | !18 = !DISubroutineType(types: !19) 61 | !19 = !{null} 62 | !20 = !{} 63 | !21 = !DILocation(line: 7, column: 14, scope: !17) 64 | !22 = !DILocation(line: 8, column: 1, scope: !17) 65 | !23 = distinct !DISubprogram(name: "main", scope: !7, file: !7, line: 10, type: !24, scopeLine: 10, spFlags: DISPFlagDefinition, unit: !2, retainedNodes: !20) 66 | !24 = !DISubroutineType(types: !25) 67 | !25 = !{!9} 68 | !26 = !DILocalVariable(name: "p_local", scope: !23, file: !7, line: 11, type: !8) 69 | !27 = !DILocation(line: 0, scope: !23) 70 | !28 = !DILocation(line: 13, column: 5, scope: !23) 71 | !29 = !DILocation(line: 14, column: 23, scope: !23) 72 | !30 = !DILocation(line: 14, column: 5, scope: !23) 73 | !31 = !DILocation(line: 15, column: 5, scope: !23) 74 | -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/pta/test2.c: -------------------------------------------------------------------------------- 1 | extern void MAYALIAS(void* p, void* q); 2 | 3 | 4 | void foo(int *m, int *n) 5 | { 6 | MAYALIAS(m,n); 7 | } 8 | 9 | int main() 10 | { 11 | int *p, *q; 12 | int a,b; 13 | if (a) { 14 | p = &a; 15 | q = &b; 16 | foo(p,q); 17 | } 18 | else { 19 | p = &b; 20 | q = &a; 21 | foo(p,q); 22 | } 23 | return 0; 24 | } -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/pta/test2.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test2.ll' 2 | source_filename = "./test2.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define void @foo(ptr noundef %m, ptr noundef %n) #0 !dbg !9 { 8 | entry: 9 | call void @llvm.dbg.value(metadata ptr %m, metadata !16, metadata !DIExpression()), !dbg !17 10 | call void @llvm.dbg.value(metadata ptr %n, metadata !18, metadata !DIExpression()), !dbg !17 11 | call void @MAYALIAS(ptr noundef %m, ptr noundef %n), !dbg !19 12 | ret void, !dbg !20 13 | } 14 | 15 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 16 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 17 | 18 | declare void @MAYALIAS(ptr noundef, ptr noundef) #2 19 | 20 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 21 | define i32 @main() #0 !dbg !21 { 22 | entry: 23 | %a = alloca i32, align 4 24 | %b = alloca i32, align 4 25 | call void @llvm.dbg.declare(metadata ptr %a, metadata !24, metadata !DIExpression()), !dbg !25 26 | call void @llvm.dbg.declare(metadata ptr %b, metadata !26, metadata !DIExpression()), !dbg !27 27 | %0 = load i32, ptr %a, align 4, !dbg !28 28 | %tobool = icmp ne i32 %0, 0, !dbg !28 29 | br i1 %tobool, label %if.then, label %if.else, !dbg !30 30 | 31 | if.then: ; preds = %entry 32 | call void @llvm.dbg.value(metadata ptr %a, metadata !31, metadata !DIExpression()), !dbg !32 33 | call void @llvm.dbg.value(metadata ptr %b, metadata !33, metadata !DIExpression()), !dbg !32 34 | call void @foo(ptr noundef %a, ptr noundef %b), !dbg !34 35 | br label %if.end, !dbg !36 36 | 37 | if.else: ; preds = %entry 38 | call void @llvm.dbg.value(metadata ptr %b, metadata !31, metadata !DIExpression()), !dbg !32 39 | call void @llvm.dbg.value(metadata ptr %a, metadata !33, metadata !DIExpression()), !dbg !32 40 | call void @foo(ptr noundef %b, ptr noundef %a), !dbg !37 41 | br label %if.end 42 | 43 | if.end: ; preds = %if.else, %if.then 44 | ret i32 0, !dbg !39 45 | } 46 | 47 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 48 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 49 | 50 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 51 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 52 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 53 | 54 | !llvm.dbg.cu = !{!0} 55 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 56 | !llvm.ident = !{!8} 57 | 58 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 59 | !1 = !DIFile(filename: "test2.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/pta") 60 | !2 = !{i32 7, !"Dwarf Version", i32 4} 61 | !3 = !{i32 2, !"Debug Info Version", i32 3} 62 | !4 = !{i32 1, !"wchar_size", i32 4} 63 | !5 = !{i32 8, !"PIC Level", i32 2} 64 | !6 = !{i32 7, !"uwtable", i32 1} 65 | !7 = !{i32 7, !"frame-pointer", i32 1} 66 | !8 = !{!"Homebrew clang version 16.0.6"} 67 | !9 = distinct !DISubprogram(name: "foo", scope: !10, file: !10, line: 4, type: !11, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !15) 68 | !10 = !DIFile(filename: "./test2.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/pta") 69 | !11 = !DISubroutineType(types: !12) 70 | !12 = !{null, !13, !13} 71 | !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) 72 | !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 73 | !15 = !{} 74 | !16 = !DILocalVariable(name: "m", arg: 1, scope: !9, file: !10, line: 4, type: !13) 75 | !17 = !DILocation(line: 0, scope: !9) 76 | !18 = !DILocalVariable(name: "n", arg: 2, scope: !9, file: !10, line: 4, type: !13) 77 | !19 = !DILocation(line: 6, column: 5, scope: !9) 78 | !20 = !DILocation(line: 7, column: 1, scope: !9) 79 | !21 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 9, type: !22, scopeLine: 10, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !15) 80 | !22 = !DISubroutineType(types: !23) 81 | !23 = !{!14} 82 | !24 = !DILocalVariable(name: "a", scope: !21, file: !10, line: 12, type: !14) 83 | !25 = !DILocation(line: 12, column: 9, scope: !21) 84 | !26 = !DILocalVariable(name: "b", scope: !21, file: !10, line: 12, type: !14) 85 | !27 = !DILocation(line: 12, column: 11, scope: !21) 86 | !28 = !DILocation(line: 13, column: 9, scope: !29) 87 | !29 = distinct !DILexicalBlock(scope: !21, file: !10, line: 13, column: 9) 88 | !30 = !DILocation(line: 13, column: 9, scope: !21) 89 | !31 = !DILocalVariable(name: "p", scope: !21, file: !10, line: 11, type: !13) 90 | !32 = !DILocation(line: 0, scope: !21) 91 | !33 = !DILocalVariable(name: "q", scope: !21, file: !10, line: 11, type: !13) 92 | !34 = !DILocation(line: 16, column: 9, scope: !35) 93 | !35 = distinct !DILexicalBlock(scope: !29, file: !10, line: 13, column: 12) 94 | !36 = !DILocation(line: 17, column: 5, scope: !35) 95 | !37 = !DILocation(line: 21, column: 9, scope: !38) 96 | !38 = distinct !DILexicalBlock(scope: !29, file: !10, line: 18, column: 10) 97 | !39 = !DILocation(line: 23, column: 5, scope: !21) 98 | -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/pta/test3.c: -------------------------------------------------------------------------------- 1 | extern void MAYALIAS(void* p, void* q); 2 | 3 | void foo(int *m, int *n) 4 | { 5 | MAYALIAS(m,n); 6 | int x, y; 7 | x = *n; 8 | y = *m; 9 | *m = x; 10 | *n = y; 11 | } 12 | 13 | int main() 14 | { 15 | int *p, *q; 16 | int a, b, c; 17 | if (c) { 18 | p = &a; 19 | q = &b; 20 | foo(p,q); 21 | } 22 | else { 23 | p = &b; 24 | q = &c; 25 | foo(p,q); 26 | } 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/pta/test4.c: -------------------------------------------------------------------------------- 1 | extern void MAYALIAS(void* p, void* q); 2 | extern void NOALIAS(void* p, void* q); 3 | 4 | typedef struct { 5 | int *ptr1; 6 | int value; 7 | int *ptr2; 8 | } MyStruct; 9 | 10 | int main() { 11 | int a = 10; 12 | int b = 20; 13 | MyStruct s1, s2; 14 | 15 | s1.ptr1 = &a; 16 | s1.ptr2 = &a; 17 | s2.ptr1 = &b; 18 | s2.ptr2 = &a; 19 | 20 | MAYALIAS(s1.ptr1, s1.ptr2); 21 | 22 | MAYALIAS(s1.ptr2, s2.ptr2); 23 | 24 | return 0; 25 | } 26 | -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/pta/test4.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test4.ll' 2 | source_filename = "./test4.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | %struct.MyStruct = type { ptr, i32, ptr } 7 | 8 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 9 | define i32 @main() #0 !dbg !9 { 10 | entry: 11 | %a = alloca i32, align 4 12 | %b = alloca i32, align 4 13 | %s1 = alloca %struct.MyStruct, align 8 14 | %s2 = alloca %struct.MyStruct, align 8 15 | call void @llvm.dbg.declare(metadata ptr %a, metadata !15, metadata !DIExpression()), !dbg !16 16 | store i32 10, ptr %a, align 4, !dbg !16 17 | call void @llvm.dbg.declare(metadata ptr %b, metadata !17, metadata !DIExpression()), !dbg !18 18 | store i32 20, ptr %b, align 4, !dbg !18 19 | call void @llvm.dbg.declare(metadata ptr %s1, metadata !19, metadata !DIExpression()), !dbg !27 20 | call void @llvm.dbg.declare(metadata ptr %s2, metadata !28, metadata !DIExpression()), !dbg !29 21 | %ptr1 = getelementptr inbounds %struct.MyStruct, ptr %s1, i32 0, i32 0, !dbg !30 22 | store ptr %a, ptr %ptr1, align 8, !dbg !31 23 | %ptr2 = getelementptr inbounds %struct.MyStruct, ptr %s1, i32 0, i32 2, !dbg !32 24 | store ptr %a, ptr %ptr2, align 8, !dbg !33 25 | %ptr11 = getelementptr inbounds %struct.MyStruct, ptr %s2, i32 0, i32 0, !dbg !34 26 | store ptr %b, ptr %ptr11, align 8, !dbg !35 27 | %ptr22 = getelementptr inbounds %struct.MyStruct, ptr %s2, i32 0, i32 2, !dbg !36 28 | store ptr %a, ptr %ptr22, align 8, !dbg !37 29 | %ptr13 = getelementptr inbounds %struct.MyStruct, ptr %s1, i32 0, i32 0, !dbg !38 30 | %0 = load ptr, ptr %ptr13, align 8, !dbg !38 31 | %ptr24 = getelementptr inbounds %struct.MyStruct, ptr %s1, i32 0, i32 2, !dbg !39 32 | %1 = load ptr, ptr %ptr24, align 8, !dbg !39 33 | call void @MAYALIAS(ptr noundef %0, ptr noundef %1), !dbg !40 34 | %ptr25 = getelementptr inbounds %struct.MyStruct, ptr %s1, i32 0, i32 2, !dbg !41 35 | %2 = load ptr, ptr %ptr25, align 8, !dbg !41 36 | %ptr26 = getelementptr inbounds %struct.MyStruct, ptr %s2, i32 0, i32 2, !dbg !42 37 | %3 = load ptr, ptr %ptr26, align 8, !dbg !42 38 | call void @MAYALIAS(ptr noundef %2, ptr noundef %3), !dbg !43 39 | ret i32 0, !dbg !44 40 | } 41 | 42 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 43 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 44 | 45 | declare void @MAYALIAS(ptr noundef, ptr noundef) #2 46 | 47 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 48 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 49 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 50 | 51 | !llvm.dbg.cu = !{!0} 52 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 53 | !llvm.ident = !{!8} 54 | 55 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 56 | !1 = !DIFile(filename: "test4.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/pta") 57 | !2 = !{i32 7, !"Dwarf Version", i32 4} 58 | !3 = !{i32 2, !"Debug Info Version", i32 3} 59 | !4 = !{i32 1, !"wchar_size", i32 4} 60 | !5 = !{i32 8, !"PIC Level", i32 2} 61 | !6 = !{i32 7, !"uwtable", i32 1} 62 | !7 = !{i32 7, !"frame-pointer", i32 1} 63 | !8 = !{!"Homebrew clang version 16.0.6"} 64 | !9 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 10, type: !11, scopeLine: 10, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) 65 | !10 = !DIFile(filename: "./test4.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/pta") 66 | !11 = !DISubroutineType(types: !12) 67 | !12 = !{!13} 68 | !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 69 | !14 = !{} 70 | !15 = !DILocalVariable(name: "a", scope: !9, file: !10, line: 11, type: !13) 71 | !16 = !DILocation(line: 11, column: 9, scope: !9) 72 | !17 = !DILocalVariable(name: "b", scope: !9, file: !10, line: 12, type: !13) 73 | !18 = !DILocation(line: 12, column: 9, scope: !9) 74 | !19 = !DILocalVariable(name: "s1", scope: !9, file: !10, line: 13, type: !20) 75 | !20 = !DIDerivedType(tag: DW_TAG_typedef, name: "MyStruct", file: !10, line: 8, baseType: !21) 76 | !21 = distinct !DICompositeType(tag: DW_TAG_structure_type, file: !10, line: 4, size: 192, elements: !22) 77 | !22 = !{!23, !25, !26} 78 | !23 = !DIDerivedType(tag: DW_TAG_member, name: "ptr1", scope: !21, file: !10, line: 5, baseType: !24, size: 64) 79 | !24 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) 80 | !25 = !DIDerivedType(tag: DW_TAG_member, name: "value", scope: !21, file: !10, line: 6, baseType: !13, size: 32, offset: 64) 81 | !26 = !DIDerivedType(tag: DW_TAG_member, name: "ptr2", scope: !21, file: !10, line: 7, baseType: !24, size: 64, offset: 128) 82 | !27 = !DILocation(line: 13, column: 14, scope: !9) 83 | !28 = !DILocalVariable(name: "s2", scope: !9, file: !10, line: 13, type: !20) 84 | !29 = !DILocation(line: 13, column: 18, scope: !9) 85 | !30 = !DILocation(line: 15, column: 8, scope: !9) 86 | !31 = !DILocation(line: 15, column: 13, scope: !9) 87 | !32 = !DILocation(line: 16, column: 8, scope: !9) 88 | !33 = !DILocation(line: 16, column: 13, scope: !9) 89 | !34 = !DILocation(line: 17, column: 8, scope: !9) 90 | !35 = !DILocation(line: 17, column: 13, scope: !9) 91 | !36 = !DILocation(line: 18, column: 8, scope: !9) 92 | !37 = !DILocation(line: 18, column: 13, scope: !9) 93 | !38 = !DILocation(line: 20, column: 17, scope: !9) 94 | !39 = !DILocation(line: 20, column: 26, scope: !9) 95 | !40 = !DILocation(line: 20, column: 5, scope: !9) 96 | !41 = !DILocation(line: 22, column: 17, scope: !9) 97 | !42 = !DILocation(line: 22, column: 26, scope: !9) 98 | !43 = !DILocation(line: 22, column: 5, scope: !9) 99 | !44 = !DILocation(line: 24, column: 5, scope: !9) 100 | -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/taint/test1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | extern void MAYALIAS(void* p, void* q); 4 | extern void broadcast(char* num); 5 | char *tgetstr(){ 6 | // e.g. sql injection init 7 | static char initstr[25] = "select* From City .."; 8 | return initstr; 9 | } 10 | 11 | 12 | int main(){ 13 | char *injection = tgetstr(); 14 | char* s = injection; 15 | char* b = s; 16 | MAYALIAS(injection, s); 17 | broadcast(b); 18 | 19 | return 0; 20 | } -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/taint/test1.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test1.ll' 2 | source_filename = "./test1.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | @tgetstr.initstr = internal global [25 x i8] c"select* From City ..\00\00\00\00\00", align 1, !dbg !0 7 | 8 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 9 | define ptr @tgetstr() #0 !dbg !2 { 10 | entry: 11 | ret ptr @tgetstr.initstr, !dbg !22 12 | } 13 | 14 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 15 | define i32 @main() #0 !dbg !23 { 16 | entry: 17 | %call = call ptr @tgetstr(), !dbg !27 18 | call void @llvm.dbg.value(metadata ptr %call, metadata !28, metadata !DIExpression()), !dbg !29 19 | call void @llvm.dbg.value(metadata ptr %call, metadata !30, metadata !DIExpression()), !dbg !29 20 | call void @llvm.dbg.value(metadata ptr %call, metadata !31, metadata !DIExpression()), !dbg !29 21 | call void @MAYALIAS(ptr noundef %call, ptr noundef %call), !dbg !32 22 | call void @broadcast(ptr noundef %call), !dbg !33 23 | ret i32 0, !dbg !34 24 | } 25 | 26 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 27 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 28 | 29 | declare void @MAYALIAS(ptr noundef, ptr noundef) #2 30 | 31 | declare void @broadcast(ptr noundef) #2 32 | 33 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 34 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 35 | 36 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 37 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 38 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 39 | 40 | !llvm.dbg.cu = !{!8} 41 | !llvm.module.flags = !{!15, !16, !17, !18, !19, !20} 42 | !llvm.ident = !{!21} 43 | 44 | !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) 45 | !1 = distinct !DIGlobalVariable(name: "initstr", scope: !2, file: !3, line: 7, type: !12, isLocal: true, isDefinition: true) 46 | !2 = distinct !DISubprogram(name: "tgetstr", scope: !3, file: !3, line: 5, type: !4, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !8, retainedNodes: !11) 47 | !3 = !DIFile(filename: "./test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/taint") 48 | !4 = !DISubroutineType(types: !5) 49 | !5 = !{!6} 50 | !6 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !7, size: 64) 51 | !7 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) 52 | !8 = distinct !DICompileUnit(language: DW_LANG_C11, file: !9, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !10, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 53 | !9 = !DIFile(filename: "test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-1/Tests/testcases/taint") 54 | !10 = !{!0} 55 | !11 = !{} 56 | !12 = !DICompositeType(tag: DW_TAG_array_type, baseType: !7, size: 200, elements: !13) 57 | !13 = !{!14} 58 | !14 = !DISubrange(count: 25) 59 | !15 = !{i32 7, !"Dwarf Version", i32 4} 60 | !16 = !{i32 2, !"Debug Info Version", i32 3} 61 | !17 = !{i32 1, !"wchar_size", i32 4} 62 | !18 = !{i32 8, !"PIC Level", i32 2} 63 | !19 = !{i32 7, !"uwtable", i32 1} 64 | !20 = !{i32 7, !"frame-pointer", i32 1} 65 | !21 = !{!"Homebrew clang version 16.0.6"} 66 | !22 = !DILocation(line: 8, column: 5, scope: !2) 67 | !23 = distinct !DISubprogram(name: "main", scope: !3, file: !3, line: 12, type: !24, scopeLine: 12, spFlags: DISPFlagDefinition, unit: !8, retainedNodes: !11) 68 | !24 = !DISubroutineType(types: !25) 69 | !25 = !{!26} 70 | !26 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 71 | !27 = !DILocation(line: 13, column: 23, scope: !23) 72 | !28 = !DILocalVariable(name: "injection", scope: !23, file: !3, line: 13, type: !6) 73 | !29 = !DILocation(line: 0, scope: !23) 74 | !30 = !DILocalVariable(name: "s", scope: !23, file: !3, line: 14, type: !6) 75 | !31 = !DILocalVariable(name: "b", scope: !23, file: !3, line: 15, type: !6) 76 | !32 = !DILocation(line: 16, column: 5, scope: !23) 77 | !33 = !DILocation(line: 17, column: 5, scope: !23) 78 | !34 = !DILocation(line: 19, column: 5, scope: !23) 79 | -------------------------------------------------------------------------------- /Assignment-1/Tests/testcases/taint/test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | extern void broadcast(char*); 4 | char* getchar(){ return "/0 "; }; //init a char number 5 | extern void MAYALIAS(void* p, void* q); 6 | int main(){ 7 | bool loopCondition = true; 8 | bool BranchCondition = true; 9 | char* secretToken = getchar(); // source 10 | while(loopCondition){ 11 | if(BranchCondition){ 12 | char* a = secretToken; 13 | broadcast(a); // sink 14 | MAYALIAS(a,secretToken); 15 | } 16 | else{ 17 | char* b = "hello"; 18 | } 19 | } 20 | } -------------------------------------------------------------------------------- /Assignment-2/CPP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories( ${Z3MGR_DIR}) 2 | file(GLOB SOURCES 3 | *.cpp 4 | ${Z3MGR_DIR}/*.cpp 5 | ) 6 | list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/test-sse.cpp") 7 | set(LIB ${SVF_LIB} ${llvm_libs} ${Z3_LIBRARIES}) 8 | add_library(assign-2 ${SOURCES}) 9 | target_link_libraries(assign-2 ${LIB}) 10 | set_target_properties(assign-2 PROPERTIES 11 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 12 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 13 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 14 | ) 15 | add_executable(ass2 test-sse.cpp) 16 | target_link_libraries(ass2 ${LIB} assign-2) 17 | set_target_properties(ass2 PROPERTIES 18 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 19 | 20 | message(STATUS "Adding test for sse_assert_files") 21 | file(GLOB ass2files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/../Tests "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/testcases/sse/*.ll") 22 | message(STATUS "file for sse_assert_files: ${ass2files}") 23 | foreach(filename ${ass2files}) 24 | message(STATUS "Adding test for ${filename}") 25 | add_test( 26 | NAME ass2-cpp/${filename} 27 | COMMAND ass2 ${CMAKE_CURRENT_SOURCE_DIR}/../Tests/${filename} 28 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin 29 | ) 30 | endforeach() 31 | -------------------------------------------------------------------------------- /Assignment-2/CPP/Z3SSEMgr.h: -------------------------------------------------------------------------------- 1 | //===- Z3Mgr.h -- Z3 manager for symbolic execution ------------------// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2022> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===----------------------------------------------------------------------===// 22 | /* 23 | * Z3 manager for symbolic execution 24 | * 25 | * Created on: Feb 19, 2024 26 | */ 27 | 28 | #ifndef SOFTWARE_SECURITY_ANALYSIS_Z3SSEMGR_H 29 | #define SOFTWARE_SECURITY_ANALYSIS_Z3SSEMGR_H 30 | 31 | #include "Z3Mgr.h" 32 | #include "SVFIR/SVFIR.h" 33 | 34 | namespace SVF { 35 | 36 | class SVFIR; 37 | class ValVar; 38 | class ObjVar; 39 | class GepStmt; 40 | 41 | class Z3SSEMgr : public Z3Mgr { 42 | typedef std::vector CallStack; 43 | public: 44 | /// Constructor 45 | Z3SSEMgr(SVFIR* ir); 46 | 47 | 48 | std::string callingCtxToStr(const CallStack& callingCtx); 49 | 50 | z3::expr getZ3Expr(u32_t idx, const CallStack& callingCtx); 51 | 52 | /// Initialize the expr value for each objects (address-taken variables and constants) 53 | z3::expr createExprForObjVar(const ObjVar* obj); 54 | 55 | /// Return the address expr of a ObjVar 56 | z3::expr getMemObjAddress(u32_t idx); 57 | 58 | /// Return the field address given a pointer points to a struct object and an offset 59 | z3::expr getGepObjAddress(z3::expr pointer, u32_t offset); 60 | 61 | /// Return the offset expression of a GepStmt 62 | s32_t getGepOffset(const GepStmt* gep, const CallStack& callingCtx); 63 | 64 | /// Dump values of all exprs 65 | virtual void printExprValues(const CallStack& callingCtx); 66 | 67 | private: 68 | SVFIR* svfir; 69 | }; 70 | 71 | } // namespace SVF 72 | 73 | #endif // SOFTWARE_SECURITY_ANALYSIS_Z3MGR_H 74 | -------------------------------------------------------------------------------- /Assignment-2/CPP/test-sse.cpp: -------------------------------------------------------------------------------- 1 | #include "Assignment_2.h" 2 | #include "SVF-LLVM/LLVMUtil.h" 3 | #include "Util/CommandLine.h" 4 | #include "Util/Options.h" 5 | #include "WPA/Andersen.h" 6 | 7 | using namespace SVF; 8 | using namespace SVFUtil; 9 | u32_t SSE::assert_checked = 0; 10 | 11 | /* 12 | // Software-Verification-Teaching Assignment 4 main function entry 13 | // To run your program with testcases , please set the bitcode from Assignment-2/Tests/testcases/sse/ for "args" in 14 | file'.vscode/launch.json' 15 | // e.g. To check test1, set "args": ["Assignment-2/Tests/testcases/sse/test1.ll"] in file'.vscode/launch.json' 16 | */ 17 | int main(int argc, char** argv) { 18 | int arg_num = 0; 19 | int extraArgc = 4; 20 | char** arg_value = new char*[argc + extraArgc]; 21 | for (; arg_num < argc; ++arg_num) { 22 | arg_value[arg_num] = argv[arg_num]; 23 | } 24 | std::vector moduleNameVec; 25 | 26 | int orgArgNum = arg_num; 27 | arg_value[arg_num++] = (char*)"-model-arrays=true"; 28 | arg_value[arg_num++] = (char*)"-pre-field-sensitive=false"; 29 | arg_value[arg_num++] = (char*)"-model-consts=true"; 30 | arg_value[arg_num++] = (char*)"-stat=false"; 31 | assert(arg_num == (orgArgNum + extraArgc) && "more extra arguments? Change the value of extraArgc"); 32 | 33 | moduleNameVec = OptionBase::parseOptions(arg_num, 34 | arg_value, 35 | "Software-Verification-Teaching Assignment 4", 36 | "[options] "); 37 | 38 | LLVMModuleSet::getLLVMModuleSet()->buildSVFModule(moduleNameVec); 39 | LLVMModuleSet::getLLVMModuleSet()->dumpModulesToFile(".svf"); 40 | 41 | SVFIRBuilder builder; 42 | SVFIR* svfir = builder.build(); 43 | 44 | CallGraph* callgraph = AndersenWaveDiff::createAndersenWaveDiff(svfir)->getCallGraph(); 45 | builder.updateCallGraph(callgraph); 46 | 47 | /// ICFG 48 | ICFG* icfg = svfir->getICFG(); 49 | icfg->updateCallGraph(callgraph); 50 | icfg->dump(moduleNameVec[0] + ".icfg"); 51 | 52 | SSE* sse = new SSE(svfir, icfg); 53 | sse->analyse(); 54 | 55 | SVF::LLVMModuleSet::releaseLLVMModuleSet(); 56 | SVF::SVFIR::releaseSVFIR(); 57 | 58 | delete[] arg_value; 59 | delete sse; 60 | if (SSE::assert_checked > 0) { 61 | return 0; 62 | } 63 | else { 64 | std::cerr << "No assertion was checked!" << std::endl; 65 | return 1; 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /Assignment-2/Python/Assignment_2.py: -------------------------------------------------------------------------------- 1 | 2 | from Z3SSEMgr import * 3 | 4 | 5 | class Assignment2(SSE): 6 | def __init__(self, svfir: pysvf.SVFIR) -> None: 7 | super().__init__(svfir) 8 | 9 | ''' 10 | /// TODO: collect each path once this method is called during reachability analysis, and 11 | /// Collect each program path from the entry to each assertion of the program. In this function, 12 | /// you will need (1) add each path into the paths set, (2) call translatePath to convert each path into Z3 expressions. 13 | /// Note that translatePath returns true if the path is feasible, false if the path is infeasible. (3) If a path is feasible, 14 | /// you will need to call assertchecking to verify the assertion (which is the last ICFGNode of this path). 15 | ''' 16 | def collectAndTranslatePath(self, path: list) -> None: 17 | assert isinstance(path, list), "path is not a valid list, the type of path is {}".format(type(path)) 18 | pass 19 | 20 | ''' 21 | /// TODO: Implement handling of branch statements inside a function 22 | /// Return A given branch on the ICFG looks like the following: 23 | /// ICFGNode1 (condition %cmp) 24 | /// 1 / \ 0 25 | /// ICFGNode2 ICFGNode3 26 | /// edge->getCondition() returns the branch condition variable (%cmp) of type SVFValue* (for if/else) or a numeric condition variable (for switch). 27 | /// Given the condition variable, you could obtain the SVFVar ID via "edge.getCondition().getId()" 28 | /// edge->getCondition() returns nullptr if this IntraCFGEdge is not a branch. 29 | /// edge->getSuccessorCondValue() returns the actual condition value (1/0 for if/else) when this branch/IntraCFGEdge is executed. For example, the successorCondValue is 1 on the edge from ICFGNode1 to ICFGNode2, and 0 on the edge from ICFGNode1 to ICFGNode3 30 | n true if the path is feasible, false otherwise. 31 | ''' 32 | def handleBranch(self, edge: pysvf.IntraCFGEdge) -> bool: 33 | assert isinstance(edge, pysvf.IntraCFGEdge), "edge is not a valid IntraCFGEdge object, the type of edge is {}".format(type(edge)) 34 | assert edge.getCondition() and "not a conditional control-flow transfer?" 35 | cond = self.z3mgr.getZ3Expr(edge.getCondition().getId(), self.callingCtx) 36 | successor_val = self.z3mgr.getZ3Val(edge.getSuccessorCondValue()) 37 | pass 38 | 39 | ''' 40 | /// TODO: Implement handling of function calls 41 | ''' 42 | def handleCall(self, edge: pysvf.CallCFGEdge) -> None: 43 | assert isinstance(edge, pysvf.CallCFGEdge), "edge is not a valid CallCFGEdge object, the type of edge is {}".format(type(edge)) 44 | pass 45 | 46 | 47 | ''' 48 | /// TODO: Implement handling of function returns 49 | ''' 50 | def handleRet(self, edge: pysvf.RetCFGEdge) -> None: 51 | assert isinstance(edge, pysvf.RetCFGEdge), "edge is not a valid RetCFGEdge object, the type of edge is {}".format(type(edge)) 52 | pass 53 | 54 | ''' 55 | /// TODO: Translate AddrStmt, CopyStmt, LoadStmt, StoreStmt, GepStmt and CmpStmt 56 | /// Translate AddrStmt, CopyStmt, LoadStmt, StoreStmt, GepStmt, BinaryOPStmt, CmpStmt, SelectStmt, and PhiStmt 57 | ''' 58 | def handleNonBranch(self, edge: pysvf.IntraCFGEdge) -> bool: 59 | assert isinstance(edge, pysvf.IntraCFGEdge), "edge is not a valid IntraCFGEdge object, the type of edge is {}".format(type(edge)) 60 | pass 61 | 62 | def handleIntra(self, edge: pysvf.IntraCFGEdge) -> bool: 63 | assert isinstance(edge, pysvf.IntraCFGEdge), "edge is not a valid IntraCFGEdge object, the type of edge is {}".format(type(edge)) 64 | if edge.getCondition(): 65 | if self.handleBranch(edge) is False: 66 | return False 67 | return self.handleNonBranch(edge) 68 | 69 | ''' 70 | /// TODO: Implement your context-sensitive ICFG traversal here to traverse each program path (once for any loop) from 71 | /// You will need to collect each path from src node to snk node and then add the path to the `paths` set by 72 | /// calling the `collectAndTranslatePath` method which is then trigger the path translation. 73 | /// This implementation, slightly different from Assignment-1, requires ICFGNode* as the first argument. 74 | ''' 75 | def reachability(self, cur_edge: pysvf.ICFGEdge, sink: pysvf.ICFGNode) -> None: 76 | assert isinstance(cur_edge, pysvf.ICFGEdge) and "cur_edge is not a valid IntraCFGEdge object" 77 | assert isinstance(sink, pysvf.ICFGNode) and "sink is not a valid ICFGNode object" 78 | pass 79 | 80 | 81 | 82 | 83 | 84 | -------------------------------------------------------------------------------- /Assignment-2/Python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | message(STATUS "Adding test for sse_assert_files") 2 | file(GLOB ass2files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/../Tests "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/testcases/sse/*.ll") 3 | message(STATUS "file for sse_assert_files: ${ass2files}") 4 | foreach(filename ${ass2files}) 5 | message(STATUS "Adding test for ${filename}") 6 | add_test( 7 | NAME ass2-py/${filename} 8 | COMMAND python3 test-sse.py ${CMAKE_CURRENT_SOURCE_DIR}/../Tests/${filename} 9 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 10 | ) 11 | endforeach() -------------------------------------------------------------------------------- /Assignment-2/Python/test-sse.py: -------------------------------------------------------------------------------- 1 | from Assignment_2 import * 2 | 3 | if __name__ == "__main__": 4 | # check sys.argv and print friendly error message if not enough arguments 5 | if len(sys.argv) < 2: 6 | print("Usage: python3 test-sse.py ") 7 | sys.exit(1) 8 | pysvf.buildSVFModule(sys.argv[1:]) 9 | pag = pysvf.getPAG() 10 | ass4 = Assignment2(pag) 11 | ass4.analyse() -------------------------------------------------------------------------------- /Assignment-2/Tests/testcases/sse/test1.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | //ADDR, LOAD, STORE, CAST(COPY) 3 | extern void svf_assert(bool); 4 | 5 | int main() { 6 | int *p; 7 | int a = 1; 8 | p = &a; 9 | *p = 3; 10 | svf_assert(a == 3); 11 | } -------------------------------------------------------------------------------- /Assignment-2/Tests/testcases/sse/test1.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test1.ll' 2 | source_filename = "./test1.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define i32 @main() #0 !dbg !9 { 8 | entry: 9 | call void @llvm.dbg.value(metadata i32 1, metadata !15, metadata !DIExpression()), !dbg !16 10 | call void @llvm.dbg.value(metadata ptr undef, metadata !17, metadata !DIExpression()), !dbg !16 11 | call void @llvm.dbg.value(metadata i32 3, metadata !15, metadata !DIExpression()), !dbg !16 12 | %cmp = icmp eq i32 3, 3, !dbg !19 13 | call void @svf_assert(i1 noundef zeroext %cmp), !dbg !20 14 | ret i32 0, !dbg !21 15 | } 16 | 17 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 18 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 19 | 20 | declare void @svf_assert(i1 noundef zeroext) #2 21 | 22 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 23 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 24 | 25 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 26 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 27 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 28 | 29 | !llvm.dbg.cu = !{!0} 30 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 31 | !llvm.ident = !{!8} 32 | 33 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 34 | !1 = !DIFile(filename: "test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-2/Tests/testcases/sse") 35 | !2 = !{i32 7, !"Dwarf Version", i32 4} 36 | !3 = !{i32 2, !"Debug Info Version", i32 3} 37 | !4 = !{i32 1, !"wchar_size", i32 4} 38 | !5 = !{i32 8, !"PIC Level", i32 2} 39 | !6 = !{i32 7, !"uwtable", i32 1} 40 | !7 = !{i32 7, !"frame-pointer", i32 1} 41 | !8 = !{!"Homebrew clang version 16.0.6"} 42 | !9 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 5, type: !11, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) 43 | !10 = !DIFile(filename: "./test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-2/Tests/testcases/sse") 44 | !11 = !DISubroutineType(types: !12) 45 | !12 = !{!13} 46 | !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 47 | !14 = !{} 48 | !15 = !DILocalVariable(name: "a", scope: !9, file: !10, line: 7, type: !13) 49 | !16 = !DILocation(line: 0, scope: !9) 50 | !17 = !DILocalVariable(name: "p", scope: !9, file: !10, line: 6, type: !18) 51 | !18 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) 52 | !19 = !DILocation(line: 10, column: 18, scope: !9) 53 | !20 = !DILocation(line: 10, column: 5, scope: !9) 54 | !21 = !DILocation(line: 11, column: 1, scope: !9) 55 | -------------------------------------------------------------------------------- /Assignment-2/Tests/testcases/sse/test2.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | //ADDR, LOAD, STORE, CAST(COPY) 3 | extern void svf_assert(bool); 4 | 5 | void foo(int* p) { 6 | *p = 1; 7 | } 8 | 9 | int main() { 10 | int a = 0; 11 | foo(&a); 12 | svf_assert(a == 1); 13 | } -------------------------------------------------------------------------------- /Assignment-2/Tests/testcases/sse/test2.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test2.ll' 2 | source_filename = "./test2.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define void @foo(ptr noundef %p) #0 !dbg !9 { 8 | entry: 9 | call void @llvm.dbg.value(metadata ptr %p, metadata !16, metadata !DIExpression()), !dbg !17 10 | store i32 1, ptr %p, align 4, !dbg !18 11 | ret void, !dbg !19 12 | } 13 | 14 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 15 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 16 | 17 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 18 | define i32 @main() #0 !dbg !20 { 19 | entry: 20 | %a = alloca i32, align 4 21 | call void @llvm.dbg.declare(metadata ptr %a, metadata !23, metadata !DIExpression()), !dbg !24 22 | store i32 0, ptr %a, align 4, !dbg !24 23 | call void @foo(ptr noundef %a), !dbg !25 24 | %0 = load i32, ptr %a, align 4, !dbg !26 25 | %cmp = icmp eq i32 %0, 1, !dbg !27 26 | call void @svf_assert(i1 noundef zeroext %cmp), !dbg !28 27 | ret i32 0, !dbg !29 28 | } 29 | 30 | declare void @svf_assert(i1 noundef zeroext) #2 31 | 32 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 33 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 34 | 35 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 36 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 37 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 38 | 39 | !llvm.dbg.cu = !{!0} 40 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 41 | !llvm.ident = !{!8} 42 | 43 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 44 | !1 = !DIFile(filename: "test2.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-2/Tests/testcases/sse") 45 | !2 = !{i32 7, !"Dwarf Version", i32 4} 46 | !3 = !{i32 2, !"Debug Info Version", i32 3} 47 | !4 = !{i32 1, !"wchar_size", i32 4} 48 | !5 = !{i32 8, !"PIC Level", i32 2} 49 | !6 = !{i32 7, !"uwtable", i32 1} 50 | !7 = !{i32 7, !"frame-pointer", i32 1} 51 | !8 = !{!"Homebrew clang version 16.0.6"} 52 | !9 = distinct !DISubprogram(name: "foo", scope: !10, file: !10, line: 5, type: !11, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !15) 53 | !10 = !DIFile(filename: "./test2.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-2/Tests/testcases/sse") 54 | !11 = !DISubroutineType(types: !12) 55 | !12 = !{null, !13} 56 | !13 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !14, size: 64) 57 | !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 58 | !15 = !{} 59 | !16 = !DILocalVariable(name: "p", arg: 1, scope: !9, file: !10, line: 5, type: !13) 60 | !17 = !DILocation(line: 0, scope: !9) 61 | !18 = !DILocation(line: 6, column: 8, scope: !9) 62 | !19 = !DILocation(line: 7, column: 1, scope: !9) 63 | !20 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 9, type: !21, scopeLine: 9, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !15) 64 | !21 = !DISubroutineType(types: !22) 65 | !22 = !{!14} 66 | !23 = !DILocalVariable(name: "a", scope: !20, file: !10, line: 10, type: !14) 67 | !24 = !DILocation(line: 10, column: 9, scope: !20) 68 | !25 = !DILocation(line: 11, column: 5, scope: !20) 69 | !26 = !DILocation(line: 12, column: 16, scope: !20) 70 | !27 = !DILocation(line: 12, column: 18, scope: !20) 71 | !28 = !DILocation(line: 12, column: 5, scope: !20) 72 | !29 = !DILocation(line: 13, column: 1, scope: !20) 73 | -------------------------------------------------------------------------------- /Assignment-2/Tests/testcases/sse/test3.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | // CHECK: ^sat$ 3 | 4 | extern int nd(void); 5 | 6 | extern void svf_assert(bool); 7 | 8 | int test(int a, int b){ 9 | int x,y; 10 | x=1; y=1; 11 | 12 | if (a > b) { 13 | x++; 14 | y++; 15 | svf_assert (x == y); 16 | } else { 17 | x++; 18 | svf_assert (x == 2); 19 | } 20 | return 0; 21 | } 22 | 23 | int main(){ 24 | int a = 1; 25 | int b = 2; 26 | test(a,b); 27 | return 0; 28 | } -------------------------------------------------------------------------------- /Assignment-2/Tests/testcases/sse/test3.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test3.ll' 2 | source_filename = "./test3.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define i32 @test(i32 noundef %a, i32 noundef %b) #0 !dbg !9 { 8 | entry: 9 | call void @llvm.dbg.value(metadata i32 %a, metadata !15, metadata !DIExpression()), !dbg !16 10 | call void @llvm.dbg.value(metadata i32 %b, metadata !17, metadata !DIExpression()), !dbg !16 11 | call void @llvm.dbg.value(metadata i32 1, metadata !18, metadata !DIExpression()), !dbg !16 12 | call void @llvm.dbg.value(metadata i32 1, metadata !19, metadata !DIExpression()), !dbg !16 13 | %cmp = icmp sgt i32 %a, %b, !dbg !20 14 | br i1 %cmp, label %if.then, label %if.else, !dbg !22 15 | 16 | if.then: ; preds = %entry 17 | %inc = add nsw i32 1, 1, !dbg !23 18 | call void @llvm.dbg.value(metadata i32 %inc, metadata !18, metadata !DIExpression()), !dbg !16 19 | %inc1 = add nsw i32 1, 1, !dbg !25 20 | call void @llvm.dbg.value(metadata i32 %inc1, metadata !19, metadata !DIExpression()), !dbg !16 21 | %cmp2 = icmp eq i32 %inc, %inc1, !dbg !26 22 | call void @svf_assert(i1 noundef zeroext %cmp2), !dbg !27 23 | br label %if.end, !dbg !28 24 | 25 | if.else: ; preds = %entry 26 | %inc3 = add nsw i32 1, 1, !dbg !29 27 | call void @llvm.dbg.value(metadata i32 %inc3, metadata !18, metadata !DIExpression()), !dbg !16 28 | %cmp4 = icmp eq i32 %inc3, 2, !dbg !31 29 | call void @svf_assert(i1 noundef zeroext %cmp4), !dbg !32 30 | br label %if.end 31 | 32 | if.end: ; preds = %if.else, %if.then 33 | ret i32 0, !dbg !33 34 | } 35 | 36 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 37 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 38 | 39 | declare void @svf_assert(i1 noundef zeroext) #2 40 | 41 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 42 | define i32 @main() #0 !dbg !34 { 43 | entry: 44 | call void @llvm.dbg.value(metadata i32 1, metadata !37, metadata !DIExpression()), !dbg !38 45 | call void @llvm.dbg.value(metadata i32 2, metadata !39, metadata !DIExpression()), !dbg !38 46 | %call = call i32 @test(i32 noundef 1, i32 noundef 2), !dbg !40 47 | ret i32 0, !dbg !41 48 | } 49 | 50 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 51 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 52 | 53 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 54 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 55 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 56 | 57 | !llvm.dbg.cu = !{!0} 58 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 59 | !llvm.ident = !{!8} 60 | 61 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 62 | !1 = !DIFile(filename: "test3.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-2/Tests/testcases/sse") 63 | !2 = !{i32 7, !"Dwarf Version", i32 4} 64 | !3 = !{i32 2, !"Debug Info Version", i32 3} 65 | !4 = !{i32 1, !"wchar_size", i32 4} 66 | !5 = !{i32 8, !"PIC Level", i32 2} 67 | !6 = !{i32 7, !"uwtable", i32 1} 68 | !7 = !{i32 7, !"frame-pointer", i32 1} 69 | !8 = !{!"Homebrew clang version 16.0.6"} 70 | !9 = distinct !DISubprogram(name: "test", scope: !10, file: !10, line: 8, type: !11, scopeLine: 8, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) 71 | !10 = !DIFile(filename: "./test3.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-2/Tests/testcases/sse") 72 | !11 = !DISubroutineType(types: !12) 73 | !12 = !{!13, !13, !13} 74 | !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 75 | !14 = !{} 76 | !15 = !DILocalVariable(name: "a", arg: 1, scope: !9, file: !10, line: 8, type: !13) 77 | !16 = !DILocation(line: 0, scope: !9) 78 | !17 = !DILocalVariable(name: "b", arg: 2, scope: !9, file: !10, line: 8, type: !13) 79 | !18 = !DILocalVariable(name: "x", scope: !9, file: !10, line: 9, type: !13) 80 | !19 = !DILocalVariable(name: "y", scope: !9, file: !10, line: 9, type: !13) 81 | !20 = !DILocation(line: 12, column: 11, scope: !21) 82 | !21 = distinct !DILexicalBlock(scope: !9, file: !10, line: 12, column: 9) 83 | !22 = !DILocation(line: 12, column: 9, scope: !9) 84 | !23 = !DILocation(line: 13, column: 10, scope: !24) 85 | !24 = distinct !DILexicalBlock(scope: !21, file: !10, line: 12, column: 16) 86 | !25 = !DILocation(line: 14, column: 10, scope: !24) 87 | !26 = !DILocation(line: 15, column: 23, scope: !24) 88 | !27 = !DILocation(line: 15, column: 9, scope: !24) 89 | !28 = !DILocation(line: 16, column: 5, scope: !24) 90 | !29 = !DILocation(line: 17, column: 10, scope: !30) 91 | !30 = distinct !DILexicalBlock(scope: !21, file: !10, line: 16, column: 12) 92 | !31 = !DILocation(line: 18, column: 23, scope: !30) 93 | !32 = !DILocation(line: 18, column: 9, scope: !30) 94 | !33 = !DILocation(line: 20, column: 5, scope: !9) 95 | !34 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 23, type: !35, scopeLine: 23, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) 96 | !35 = !DISubroutineType(types: !36) 97 | !36 = !{!13} 98 | !37 = !DILocalVariable(name: "a", scope: !34, file: !10, line: 24, type: !13) 99 | !38 = !DILocation(line: 0, scope: !34) 100 | !39 = !DILocalVariable(name: "b", scope: !34, file: !10, line: 25, type: !13) 101 | !40 = !DILocation(line: 26, column: 5, scope: !34) 102 | !41 = !DILocation(line: 27, column: 5, scope: !34) 103 | -------------------------------------------------------------------------------- /Assignment-3/CPP/Assignment_3.h: -------------------------------------------------------------------------------- 1 | //===- Assignment-3.h -- Abstract Interpretation --// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2022> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===----------------------------------------------------------------------===// 22 | /* 23 | * Abstract Interpretation and buffer overflow detection 24 | * 25 | * Created on: Feb 19, 2024 26 | */ 27 | #include "Assignment_3_Helper.h" 28 | #include "AE/Svfexe/AbsExtAPI.h" 29 | #include "SVFIR/SVFIR.h" 30 | 31 | namespace SVF { 32 | /// Abstract Execution class 33 | class AbstractExecution { 34 | public: 35 | /// Constructor 36 | AbstractExecution() { 37 | } 38 | 39 | virtual void runOnModule(ICFG* icfg); 40 | 41 | static AbstractExecution& getAEInstance() 42 | { 43 | static AbstractExecution instance; 44 | return instance; 45 | } 46 | 47 | /// Handle global variables and initializations 48 | void handleGlobalNode(); 49 | 50 | /// Driver of the program 51 | virtual void analyse(); 52 | 53 | /// Handle state updates for each type of SVF statement 54 | virtual void updateAbsState(const SVFStmt* stmt); 55 | 56 | /// Fuction used to implement buffer overflow detection 57 | virtual void bufOverflowDetection(const SVFStmt* stmt); 58 | 59 | /// Report a buffer overflow for a given ICFG node 60 | void reportBufOverflow(const ICFGNode* node); 61 | 62 | // handle SVF Statements 63 | ///@{ 64 | void updateStateOnAddr(const AddrStmt* addr); 65 | void updateStateOnGep(const GepStmt* gep); 66 | void updateStateOnStore(const StoreStmt* store); 67 | void updateStateOnLoad(const LoadStmt* load); 68 | void updateStateOnCmp(const CmpStmt* cmp); 69 | void updateStateOnCall(const CallPE* call); 70 | void updateStateOnRet(const RetPE* retPE); 71 | void updateStateOnCopy(const CopyStmt* copy); 72 | void updateStateOnPhi(const PhiStmt* phi); 73 | void updateStateOnBinary(const BinaryOPStmt* binary); 74 | void updateStateOnSelect(const SelectStmt* select); 75 | void updateStateOnExtCall(const SVF::CallICFGNode* extCallNode); 76 | ///@} 77 | 78 | /// Handle stub functions for verifying abstract interpretation results 79 | void handleStubFunctions(const CallICFGNode* call); 80 | 81 | /// Mark recursive functions in the call graph 82 | void initWTO(); 83 | 84 | /// Path feasiblity handling 85 | ///@{ 86 | bool mergeStatesFromPredecessors(const ICFGNode* curNode, AbstractState& as); 87 | 88 | bool isCmpBranchFeasible(const CmpStmt* cmpStmt, s64_t succ, AbstractState& as); 89 | bool isSwitchBranchFeasible(const SVFVar* var, s64_t succ, AbstractState& as); 90 | bool isBranchFeasible(const IntraCFGEdge* intraEdge, AbstractState& as); 91 | ///@} 92 | 93 | /// Handle a call site in the control flow graph 94 | void handleCallSite(const CallICFGNode* callnode); 95 | bool isExternalCallForAssignment(const SVF::FunObjVar* func); 96 | 97 | /// Handle a function in the ICFG 98 | void handleFunction(const ICFGNode* funEntry); 99 | 100 | /// Get the next nodes of a node 101 | std::vector getNextNodes(const ICFGNode* node) const; 102 | /// Get the next nodes of a cycle 103 | std::vector getNextNodesOfCycle(const ICFGCycleWTO* cycle) const; 104 | 105 | bool handleICFGNode(const ICFGNode* node); 106 | 107 | void handleICFGCycle(const ICFGCycleWTO* cycle); 108 | 109 | /// Return its abstract state given an ICFGNode 110 | AbstractState& getAbsStateFromTrace(const ICFGNode* node) { 111 | return postAbsTrace[node]; 112 | } 113 | 114 | /// Update the offset of a GEP (GetElementPtr) object from its base address 115 | void updateGepObjOffsetFromBase(AbstractState& as, AddressValue gepAddrs, AddressValue objAddrs, IntervalValue offset); 116 | 117 | /// Return the accessing offset of an object at a GepStmt 118 | IntervalValue getAccessOffset(NodeID objId, const GepStmt* gep); 119 | 120 | void ensureAllAssertsValidated(); 121 | 122 | /// Destructor 123 | virtual ~AbstractExecution() { 124 | } 125 | 126 | protected: 127 | /// SVFIR and ICFG 128 | SVFIR* svfir; 129 | ICFG* icfg; 130 | 131 | /// Map a function to its corresponding WTO 132 | Map funcToWTO; 133 | /// A set of functions which are involved in recursions 134 | Set recursiveFuns; 135 | /// Abstract trace immediately before an ICFGNode. 136 | Map preAbsTrace; 137 | /// Abstract trace immediately after an ICFGNode. 138 | Map postAbsTrace; 139 | 140 | private: 141 | AbstractExecutionHelper bufOverflowHelper; 142 | 143 | Set assert_points; 144 | 145 | Map cycleHeadToCycle; 146 | 147 | AbsExtAPI* utils; 148 | }; 149 | 150 | } // namespace SVF 151 | -------------------------------------------------------------------------------- /Assignment-3/CPP/Assignment_3_Helper.h: -------------------------------------------------------------------------------- 1 | //===- Assignment-3-Helper.h -- Abstract Interpretation Helper funcs --// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2022> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===----------------------------------------------------------------------===// 22 | /* 23 | * Abstract Interpretation Helper Functions 24 | * 25 | * Created on: Feb 19, 2024 26 | */ 27 | 28 | #include "AE/Core/AbstractState.h" 29 | #include "AE/Svfexe/AEDetector.h" 30 | #include "AE/Core/ICFGWTO.h" 31 | #include "Util/SVFBugReport.h" 32 | namespace SVF { 33 | class AbstractExecutionHelper { 34 | public: 35 | /// Add a detected bug to the bug reporter and print the report 36 | ///@{ 37 | void addBugToReporter(const AEException& e, const ICFGNode* node) { 38 | 39 | GenericBug::EventStack eventStack; 40 | SVFBugEvent sourceInstEvent(SVFBugEvent::EventType::SourceInst, node); 41 | eventStack.push_back(sourceInstEvent); // Add the source instruction event to the event stack 42 | 43 | if (eventStack.size() == 0) { 44 | return; // If the event stack is empty, return early 45 | } 46 | 47 | std::string loc = eventStack.back().getEventLoc(); // Get the location of the last event in the stack 48 | 49 | // Check if the bug at this location has already been reported 50 | if (_bugLoc.find(loc) != _bugLoc.end()) { 51 | return; // If the bug location is already reported, return early 52 | } 53 | else { 54 | _bugLoc.insert(loc); // Otherwise, mark this location as reported 55 | } 56 | 57 | // Add the bug to the recorder with details from the event stack 58 | _recoder.addAbsExecBug(GenericBug::FULLBUFOVERFLOW, eventStack, 0, 0, 0, 0); 59 | _nodeToBugInfo[node] = e.what(); // Record the exception information for the node 60 | } 61 | 62 | void printReport() { 63 | if (_nodeToBugInfo.size() > 0) { 64 | std::cerr << "######################Buffer Overflow (" + std::to_string(_nodeToBugInfo.size()) 65 | + " found)######################\n"; 66 | std::cerr << "---------------------------------------------\n"; 67 | for (auto& it : _nodeToBugInfo) { 68 | std::cerr << it.second << "\n---------------------------------------------\n"; 69 | } 70 | } 71 | } 72 | ///@} 73 | 74 | void addToGepObjOffsetFromBase(const GepObjVar* obj, const IntervalValue& offset) { 75 | gepObjOffsetFromBase[obj] = offset; 76 | } 77 | 78 | bool hasGepObjOffsetFromBase(const GepObjVar* obj) const { 79 | return gepObjOffsetFromBase.find(obj) != gepObjOffsetFromBase.end(); 80 | } 81 | 82 | IntervalValue getGepObjOffsetFromBase(const GepObjVar* obj) const { 83 | if (hasGepObjOffsetFromBase(obj)) 84 | return gepObjOffsetFromBase.at(obj); 85 | else { 86 | assert(false && "GepObjVar not found in gepObjOffsetFromBase"); 87 | abort(); 88 | } 89 | } 90 | SVFBugReport& getBugReporter() { 91 | return _recoder; 92 | } 93 | 94 | private: 95 | /// Map a GEP objVar to its offset from the base address 96 | /// e.g. alloca [i32*10] x; lhs = gep x, 3 97 | /// gepObjOffsetFromBase[lhs] = [12, 12] 98 | Map gepObjOffsetFromBase; 99 | /// Bug reporter 100 | Set _bugLoc; 101 | SVFBugReport _recoder; 102 | Map _nodeToBugInfo; 103 | }; 104 | } 105 | -------------------------------------------------------------------------------- /Assignment-3/CPP/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | include_directories(${Z3MGR_DIR}) 2 | file(GLOB SOURCES 3 | *.cpp 4 | ) 5 | list(REMOVE_ITEM SOURCES "${CMAKE_CURRENT_SOURCE_DIR}/test-ae.cpp") 6 | set(LIB ${SVF_LIB} ${llvm_libs}) 7 | add_library(assign3 ${SOURCES}) 8 | target_link_libraries(assign3 ${LIB}) 9 | set_target_properties(assign3 PROPERTIES 10 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 11 | ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 12 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib 13 | ) 14 | add_executable(ass3 test-ae.cpp) 15 | target_link_libraries(ass3 ${LIB} assign3) 16 | set_target_properties(ass3 PROPERTIES 17 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 18 | 19 | 20 | # loops over ae_assert_files and run "ae $bc_file" 21 | file(GLOB ae_assert_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/../Tests "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/ae/*.ll") 22 | foreach(filename ${ae_assert_files}) 23 | add_test( 24 | NAME ass3-ae-cpp/${filename} 25 | COMMAND ass3 ${CMAKE_CURRENT_SOURCE_DIR}/../Tests/${filename} 26 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin 27 | ) 28 | endforeach() 29 | 30 | file(GLOB buf_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/../Tests "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/buf/*.ll") 31 | foreach(filename ${buf_files}) 32 | add_test( 33 | NAME ass3-buf-cpp/${filename} 34 | COMMAND ass3 -overflow ${CMAKE_CURRENT_SOURCE_DIR}/../Tests/${filename} 35 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin 36 | ) 37 | endforeach() 38 | include(CTest) 39 | 40 | 41 | -------------------------------------------------------------------------------- /Assignment-3/CPP/test-ae.cpp: -------------------------------------------------------------------------------- 1 | #include "Assignment_3.h" 2 | #include "SVF-LLVM/SVFIRBuilder.h" 3 | #include "Util/CommandLine.h" 4 | #include "Util/Options.h" 5 | #include "WPA/Andersen.h" 6 | #include "WPA/WPAPass.h" 7 | 8 | using namespace SVF; 9 | using namespace SVFUtil; 10 | 11 | int main(int argc, char** argv) { 12 | int arg_num = 0; 13 | int extraArgc = 5; 14 | char** arg_value = new char*[argc + extraArgc]; 15 | for (; arg_num < argc; ++arg_num) { 16 | arg_value[arg_num] = argv[arg_num]; 17 | } 18 | // add extra options 19 | arg_value[arg_num++] = (char*)"-model-consts=true"; 20 | arg_value[arg_num++] = (char*)"-model-arrays=true"; 21 | arg_value[arg_num++] = (char*)"-pre-field-sensitive=false"; 22 | arg_value[arg_num++] = (char*)"-field-limit=10000"; 23 | arg_value[arg_num++] = (char*)"-stat=false"; 24 | assert(arg_num == (argc + extraArgc) && "more extra arguments? Change the value of extraArgc"); 25 | 26 | std::vector moduleNameVec; 27 | moduleNameVec = 28 | OptionBase::parseOptions(arg_num, arg_value, "Static Symbolic Execution", "[options] "); 29 | delete[] arg_value; 30 | 31 | LLVMModuleSet::getLLVMModuleSet()->buildSVFModule(moduleNameVec); 32 | SVFIRBuilder builder; 33 | SVFIR* pag = builder.build(); 34 | AndersenWaveDiff* ander = AndersenWaveDiff::createAndersenWaveDiff(pag); 35 | CallGraph* callgraph = ander->getCallGraph(); 36 | builder.updateCallGraph(callgraph); 37 | pag->getICFG()->updateCallGraph(callgraph); 38 | AbstractExecution* ae = new AbstractExecution(); 39 | ae->runOnModule(pag->getICFG()); 40 | ae->ensureAllAssertsValidated(); 41 | 42 | LLVMModuleSet::releaseLLVMModuleSet(); 43 | } 44 | -------------------------------------------------------------------------------- /Assignment-3/Python/Assignment_3.py: -------------------------------------------------------------------------------- 1 | from Assignment_3_Helper import * 2 | import pysvf 3 | 4 | class Assignment3(AbstractExecution): 5 | def __init__(self, pag: pysvf.SVFIR) -> None: 6 | super().__init__(pag) 7 | 8 | 9 | """ 10 | Handle ICFG nodes in a cycle using widening and narrowing operators. 11 | 12 | This function implements abstract interpretation for cycles in the ICFG using widening and narrowing 13 | operators to ensure termination. It processes all ICFG nodes within a cycle and implements 14 | widening-narrowing iteration to reach fixed points twice: once for widening (to ensure termination) 15 | and once for narrowing (to improve precision). 16 | 17 | :param cycle: The WTO cycle containing ICFG nodes to be processed 18 | :type cycle: ICFGWTOCycle 19 | """ 20 | def handleICFGCycle(self, cycle: ICFGWTOCycle): 21 | head = cycle.head.node 22 | increasing = True 23 | iteration = 0 24 | widen_delay = self.widen_delay # Use class member for widen delay 25 | 26 | while True: 27 | # TODO: your code starts from here 28 | pass 29 | 30 | #TODO : Implement the state updates for Copy, Binary, Store, Load, Gep, Phi 31 | # TODO: your code starts from here 32 | def updateStateOnGep(self, gep: pysvf.GepStmt): 33 | pass 34 | 35 | #TODO: your code starts from here 36 | def updateStateOnStore(self, store: pysvf.StoreStmt): 37 | pass 38 | 39 | #TODO: your code starts from here 40 | # Find the comparison predicates in "class BinaryOPStmt:OpCode" under SVF/svf/include/SVFIR/SVFStatements.h 41 | # You are required to handle predicates (The program is assumed to have signed ints and also interger-overflow-free), 42 | # including Add, FAdd, Sub, FSub, Mul, FMul, SDiv, FDiv, UDiv, SRem, FRem, URem, Xor, And, Or, AShr, Shl, LShr 43 | def updateStateOnBinary(self, binary: pysvf.BinaryOPStmt): 44 | pass 45 | 46 | 47 | #TODO: your code starts from here 48 | def updateStateOnLoad(self, load: pysvf.LoadStmt): 49 | pass 50 | 51 | #TODO: your code starts from here 52 | def updateStateOnCopy(self, copy: pysvf.CopyStmt): 53 | pass 54 | 55 | # TODO: your code starts from here 56 | def updateStateOnPhi(self, phi: pysvf.PhiStmt): 57 | pass 58 | 59 | """ 60 | Detect buffer overflows in the given statement. 61 | 62 | TODO: handle GepStmt `lhs = rhs + off` and detect buffer overflow 63 | Step 1: For each `obj \in pts(rhs)`, get the size of allocated baseobj (entire mem object) via `obj_size = svfir->getBaseObj(objId)->getByteSizeOfObj();` 64 | There is a buffer overflow if `accessOffset.ub() >= obj_size`, where accessOffset is obtained via `getAccessOffset` 65 | Step 2: invoke `reportBufOverflow` with the current ICFGNode if an overflow is detected 66 | 67 | :param stmt: The statement to analyze for buffer overflows. 68 | :type stmt: pysvf.SVFStmt 69 | """ 70 | def bufOverflowDetection(self, stmt: pysvf.SVFStmt): 71 | if not isinstance(stmt.getICFGNode(), pysvf.CallICFGNode): 72 | if isinstance(stmt, pysvf.GepStmt): 73 | abstract_state = self.post_abs_trace[stmt.getICFGNode()] 74 | lhs = stmt.getLHSVarID() 75 | rhs = stmt.getRHSVarID() 76 | 77 | # Update GEP object offset from base 78 | self.buf_overflow_helper.updateGepObjOffsetFromBase(abstract_state, 79 | abstract_state[lhs].getAddrs(), abstract_state[rhs].getAddrs(), 80 | abstract_state.getByteOffset(stmt) 81 | ) 82 | 83 | # TODO: your code starts from here 84 | # Check for buffer overflow 85 | pass 86 | 87 | """ 88 | Handle external function calls and update the abstract state. 89 | 90 | This function processes specific external function calls, such as `mem_insert` and `str_insert`, 91 | to ensure that buffer overflows are detected and prevented. It checks the constraints on the 92 | buffer size and access offsets based on the function arguments. 93 | 94 | TODO: Steps: 95 | 1. For `mem_insert`: 96 | - Validate that the buffer size is greater than or equal to the sum of the position and data size. 97 | 2. For `str_insert`: 98 | - Validate that the buffer size is greater than or equal to the sum of the position and the length of the string. 99 | 100 | :param ext_call_node: The call node representing the external function call. 101 | :type ext_call_node: pysvf.CallICFGNode 102 | """ 103 | def updateStateOnExtCall(self, extCallNode: pysvf.CallICFGNode): 104 | func_name = extCallNode.getCalledFunction().getName() 105 | 106 | # Handle external calls 107 | # TODO: handle external calls 108 | # void mem_insert(void *buffer, const void *data, size_t data_size, size_t position); 109 | if func_name == "mem_insert": 110 | # void mem_insert(void *buffer, const void *data, size_t data_size, size_t position); 111 | # Check sizeof(buffer) >= position + data_size 112 | pass 113 | # TODO: handle external calls 114 | # void str_insert(void *buffer, const void *data, size_t position); 115 | elif func_name == "str_insert": 116 | # void str_insert(void *buffer, const void *data, size_t position); 117 | # Check sizeof(buffer) >= position + strlen(data) 118 | pass -------------------------------------------------------------------------------- /Assignment-3/Python/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | # loops over ae_assert_files and run "ae $bc_file" 2 | file(GLOB ae_assert_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/../Tests "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/ae/*.ll") 3 | foreach(filename ${ae_assert_files}) 4 | add_test( 5 | NAME ass3-ae-py/${filename} 6 | COMMAND python3 test-ae.py ${CMAKE_CURRENT_SOURCE_DIR}/../Tests/${filename} 7 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 8 | ) 9 | endforeach() 10 | 11 | file(GLOB buf_files RELATIVE ${CMAKE_CURRENT_SOURCE_DIR}/../Tests "${CMAKE_CURRENT_SOURCE_DIR}/../Tests/buf/*.ll") 12 | foreach(filename ${buf_files}) 13 | add_test( 14 | NAME ass3-buf-py/${filename} 15 | COMMAND python3 test-ae.py ${CMAKE_CURRENT_SOURCE_DIR}/../Tests/${filename} 16 | WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} 17 | ) 18 | endforeach() 19 | include(CTest) 20 | 21 | 22 | -------------------------------------------------------------------------------- /Assignment-3/Python/test-ae.py: -------------------------------------------------------------------------------- 1 | from Assignment_3 import * 2 | 3 | if __name__ == "__main__": 4 | # check sys.argv and print friendly error message if not enough arguments 5 | if len(sys.argv) < 2: 6 | print("Usage: python3 test-ae.py ") 7 | sys.exit(1) 8 | pysvf.buildSVFModule(sys.argv[1:]) 9 | pag = pysvf.getPAG() 10 | ass3 = Assignment3(pag) 11 | ass3.analyse() 12 | pysvf.releasePAG() -------------------------------------------------------------------------------- /Assignment-3/Tests/ae/test1.c: -------------------------------------------------------------------------------- 1 | // 2 | // Created by Jiawei Wang on 1/17/22. 3 | // 4 | 5 | #include "stdbool.h" 6 | extern void svf_assert(bool); 7 | #define LEN 10 8 | 9 | int main() { 10 | int a[LEN] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}; 11 | int *p = a + 9; 12 | *p = 10; 13 | svf_assert(a[LEN-1] == 10); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /Assignment-3/Tests/ae/test1.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test1.ll' 2 | source_filename = "./test1.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | @__const.main.a = private unnamed_addr constant [10 x i32] [i32 0, i32 1, i32 2, i32 3, i32 4, i32 5, i32 6, i32 7, i32 8, i32 9], align 4 7 | 8 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 9 | define i32 @main() #0 !dbg !9 { 10 | entry: 11 | %a = alloca [10 x i32], align 4 12 | call void @llvm.dbg.declare(metadata ptr %a, metadata !15, metadata !DIExpression()), !dbg !19 13 | call void @llvm.memcpy.p0.p0.i64(ptr align 4 %a, ptr align 4 @__const.main.a, i64 40, i1 false), !dbg !19 14 | %arraydecay = getelementptr inbounds [10 x i32], ptr %a, i64 0, i64 0, !dbg !20 15 | %add.ptr = getelementptr inbounds i32, ptr %arraydecay, i64 9, !dbg !21 16 | call void @llvm.dbg.value(metadata ptr %add.ptr, metadata !22, metadata !DIExpression()), !dbg !24 17 | store i32 10, ptr %add.ptr, align 4, !dbg !25 18 | %arrayidx = getelementptr inbounds [10 x i32], ptr %a, i64 0, i64 9, !dbg !26 19 | %0 = load i32, ptr %arrayidx, align 4, !dbg !26 20 | %cmp = icmp eq i32 %0, 10, !dbg !27 21 | call void @svf_assert(i1 noundef zeroext %cmp), !dbg !28 22 | ret i32 0, !dbg !29 23 | } 24 | 25 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 26 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 27 | 28 | ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: readwrite) 29 | declare void @llvm.memcpy.p0.p0.i64(ptr noalias nocapture writeonly, ptr noalias nocapture readonly, i64, i1 immarg) #2 30 | 31 | declare void @svf_assert(i1 noundef zeroext) #3 32 | 33 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 34 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 35 | 36 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 37 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 38 | attributes #2 = { nocallback nofree nounwind willreturn memory(argmem: readwrite) } 39 | attributes #3 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 40 | 41 | !llvm.dbg.cu = !{!0} 42 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 43 | !llvm.ident = !{!8} 44 | 45 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 46 | !1 = !DIFile(filename: "test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-3/Tests/ae") 47 | !2 = !{i32 7, !"Dwarf Version", i32 4} 48 | !3 = !{i32 2, !"Debug Info Version", i32 3} 49 | !4 = !{i32 1, !"wchar_size", i32 4} 50 | !5 = !{i32 8, !"PIC Level", i32 2} 51 | !6 = !{i32 7, !"uwtable", i32 1} 52 | !7 = !{i32 7, !"frame-pointer", i32 1} 53 | !8 = !{!"Homebrew clang version 16.0.6"} 54 | !9 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 9, type: !11, scopeLine: 9, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) 55 | !10 = !DIFile(filename: "./test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-3/Tests/ae") 56 | !11 = !DISubroutineType(types: !12) 57 | !12 = !{!13} 58 | !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 59 | !14 = !{} 60 | !15 = !DILocalVariable(name: "a", scope: !9, file: !10, line: 10, type: !16) 61 | !16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 320, elements: !17) 62 | !17 = !{!18} 63 | !18 = !DISubrange(count: 10) 64 | !19 = !DILocation(line: 10, column: 9, scope: !9) 65 | !20 = !DILocation(line: 11, column: 15, scope: !9) 66 | !21 = !DILocation(line: 11, column: 17, scope: !9) 67 | !22 = !DILocalVariable(name: "p", scope: !9, file: !10, line: 11, type: !23) 68 | !23 = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: !13, size: 64) 69 | !24 = !DILocation(line: 0, scope: !9) 70 | !25 = !DILocation(line: 12, column: 8, scope: !9) 71 | !26 = !DILocation(line: 13, column: 16, scope: !9) 72 | !27 = !DILocation(line: 13, column: 25, scope: !9) 73 | !28 = !DILocation(line: 13, column: 5, scope: !9) 74 | !29 = !DILocation(line: 14, column: 5, scope: !9) 75 | -------------------------------------------------------------------------------- /Assignment-3/Tests/ae/test2.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | extern void svf_assert(bool); 3 | int main() { 4 | int a = 10; 5 | int b = 5; 6 | int c = a / b; 7 | svf_assert(c == 2); 8 | return 0; 9 | } -------------------------------------------------------------------------------- /Assignment-3/Tests/ae/test2.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test2.ll' 2 | source_filename = "./test2.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define i32 @main() #0 !dbg !9 { 8 | entry: 9 | call void @llvm.dbg.value(metadata i32 10, metadata !15, metadata !DIExpression()), !dbg !16 10 | call void @llvm.dbg.value(metadata i32 5, metadata !17, metadata !DIExpression()), !dbg !16 11 | %div = sdiv i32 10, 5, !dbg !18 12 | call void @llvm.dbg.value(metadata i32 %div, metadata !19, metadata !DIExpression()), !dbg !16 13 | %cmp = icmp eq i32 %div, 2, !dbg !20 14 | call void @svf_assert(i1 noundef zeroext %cmp), !dbg !21 15 | ret i32 0, !dbg !22 16 | } 17 | 18 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 19 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 20 | 21 | declare void @svf_assert(i1 noundef zeroext) #2 22 | 23 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 24 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 25 | 26 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 27 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 28 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 29 | 30 | !llvm.dbg.cu = !{!0} 31 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 32 | !llvm.ident = !{!8} 33 | 34 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 35 | !1 = !DIFile(filename: "test2.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-3/Tests/ae") 36 | !2 = !{i32 7, !"Dwarf Version", i32 4} 37 | !3 = !{i32 2, !"Debug Info Version", i32 3} 38 | !4 = !{i32 1, !"wchar_size", i32 4} 39 | !5 = !{i32 8, !"PIC Level", i32 2} 40 | !6 = !{i32 7, !"uwtable", i32 1} 41 | !7 = !{i32 7, !"frame-pointer", i32 1} 42 | !8 = !{!"Homebrew clang version 16.0.6"} 43 | !9 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 3, type: !11, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) 44 | !10 = !DIFile(filename: "./test2.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-3/Tests/ae") 45 | !11 = !DISubroutineType(types: !12) 46 | !12 = !{!13} 47 | !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 48 | !14 = !{} 49 | !15 = !DILocalVariable(name: "a", scope: !9, file: !10, line: 4, type: !13) 50 | !16 = !DILocation(line: 0, scope: !9) 51 | !17 = !DILocalVariable(name: "b", scope: !9, file: !10, line: 5, type: !13) 52 | !18 = !DILocation(line: 6, column: 12, scope: !9) 53 | !19 = !DILocalVariable(name: "c", scope: !9, file: !10, line: 6, type: !13) 54 | !20 = !DILocation(line: 7, column: 15, scope: !9) 55 | !21 = !DILocation(line: 7, column: 2, scope: !9) 56 | !22 = !DILocation(line: 8, column: 2, scope: !9) 57 | -------------------------------------------------------------------------------- /Assignment-3/Tests/ae/test3.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | extern void svf_assert(bool); 3 | 4 | int foo(void) 5 | { 6 | return 1; 7 | } 8 | 9 | int main() { 10 | int x, y; 11 | x = 1; 12 | y = 0; 13 | switch (foo()) 14 | { 15 | case 0: 16 | x += 1; 17 | break; 18 | case 1: 19 | x += y; 20 | break; 21 | case 2: 22 | x -= y; 23 | break; 24 | default: 25 | x++; 26 | y++; 27 | break; 28 | } 29 | svf_assert(x >= y); 30 | return 0; 31 | } -------------------------------------------------------------------------------- /Assignment-3/Tests/ae/test3.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test3.ll' 2 | source_filename = "test3.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define i32 @foo() #0 !dbg !9 { 8 | entry: 9 | ret i32 1, !dbg !14 10 | } 11 | 12 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 13 | define i32 @main() #0 !dbg !15 { 14 | entry: 15 | call void @llvm.dbg.value(metadata i32 1, metadata !16, metadata !DIExpression()), !dbg !17 16 | call void @llvm.dbg.value(metadata i32 0, metadata !18, metadata !DIExpression()), !dbg !17 17 | %call = call i32 @foo(), !dbg !19 18 | switch i32 %call, label %sw.default [ 19 | i32 0, label %sw.bb 20 | i32 1, label %sw.bb1 21 | i32 2, label %sw.bb3 22 | ], !dbg !20 23 | 24 | sw.bb: ; preds = %entry 25 | %add = add nsw i32 1, 1, !dbg !21 26 | call void @llvm.dbg.value(metadata i32 %add, metadata !16, metadata !DIExpression()), !dbg !17 27 | br label %sw.epilog, !dbg !23 28 | 29 | sw.bb1: ; preds = %entry 30 | %add2 = add nsw i32 1, 0, !dbg !24 31 | call void @llvm.dbg.value(metadata i32 %add2, metadata !16, metadata !DIExpression()), !dbg !17 32 | br label %sw.epilog, !dbg !25 33 | 34 | sw.bb3: ; preds = %entry 35 | %sub = sub nsw i32 1, 0, !dbg !26 36 | call void @llvm.dbg.value(metadata i32 %sub, metadata !16, metadata !DIExpression()), !dbg !17 37 | br label %sw.epilog, !dbg !27 38 | 39 | sw.default: ; preds = %entry 40 | %inc = add nsw i32 1, 1, !dbg !28 41 | call void @llvm.dbg.value(metadata i32 %inc, metadata !16, metadata !DIExpression()), !dbg !17 42 | %inc4 = add nsw i32 0, 1, !dbg !29 43 | call void @llvm.dbg.value(metadata i32 %inc4, metadata !18, metadata !DIExpression()), !dbg !17 44 | br label %sw.epilog, !dbg !30 45 | 46 | sw.epilog: ; preds = %sw.default, %sw.bb3, %sw.bb1, %sw.bb 47 | %x.0 = phi i32 [ %inc, %sw.default ], [ %sub, %sw.bb3 ], [ %add2, %sw.bb1 ], [ %add, %sw.bb ], !dbg !31 48 | %y.0 = phi i32 [ %inc4, %sw.default ], [ 0, %sw.bb3 ], [ 0, %sw.bb1 ], [ 0, %sw.bb ], !dbg !17 49 | call void @llvm.dbg.value(metadata i32 %y.0, metadata !18, metadata !DIExpression()), !dbg !17 50 | call void @llvm.dbg.value(metadata i32 %x.0, metadata !16, metadata !DIExpression()), !dbg !17 51 | %cmp = icmp sge i32 %x.0, %y.0, !dbg !32 52 | call void @svf_assert(i1 noundef zeroext %cmp), !dbg !33 53 | ret i32 0, !dbg !34 54 | } 55 | 56 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 57 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 58 | 59 | declare void @svf_assert(i1 noundef zeroext) #2 60 | 61 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 62 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 63 | 64 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 65 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 66 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 67 | 68 | !llvm.dbg.cu = !{!0} 69 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 70 | !llvm.ident = !{!8} 71 | 72 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 73 | !1 = !DIFile(filename: "test3.c", directory: "/Users/z5489735/2023/0718/Software-Security-Analysis/teaching/Assignment-3/Tests/ae") 74 | !2 = !{i32 7, !"Dwarf Version", i32 4} 75 | !3 = !{i32 2, !"Debug Info Version", i32 3} 76 | !4 = !{i32 1, !"wchar_size", i32 4} 77 | !5 = !{i32 8, !"PIC Level", i32 2} 78 | !6 = !{i32 7, !"uwtable", i32 1} 79 | !7 = !{i32 7, !"frame-pointer", i32 1} 80 | !8 = !{!"Homebrew clang version 16.0.6"} 81 | !9 = distinct !DISubprogram(name: "foo", scope: !1, file: !1, line: 4, type: !10, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13) 82 | !10 = !DISubroutineType(types: !11) 83 | !11 = !{!12} 84 | !12 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 85 | !13 = !{} 86 | !14 = !DILocation(line: 6, column: 5, scope: !9) 87 | !15 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 9, type: !10, scopeLine: 9, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !13) 88 | !16 = !DILocalVariable(name: "x", scope: !15, file: !1, line: 10, type: !12) 89 | !17 = !DILocation(line: 0, scope: !15) 90 | !18 = !DILocalVariable(name: "y", scope: !15, file: !1, line: 10, type: !12) 91 | !19 = !DILocation(line: 13, column: 11, scope: !15) 92 | !20 = !DILocation(line: 13, column: 3, scope: !15) 93 | !21 = !DILocation(line: 16, column: 11, scope: !22) 94 | !22 = distinct !DILexicalBlock(scope: !15, file: !1, line: 14, column: 3) 95 | !23 = !DILocation(line: 17, column: 9, scope: !22) 96 | !24 = !DILocation(line: 19, column: 11, scope: !22) 97 | !25 = !DILocation(line: 20, column: 9, scope: !22) 98 | !26 = !DILocation(line: 22, column: 11, scope: !22) 99 | !27 = !DILocation(line: 23, column: 9, scope: !22) 100 | !28 = !DILocation(line: 25, column: 10, scope: !22) 101 | !29 = !DILocation(line: 26, column: 10, scope: !22) 102 | !30 = !DILocation(line: 27, column: 9, scope: !22) 103 | !31 = !DILocation(line: 0, scope: !22) 104 | !32 = !DILocation(line: 29, column: 18, scope: !15) 105 | !33 = !DILocation(line: 29, column: 5, scope: !15) 106 | !34 = !DILocation(line: 30, column: 5, scope: !15) 107 | -------------------------------------------------------------------------------- /Assignment-3/Tests/ae/test4.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | extern void svf_assert(bool); 3 | 4 | int main() { 5 | int x; 6 | x=1; 7 | while(x<10000) { 8 | x++; 9 | } 10 | svf_assert(x == 10000); 11 | return 0; 12 | } -------------------------------------------------------------------------------- /Assignment-3/Tests/ae/test4.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test4.ll' 2 | source_filename = "./test4.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define i32 @main() #0 !dbg !9 { 8 | entry: 9 | call void @llvm.dbg.value(metadata i32 1, metadata !15, metadata !DIExpression()), !dbg !16 10 | br label %while.cond, !dbg !17 11 | 12 | while.cond: ; preds = %while.body, %entry 13 | %x.0 = phi i32 [ 1, %entry ], [ %inc, %while.body ], !dbg !16 14 | call void @llvm.dbg.value(metadata i32 %x.0, metadata !15, metadata !DIExpression()), !dbg !16 15 | %cmp = icmp slt i32 %x.0, 10000, !dbg !18 16 | br i1 %cmp, label %while.body, label %while.end, !dbg !17 17 | 18 | while.body: ; preds = %while.cond 19 | %inc = add nsw i32 %x.0, 1, !dbg !19 20 | call void @llvm.dbg.value(metadata i32 %inc, metadata !15, metadata !DIExpression()), !dbg !16 21 | br label %while.cond, !dbg !17, !llvm.loop !21 22 | 23 | while.end: ; preds = %while.cond 24 | %cmp1 = icmp eq i32 %x.0, 10000, !dbg !24 25 | call void @svf_assert(i1 noundef zeroext %cmp1), !dbg !25 26 | ret i32 0, !dbg !26 27 | } 28 | 29 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 30 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 31 | 32 | declare void @svf_assert(i1 noundef zeroext) #2 33 | 34 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 35 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 36 | 37 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 38 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 39 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 40 | 41 | !llvm.dbg.cu = !{!0} 42 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 43 | !llvm.ident = !{!8} 44 | 45 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 46 | !1 = !DIFile(filename: "test4.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-3/Tests/ae") 47 | !2 = !{i32 7, !"Dwarf Version", i32 4} 48 | !3 = !{i32 2, !"Debug Info Version", i32 3} 49 | !4 = !{i32 1, !"wchar_size", i32 4} 50 | !5 = !{i32 8, !"PIC Level", i32 2} 51 | !6 = !{i32 7, !"uwtable", i32 1} 52 | !7 = !{i32 7, !"frame-pointer", i32 1} 53 | !8 = !{!"Homebrew clang version 16.0.6"} 54 | !9 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 4, type: !11, scopeLine: 4, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) 55 | !10 = !DIFile(filename: "./test4.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-3/Tests/ae") 56 | !11 = !DISubroutineType(types: !12) 57 | !12 = !{!13} 58 | !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 59 | !14 = !{} 60 | !15 = !DILocalVariable(name: "x", scope: !9, file: !10, line: 5, type: !13) 61 | !16 = !DILocation(line: 0, scope: !9) 62 | !17 = !DILocation(line: 7, column: 5, scope: !9) 63 | !18 = !DILocation(line: 7, column: 12, scope: !9) 64 | !19 = !DILocation(line: 8, column: 10, scope: !20) 65 | !20 = distinct !DILexicalBlock(scope: !9, file: !10, line: 7, column: 20) 66 | !21 = distinct !{!21, !17, !22, !23} 67 | !22 = !DILocation(line: 9, column: 5, scope: !9) 68 | !23 = !{!"llvm.loop.mustprogress"} 69 | !24 = !DILocation(line: 10, column: 18, scope: !9) 70 | !25 = !DILocation(line: 10, column: 5, scope: !9) 71 | !26 = !DILocation(line: 11, column: 5, scope: !9) 72 | -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test1.c: -------------------------------------------------------------------------------- 1 | extern void OVERFLOW(void* data, int size); 2 | int main() { 3 | int arr[5]; 4 | OVERFLOW(arr, 5*sizeof(int)); 5 | arr[5] = 10; 6 | } -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test1.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test1.ll' 2 | source_filename = "./test1.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define i32 @main() #0 !dbg !9 { 8 | entry: 9 | %arr = alloca [5 x i32], align 4 10 | call void @llvm.dbg.declare(metadata ptr %arr, metadata !15, metadata !DIExpression()), !dbg !19 11 | %arraydecay = getelementptr inbounds [5 x i32], ptr %arr, i64 0, i64 0, !dbg !20 12 | call void @OVERFLOW(ptr noundef %arraydecay, i32 noundef 20), !dbg !21 13 | %arrayidx = getelementptr inbounds [5 x i32], ptr %arr, i64 0, i64 5, !dbg !22 14 | store i32 10, ptr %arrayidx, align 4, !dbg !23 15 | ret i32 0, !dbg !24 16 | } 17 | 18 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 19 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 20 | 21 | declare void @OVERFLOW(ptr noundef, i32 noundef) #2 22 | 23 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 24 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 25 | attributes #2 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 26 | 27 | !llvm.dbg.cu = !{!0} 28 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 29 | !llvm.ident = !{!8} 30 | 31 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 32 | !1 = !DIFile(filename: "test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-3/Tests/buf") 33 | !2 = !{i32 7, !"Dwarf Version", i32 4} 34 | !3 = !{i32 2, !"Debug Info Version", i32 3} 35 | !4 = !{i32 1, !"wchar_size", i32 4} 36 | !5 = !{i32 8, !"PIC Level", i32 2} 37 | !6 = !{i32 7, !"uwtable", i32 1} 38 | !7 = !{i32 7, !"frame-pointer", i32 1} 39 | !8 = !{!"Homebrew clang version 16.0.6"} 40 | !9 = distinct !DISubprogram(name: "main", scope: !10, file: !10, line: 2, type: !11, scopeLine: 2, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !14) 41 | !10 = !DIFile(filename: "./test1.c", directory: "/Users/z5489735/2023/0513/Software-Security-Analysis/Assignment-3/Tests/buf") 42 | !11 = !DISubroutineType(types: !12) 43 | !12 = !{!13} 44 | !13 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 45 | !14 = !{} 46 | !15 = !DILocalVariable(name: "arr", scope: !9, file: !10, line: 3, type: !16) 47 | !16 = !DICompositeType(tag: DW_TAG_array_type, baseType: !13, size: 160, elements: !17) 48 | !17 = !{!18} 49 | !18 = !DISubrange(count: 5) 50 | !19 = !DILocation(line: 3, column: 9, scope: !9) 51 | !20 = !DILocation(line: 4, column: 14, scope: !9) 52 | !21 = !DILocation(line: 4, column: 5, scope: !9) 53 | !22 = !DILocation(line: 5, column: 5, scope: !9) 54 | !23 = !DILocation(line: 5, column: 12, scope: !9) 55 | !24 = !DILocation(line: 6, column: 1, scope: !9) 56 | -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test2.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include // For int64_t 3 | #include // For exit and EXIT_FAILURE 4 | extern void OVERFLOW(void* data, int size); 5 | 6 | void CWE121_Stack_Based_Buffer_Overflow__CWE805_int64_t_declare_loop_01_bad() { 7 | int64_t dataBadBuffer[50]; 8 | 9 | int64_t source[100] = {0}; // Fill with 0's 10 | size_t i; 11 | 12 | // POTENTIAL FLAW: Possible buffer overflow if data < 100 13 | OVERFLOW(dataBadBuffer, 100 * sizeof(int64_t)); 14 | for (i = 0; i < 100; i++) { 15 | dataBadBuffer[i] = source[i]; // Unsafe memory access 16 | } 17 | } 18 | 19 | int main() { 20 | CWE121_Stack_Based_Buffer_Overflow__CWE805_int64_t_declare_loop_01_bad(); 21 | return 0; 22 | } -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include // For rand() and srand() 3 | #include // For time() 4 | extern void OVERFLOW(void* data, int size); 5 | 6 | 7 | void CWE121_Stack_Based_Buffer_Overflow__CWE129_rand_01_bad() { 8 | int data; 9 | /* Initialize data */ 10 | data = -1; 11 | /* POTENTIAL FLAW: Set data to the remainder when 9999 is divided by 100 */ 12 | data = 9999 % 100; 13 | 14 | int i; 15 | int buffer[10] = { 0 }; 16 | /* POTENTIAL FLAW: Attempt to write to an index of the array that is above the upper bound 17 | * This code does check to see if the array index is negative */ 18 | if (data >= 0) 19 | { 20 | OVERFLOW(buffer, 99 * sizeof(int)); 21 | buffer[data] = 1; 22 | } 23 | } 24 | 25 | int main() { 26 | CWE121_Stack_Based_Buffer_Overflow__CWE129_rand_01_bad(); 27 | return 0; 28 | } 29 | -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test3.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test3.ll' 2 | source_filename = "test3.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 7 | define void @CWE121_Stack_Based_Buffer_Overflow__CWE129_rand_01_bad() #0 !dbg !9 { 8 | entry: 9 | %buffer = alloca [10 x i32], align 4 10 | call void @llvm.dbg.value(metadata i32 -1, metadata !13, metadata !DIExpression()), !dbg !15 11 | call void @llvm.dbg.value(metadata i32 99, metadata !13, metadata !DIExpression()), !dbg !15 12 | call void @llvm.dbg.declare(metadata ptr undef, metadata !16, metadata !DIExpression()), !dbg !17 13 | call void @llvm.dbg.declare(metadata ptr %buffer, metadata !18, metadata !DIExpression()), !dbg !22 14 | call void @llvm.memset.p0.i64(ptr align 4 %buffer, i8 0, i64 40, i1 false), !dbg !22 15 | %cmp = icmp sge i32 99, 0, !dbg !23 16 | br i1 %cmp, label %if.then, label %if.end, !dbg !25 17 | 18 | if.then: ; preds = %entry 19 | %arraydecay = getelementptr inbounds [10 x i32], ptr %buffer, i64 0, i64 0, !dbg !26 20 | call void @OVERFLOW(ptr noundef %arraydecay, i32 noundef 396), !dbg !28 21 | %idxprom = sext i32 99 to i64, !dbg !29 22 | %arrayidx = getelementptr inbounds [10 x i32], ptr %buffer, i64 0, i64 %idxprom, !dbg !29 23 | store i32 1, ptr %arrayidx, align 4, !dbg !30 24 | br label %if.end, !dbg !31 25 | 26 | if.end: ; preds = %if.then, %entry 27 | ret void, !dbg !32 28 | } 29 | 30 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 31 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 32 | 33 | ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write) 34 | declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #2 35 | 36 | declare void @OVERFLOW(ptr noundef, i32 noundef) #3 37 | 38 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 39 | define i32 @main() #0 !dbg !33 { 40 | entry: 41 | call void @CWE121_Stack_Based_Buffer_Overflow__CWE129_rand_01_bad(), !dbg !36 42 | ret i32 0, !dbg !37 43 | } 44 | 45 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 46 | declare void @llvm.dbg.value(metadata, metadata, metadata) #1 47 | 48 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 49 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 50 | attributes #2 = { nocallback nofree nounwind willreturn memory(argmem: write) } 51 | attributes #3 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 52 | 53 | !llvm.dbg.cu = !{!0} 54 | !llvm.module.flags = !{!2, !3, !4, !5, !6, !7} 55 | !llvm.ident = !{!8} 56 | 57 | !0 = distinct !DICompileUnit(language: DW_LANG_C11, file: !1, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 58 | !1 = !DIFile(filename: "test3.c", directory: "/Users/z5489735/2023/0617/solution/Software-Security-Analysis/Assignment-3/Tests/buf") 59 | !2 = !{i32 7, !"Dwarf Version", i32 4} 60 | !3 = !{i32 2, !"Debug Info Version", i32 3} 61 | !4 = !{i32 1, !"wchar_size", i32 4} 62 | !5 = !{i32 8, !"PIC Level", i32 2} 63 | !6 = !{i32 7, !"uwtable", i32 1} 64 | !7 = !{i32 7, !"frame-pointer", i32 1} 65 | !8 = !{!"Homebrew clang version 16.0.6"} 66 | !9 = distinct !DISubprogram(name: "CWE121_Stack_Based_Buffer_Overflow__CWE129_rand_01_bad", scope: !1, file: !1, line: 7, type: !10, scopeLine: 7, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !12) 67 | !10 = !DISubroutineType(types: !11) 68 | !11 = !{null} 69 | !12 = !{} 70 | !13 = !DILocalVariable(name: "data", scope: !9, file: !1, line: 8, type: !14) 71 | !14 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 72 | !15 = !DILocation(line: 0, scope: !9) 73 | !16 = !DILocalVariable(name: "i", scope: !9, file: !1, line: 14, type: !14) 74 | !17 = !DILocation(line: 14, column: 9, scope: !9) 75 | !18 = !DILocalVariable(name: "buffer", scope: !9, file: !1, line: 15, type: !19) 76 | !19 = !DICompositeType(tag: DW_TAG_array_type, baseType: !14, size: 320, elements: !20) 77 | !20 = !{!21} 78 | !21 = !DISubrange(count: 10) 79 | !22 = !DILocation(line: 15, column: 9, scope: !9) 80 | !23 = !DILocation(line: 18, column: 14, scope: !24) 81 | !24 = distinct !DILexicalBlock(scope: !9, file: !1, line: 18, column: 9) 82 | !25 = !DILocation(line: 18, column: 9, scope: !9) 83 | !26 = !DILocation(line: 20, column: 18, scope: !27) 84 | !27 = distinct !DILexicalBlock(scope: !24, file: !1, line: 19, column: 5) 85 | !28 = !DILocation(line: 20, column: 9, scope: !27) 86 | !29 = !DILocation(line: 21, column: 9, scope: !27) 87 | !30 = !DILocation(line: 21, column: 22, scope: !27) 88 | !31 = !DILocation(line: 22, column: 5, scope: !27) 89 | !32 = !DILocation(line: 23, column: 1, scope: !9) 90 | !33 = distinct !DISubprogram(name: "main", scope: !1, file: !1, line: 25, type: !34, scopeLine: 25, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !12) 91 | !34 = !DISubroutineType(types: !35) 92 | !35 = !{!14} 93 | !36 = !DILocation(line: 26, column: 5, scope: !33) 94 | !37 = !DILocation(line: 27, column: 5, scope: !33) 95 | -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test4.c: -------------------------------------------------------------------------------- 1 | void mem_insert(void *buffer, const void *data, int data_size, int position); 2 | extern void OVERFLOW(void* data, int size); 3 | int main() { 4 | char buffer[10] = {0}; 5 | mem_insert(buffer, "abcdef", 6, 5); 6 | OVERFLOW(buffer, 11); 7 | } -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test4.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test4.ll' 2 | source_filename = "test4.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | @.str = private unnamed_addr constant [7 x i8] c"abcdef\00", align 1, !dbg !0 7 | 8 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 9 | define i32 @main() #0 !dbg !16 { 10 | entry: 11 | %buffer = alloca [10 x i8], align 1 12 | call void @llvm.dbg.declare(metadata ptr %buffer, metadata !21, metadata !DIExpression()), !dbg !25 13 | call void @llvm.memset.p0.i64(ptr align 1 %buffer, i8 0, i64 10, i1 false), !dbg !25 14 | %arraydecay = getelementptr inbounds [10 x i8], ptr %buffer, i64 0, i64 0, !dbg !26 15 | call void @mem_insert(ptr noundef %arraydecay, ptr noundef @.str, i32 noundef 6, i32 noundef 5), !dbg !27 16 | %arraydecay1 = getelementptr inbounds [10 x i8], ptr %buffer, i64 0, i64 0, !dbg !28 17 | call void @OVERFLOW(ptr noundef %arraydecay1, i32 noundef 11), !dbg !29 18 | ret i32 0, !dbg !30 19 | } 20 | 21 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 22 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 23 | 24 | ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write) 25 | declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #2 26 | 27 | declare void @mem_insert(ptr noundef, ptr noundef, i32 noundef, i32 noundef) #3 28 | 29 | declare void @OVERFLOW(ptr noundef, i32 noundef) #3 30 | 31 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 32 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 33 | attributes #2 = { nocallback nofree nounwind willreturn memory(argmem: write) } 34 | attributes #3 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 35 | 36 | !llvm.dbg.cu = !{!7} 37 | !llvm.module.flags = !{!9, !10, !11, !12, !13, !14} 38 | !llvm.ident = !{!15} 39 | 40 | !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) 41 | !1 = distinct !DIGlobalVariable(scope: null, file: !2, line: 5, type: !3, isLocal: true, isDefinition: true) 42 | !2 = !DIFile(filename: "test4.c", directory: "/Users/z5489735/2023/0617/Software-Security-Analysis/Assignment-3/Tests/buf") 43 | !3 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 56, elements: !5) 44 | !4 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) 45 | !5 = !{!6} 46 | !6 = !DISubrange(count: 7) 47 | !7 = distinct !DICompileUnit(language: DW_LANG_C11, file: !2, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !8, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 48 | !8 = !{!0} 49 | !9 = !{i32 7, !"Dwarf Version", i32 4} 50 | !10 = !{i32 2, !"Debug Info Version", i32 3} 51 | !11 = !{i32 1, !"wchar_size", i32 4} 52 | !12 = !{i32 8, !"PIC Level", i32 2} 53 | !13 = !{i32 7, !"uwtable", i32 1} 54 | !14 = !{i32 7, !"frame-pointer", i32 1} 55 | !15 = !{!"Homebrew clang version 16.0.6"} 56 | !16 = distinct !DISubprogram(name: "main", scope: !2, file: !2, line: 3, type: !17, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !20) 57 | !17 = !DISubroutineType(types: !18) 58 | !18 = !{!19} 59 | !19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 60 | !20 = !{} 61 | !21 = !DILocalVariable(name: "buffer", scope: !16, file: !2, line: 4, type: !22) 62 | !22 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 80, elements: !23) 63 | !23 = !{!24} 64 | !24 = !DISubrange(count: 10) 65 | !25 = !DILocation(line: 4, column: 7, scope: !16) 66 | !26 = !DILocation(line: 5, column: 23, scope: !16) 67 | !27 = !DILocation(line: 5, column: 2, scope: !16) 68 | !28 = !DILocation(line: 6, column: 11, scope: !16) 69 | !29 = !DILocation(line: 6, column: 2, scope: !16) 70 | !30 = !DILocation(line: 7, column: 1, scope: !16) 71 | -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test5.c: -------------------------------------------------------------------------------- 1 | void str_insert(void *buffer, const void *data, int position); 2 | extern void OVERFLOW(void* data, int size); 3 | int main() { 4 | char buffer[10] = {0}; 5 | str_insert(buffer, "abcdef", 5); 6 | OVERFLOW(buffer, 11); 7 | } -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test5.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test5.ll' 2 | source_filename = "test5.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | @.str = private unnamed_addr constant [7 x i8] c"abcdef\00", align 1, !dbg !0 7 | 8 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 9 | define i32 @main() #0 !dbg !16 { 10 | entry: 11 | %buffer = alloca [10 x i8], align 1 12 | call void @llvm.dbg.declare(metadata ptr %buffer, metadata !21, metadata !DIExpression()), !dbg !25 13 | call void @llvm.memset.p0.i64(ptr align 1 %buffer, i8 0, i64 10, i1 false), !dbg !25 14 | %arraydecay = getelementptr inbounds [10 x i8], ptr %buffer, i64 0, i64 0, !dbg !26 15 | call void @str_insert(ptr noundef %arraydecay, ptr noundef @.str, i32 noundef 5), !dbg !27 16 | %arraydecay1 = getelementptr inbounds [10 x i8], ptr %buffer, i64 0, i64 0, !dbg !28 17 | call void @OVERFLOW(ptr noundef %arraydecay1, i32 noundef 11), !dbg !29 18 | ret i32 0, !dbg !30 19 | } 20 | 21 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 22 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 23 | 24 | ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write) 25 | declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #2 26 | 27 | declare void @str_insert(ptr noundef, ptr noundef, i32 noundef) #3 28 | 29 | declare void @OVERFLOW(ptr noundef, i32 noundef) #3 30 | 31 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 32 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 33 | attributes #2 = { nocallback nofree nounwind willreturn memory(argmem: write) } 34 | attributes #3 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 35 | 36 | !llvm.dbg.cu = !{!7} 37 | !llvm.module.flags = !{!9, !10, !11, !12, !13, !14} 38 | !llvm.ident = !{!15} 39 | 40 | !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) 41 | !1 = distinct !DIGlobalVariable(scope: null, file: !2, line: 5, type: !3, isLocal: true, isDefinition: true) 42 | !2 = !DIFile(filename: "test5.c", directory: "/Users/z5489735/2023/0617/Software-Security-Analysis/Assignment-3/Tests/buf") 43 | !3 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 56, elements: !5) 44 | !4 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) 45 | !5 = !{!6} 46 | !6 = !DISubrange(count: 7) 47 | !7 = distinct !DICompileUnit(language: DW_LANG_C11, file: !2, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !8, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 48 | !8 = !{!0} 49 | !9 = !{i32 7, !"Dwarf Version", i32 4} 50 | !10 = !{i32 2, !"Debug Info Version", i32 3} 51 | !11 = !{i32 1, !"wchar_size", i32 4} 52 | !12 = !{i32 8, !"PIC Level", i32 2} 53 | !13 = !{i32 7, !"uwtable", i32 1} 54 | !14 = !{i32 7, !"frame-pointer", i32 1} 55 | !15 = !{!"Homebrew clang version 16.0.6"} 56 | !16 = distinct !DISubprogram(name: "main", scope: !2, file: !2, line: 3, type: !17, scopeLine: 3, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !20) 57 | !17 = !DISubroutineType(types: !18) 58 | !18 = !{!19} 59 | !19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 60 | !20 = !{} 61 | !21 = !DILocalVariable(name: "buffer", scope: !16, file: !2, line: 4, type: !22) 62 | !22 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 80, elements: !23) 63 | !23 = !{!24} 64 | !24 = !DISubrange(count: 10) 65 | !25 = !DILocation(line: 4, column: 7, scope: !16) 66 | !26 = !DILocation(line: 5, column: 23, scope: !16) 67 | !27 = !DILocation(line: 5, column: 2, scope: !16) 68 | !28 = !DILocation(line: 6, column: 11, scope: !16) 69 | !29 = !DILocation(line: 6, column: 2, scope: !16) 70 | !30 = !DILocation(line: 7, column: 1, scope: !16) 71 | -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test6.c: -------------------------------------------------------------------------------- 1 | #include 2 | void mem_insert(void *buffer, const void *data, int data_size, int position); 3 | extern void OVERFLOW(void* data, int size); 4 | extern void svf_assert(bool condition); 5 | int main() { 6 | char buffer[10] = {0}; 7 | mem_insert(buffer, "abcdef", 3, 5); 8 | svf_assert(buffer[5] == 'a'); 9 | svf_assert(buffer[6] == 'b'); 10 | svf_assert(buffer[7] == 'c'); 11 | svf_assert(buffer[8] != 'd'); 12 | return 0; 13 | } -------------------------------------------------------------------------------- /Assignment-3/Tests/buf/test6.ll: -------------------------------------------------------------------------------- 1 | ; ModuleID = './test6.ll' 2 | source_filename = "test6.c" 3 | target datalayout = "e-m:o-i64:64-i128:128-n32:64-S128" 4 | target triple = "arm64-apple-macosx14.0.0" 5 | 6 | @.str = private unnamed_addr constant [7 x i8] c"abcdef\00", align 1, !dbg !0 7 | 8 | ; Function Attrs: noinline nounwind ssp uwtable(sync) 9 | define i32 @main() #0 !dbg !16 { 10 | entry: 11 | %buffer = alloca [10 x i8], align 1 12 | call void @llvm.dbg.declare(metadata ptr %buffer, metadata !21, metadata !DIExpression()), !dbg !25 13 | call void @llvm.memset.p0.i64(ptr align 1 %buffer, i8 0, i64 10, i1 false), !dbg !25 14 | %arraydecay = getelementptr inbounds [10 x i8], ptr %buffer, i64 0, i64 0, !dbg !26 15 | call void @mem_insert(ptr noundef %arraydecay, ptr noundef @.str, i32 noundef 3, i32 noundef 5), !dbg !27 16 | %arrayidx = getelementptr inbounds [10 x i8], ptr %buffer, i64 0, i64 5, !dbg !28 17 | %0 = load i8, ptr %arrayidx, align 1, !dbg !28 18 | %conv = sext i8 %0 to i32, !dbg !28 19 | %cmp = icmp eq i32 %conv, 97, !dbg !29 20 | call void @svf_assert(i1 noundef zeroext %cmp), !dbg !30 21 | %arrayidx2 = getelementptr inbounds [10 x i8], ptr %buffer, i64 0, i64 6, !dbg !31 22 | %1 = load i8, ptr %arrayidx2, align 1, !dbg !31 23 | %conv3 = sext i8 %1 to i32, !dbg !31 24 | %cmp4 = icmp eq i32 %conv3, 98, !dbg !32 25 | call void @svf_assert(i1 noundef zeroext %cmp4), !dbg !33 26 | %arrayidx6 = getelementptr inbounds [10 x i8], ptr %buffer, i64 0, i64 7, !dbg !34 27 | %2 = load i8, ptr %arrayidx6, align 1, !dbg !34 28 | %conv7 = sext i8 %2 to i32, !dbg !34 29 | %cmp8 = icmp eq i32 %conv7, 99, !dbg !35 30 | call void @svf_assert(i1 noundef zeroext %cmp8), !dbg !36 31 | %arrayidx10 = getelementptr inbounds [10 x i8], ptr %buffer, i64 0, i64 8, !dbg !37 32 | %3 = load i8, ptr %arrayidx10, align 1, !dbg !37 33 | %conv11 = sext i8 %3 to i32, !dbg !37 34 | %cmp12 = icmp ne i32 %conv11, 100, !dbg !38 35 | call void @svf_assert(i1 noundef zeroext %cmp12), !dbg !39 36 | ret i32 0, !dbg !40 37 | } 38 | 39 | ; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none) 40 | declare void @llvm.dbg.declare(metadata, metadata, metadata) #1 41 | 42 | ; Function Attrs: nocallback nofree nounwind willreturn memory(argmem: write) 43 | declare void @llvm.memset.p0.i64(ptr nocapture writeonly, i8, i64, i1 immarg) #2 44 | 45 | declare void @mem_insert(ptr noundef, ptr noundef, i32 noundef, i32 noundef) #3 46 | 47 | declare void @svf_assert(i1 noundef zeroext) #3 48 | 49 | attributes #0 = { noinline nounwind ssp uwtable(sync) "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 50 | attributes #1 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) } 51 | attributes #2 = { nocallback nofree nounwind willreturn memory(argmem: write) } 52 | attributes #3 = { "frame-pointer"="non-leaf" "no-trapping-math"="true" "stack-protector-buffer-size"="8" "target-cpu"="apple-m1" "target-features"="+aes,+crc,+crypto,+dotprod,+fp-armv8,+fp16fml,+fullfp16,+lse,+neon,+ras,+rcpc,+rdm,+sha2,+sha3,+sm4,+v8.1a,+v8.2a,+v8.3a,+v8.4a,+v8.5a,+v8a,+zcm,+zcz" } 53 | 54 | !llvm.dbg.cu = !{!7} 55 | !llvm.module.flags = !{!9, !10, !11, !12, !13, !14} 56 | !llvm.ident = !{!15} 57 | 58 | !0 = !DIGlobalVariableExpression(var: !1, expr: !DIExpression()) 59 | !1 = distinct !DIGlobalVariable(scope: null, file: !2, line: 7, type: !3, isLocal: true, isDefinition: true) 60 | !2 = !DIFile(filename: "test6.c", directory: "/Users/z5489735/2023/0718/Software-Security-Analysis/teaching/Assignment-3/Tests/buf") 61 | !3 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 56, elements: !5) 62 | !4 = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char) 63 | !5 = !{!6} 64 | !6 = !DISubrange(count: 7) 65 | !7 = distinct !DICompileUnit(language: DW_LANG_C11, file: !2, producer: "Homebrew clang version 16.0.6", isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, globals: !8, splitDebugInlining: false, nameTableKind: None, sysroot: "/Library/Developer/CommandLineTools/SDKs/MacOSX14.sdk", sdk: "MacOSX14.sdk") 66 | !8 = !{!0} 67 | !9 = !{i32 7, !"Dwarf Version", i32 4} 68 | !10 = !{i32 2, !"Debug Info Version", i32 3} 69 | !11 = !{i32 1, !"wchar_size", i32 4} 70 | !12 = !{i32 8, !"PIC Level", i32 2} 71 | !13 = !{i32 7, !"uwtable", i32 1} 72 | !14 = !{i32 7, !"frame-pointer", i32 1} 73 | !15 = !{!"Homebrew clang version 16.0.6"} 74 | !16 = distinct !DISubprogram(name: "main", scope: !2, file: !2, line: 5, type: !17, scopeLine: 5, spFlags: DISPFlagDefinition, unit: !7, retainedNodes: !20) 75 | !17 = !DISubroutineType(types: !18) 76 | !18 = !{!19} 77 | !19 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) 78 | !20 = !{} 79 | !21 = !DILocalVariable(name: "buffer", scope: !16, file: !2, line: 6, type: !22) 80 | !22 = !DICompositeType(tag: DW_TAG_array_type, baseType: !4, size: 80, elements: !23) 81 | !23 = !{!24} 82 | !24 = !DISubrange(count: 10) 83 | !25 = !DILocation(line: 6, column: 7, scope: !16) 84 | !26 = !DILocation(line: 7, column: 13, scope: !16) 85 | !27 = !DILocation(line: 7, column: 2, scope: !16) 86 | !28 = !DILocation(line: 8, column: 16, scope: !16) 87 | !29 = !DILocation(line: 8, column: 26, scope: !16) 88 | !30 = !DILocation(line: 8, column: 5, scope: !16) 89 | !31 = !DILocation(line: 9, column: 16, scope: !16) 90 | !32 = !DILocation(line: 9, column: 26, scope: !16) 91 | !33 = !DILocation(line: 9, column: 5, scope: !16) 92 | !34 = !DILocation(line: 10, column: 16, scope: !16) 93 | !35 = !DILocation(line: 10, column: 26, scope: !16) 94 | !36 = !DILocation(line: 10, column: 5, scope: !16) 95 | !37 = !DILocation(line: 11, column: 16, scope: !16) 96 | !38 = !DILocation(line: 11, column: 26, scope: !16) 97 | !39 = !DILocation(line: 11, column: 5, scope: !16) 98 | !40 = !DILocation(line: 12, column: 5, scope: !16) 99 | -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM ubuntu:24.04 2 | 3 | # Stop ubuntu-20 interactive options. 4 | ENV DEBIAN_FRONTEND noninteractive 5 | ARG TARGETPLATFORM 6 | 7 | # Stop script if any individual command fails. 8 | RUN set -e 9 | 10 | # Define LLVM version. 11 | ENV llvm_version=16.0.0 12 | 13 | # Define home directory 14 | ENV HOME=/home/SVF-tools 15 | 16 | # Define dependencies. 17 | ENV lib_deps="cmake g++ gcc git zlib1g-dev libncurses5-dev libtinfo6 build-essential libssl-dev libpcre2-dev zip libzstd-dev" 18 | ENV build_deps="wget xz-utils git gdb tcl software-properties-common" 19 | 20 | # Fetch dependencies. 21 | RUN apt-get update --fix-missing 22 | RUN apt-get install -y $build_deps $lib_deps 23 | 24 | # Add deadsnakes PPA for multiple Python versions 25 | RUN add-apt-repository ppa:deadsnakes/ppa 26 | RUN apt-get update 27 | RUN set -ex; \ 28 | apt-get update && apt-get install -y python3.10-dev python3-pip \ 29 | && update-alternatives --install /usr/bin/python3 python3 /usr/bin/python3.10 1; 30 | RUN python3 -m pip install pysvf -i https://test.pypi.org/simple/ 31 | RUN python3 -m pip install z3-solver 32 | 33 | # Fetch and build SVF source. 34 | RUN echo "Downloading LLVM and building SVF to " ${HOME} 35 | WORKDIR ${HOME} 36 | RUN git clone "https://github.com/SVF-tools/SVF.git" 37 | WORKDIR ${HOME}/SVF 38 | RUN echo "Building SVF ..." 39 | RUN bash ./build.sh debug 40 | 41 | # Export SVF, llvm, z3 paths 42 | ENV PATH=${HOME}/SVF/Release-build/bin:$PATH 43 | ENV PATH=${HOME}/SVF/llvm-$llvm_version.obj/bin:$PATH 44 | ENV SVF_DIR=${HOME}/SVF 45 | ENV LLVM_DIR=${HOME}/SVF/llvm-$llvm_version.obj 46 | ENV Z3_DIR=${HOME}/SVF/z3.obj 47 | RUN ln -s ${Z3_DIR}/bin/libz3.so ${Z3_DIR}/bin/libz3.so.4 48 | 49 | # Fetch and build Software-Security-Analysis 50 | WORKDIR ${HOME} 51 | RUN git clone "https://github.com/SVF-tools/Software-Security-Analysis.git" 52 | WORKDIR ${HOME}/Software-Security-Analysis 53 | RUN echo "Building Software-Security-Analysis ..." 54 | RUN sed -i 's/lldb/gdb/g' ${HOME}/Software-Security-Analysis/.vscode/launch.json 55 | RUN cmake -DCMAKE_BUILD_TYPE=Debug . 56 | RUN make -j8 57 | -------------------------------------------------------------------------------- /HelloWorld/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | add_executable(hello hello.cpp) 2 | set_target_properties( hello PROPERTIES 3 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) -------------------------------------------------------------------------------- /HelloWorld/hello.cpp: -------------------------------------------------------------------------------- 1 | #include 2 | using namespace std; 3 | 4 | int main() { 5 | cout << "Welcome to software security analysis course!\n"; 6 | return 0; 7 | } -------------------------------------------------------------------------------- /HelloWorld/hello.py: -------------------------------------------------------------------------------- 1 | print("Welcome to software security analysis course!") -------------------------------------------------------------------------------- /Lab-Exercise-1/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file(GLOB SOURCES 2 | CPP/*.cpp 3 | ) 4 | add_executable(lab1 ${SOURCES}) 5 | set_target_properties(lab1 PROPERTIES 6 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin) 7 | 8 | foreach (i RANGE 1 3) 9 | add_test( 10 | NAME lab1_test${i} 11 | COMMAND lab1 test${i} 12 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin 13 | ) 14 | endforeach () -------------------------------------------------------------------------------- /Lab-Exercise-1/CPP/GraphAlgorithm.cpp: -------------------------------------------------------------------------------- 1 | //===- GraphTraversal.cpp -- Graph algorithms ------------------// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2022> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===----------------------------------------------------------------------===// 22 | /* 23 | * Graph reachability and constraint solving on a self-defined graph 24 | * 25 | * Created on: Feb 18, 2024 26 | */ 27 | 28 | #include "GraphAlgorithm.h" 29 | 30 | using namespace std; 31 | 32 | /// TODO: Implement your depth-first search here to traverse each program path from src to dst (each node appears at most once in each path). 33 | /// Add each path as a string into std::set paths. 34 | /// Each path should have a format like this: "START->1->2->4->5->END", where -> indicates an edge connecting two node IDs. 35 | void Graph::reachability(Node* src, Node* dst) { 36 | /// TODO: your code starts from here 37 | } 38 | 39 | /// TODO: Implement constraint solving by iteratively (1) propagating points-to sets among nodes on CGraph, and (2) 40 | /// adding new copy edges until a fixed point is reached (i.e., no new copy edges are added). 41 | /// The solving rules are as follows: 42 | /// p <--ADDR-- o => pts(p) = pts(p) ∪ {o} 43 | /// q <--COPY-- p => pts(q) = pts(q) ∪ pts(p) 44 | /// q <--LOAD-- p => for each o ∈ pts(p) : q <--COPY-- o 45 | /// q <--STORE-- p => for each o ∈ pts(q) : o <--COPY-- p 46 | /// pts(q) denotes the points-to set of node q. 47 | /// Refer to the APIs in CGraph, including `addPts`, `getPts`, `unionPts` and `addEdge` for your implementation. 48 | void CGraph::solveWorklist() { 49 | /// TODO: your code starts from here 50 | } -------------------------------------------------------------------------------- /Lab-Exercise-1/CPP/test.cpp: -------------------------------------------------------------------------------- 1 | #include "GraphAlgorithm.h" 2 | 3 | bool Test1() { 4 | /* 5 | 6 | 7 | 1 8 | / \ 9 | 2 3 10 | \ / 11 | 4 12 | | 13 | 5 14 | 15 | */ 16 | // init nodes 17 | Node* node1 = new Node(1); 18 | Node* node2 = new Node(2); 19 | Node* node3 = new Node(3); 20 | Node* node4 = new Node(4); 21 | Node* node5 = new Node(5); 22 | 23 | // init edges 24 | Edge* edge1 = new Edge(node1, node2); 25 | Edge* edge2 = new Edge(node1, node3); 26 | node1->addOutEdge(edge1); 27 | node1->addOutEdge(edge2); 28 | Edge* edge3 = new Edge(node2, node4); 29 | Edge* edge4 = new Edge(node3, node4); 30 | node2->addOutEdge(edge3); 31 | node3->addOutEdge(edge4); 32 | Edge* edge5 = new Edge(node4, node5); 33 | node4->addOutEdge(edge5); 34 | 35 | // init Graph 36 | Graph* g = new Graph(); 37 | g->addNode(node1); 38 | g->addNode(node2); 39 | g->addNode(node3); 40 | g->addNode(node4); 41 | g->addNode(node5); 42 | // test 43 | g->reachability(node1, node5); 44 | // print paths 45 | std::set results = {"START->1->2->4->5->END", "START->1->3->4->5->END"}; 46 | if (g->getPaths().size() != results.size()) { 47 | std::cerr << "Test 1: Your result is not correct!" << std::endl; 48 | return false; 49 | } 50 | else { 51 | for (auto path : g->getPaths()) { 52 | if (results.find(path) == results.end()) { 53 | std::cerr << "Test 1: Your result is not correct!" << std::endl; 54 | return false; 55 | } 56 | } 57 | } 58 | return true; 59 | } 60 | 61 | bool Test2() { 62 | /* 63 | * 1 --(Addr)---> 2 --(Store)---> 4 --(Copy)---> 5 --(Load)---> 6 64 | * 3 --------(Addr)---------------^ 65 | */ 66 | // init nodes 67 | CGNode* node1 = new CGNode(1); 68 | CGNode* node2 = new CGNode(2); 69 | CGNode* node3 = new CGNode(3); 70 | CGNode* node4 = new CGNode(4); 71 | CGNode* node5 = new CGNode(5); 72 | CGNode* node6 = new CGNode(6); 73 | CGraph* g = new CGraph(); 74 | g->addNode(node1); 75 | g->addNode(node2); 76 | g->addNode(node3); 77 | g->addNode(node4); 78 | g->addNode(node5); 79 | g->addNode(node6); 80 | g->addEdge(node1, node2, CGEdge::ADDR); 81 | g->addEdge(node3, node4, CGEdge::ADDR); 82 | g->addEdge(node2, node4, CGEdge::STORE); 83 | g->addEdge(node4, node5, CGEdge::COPY); 84 | g->addEdge(node5, node6, CGEdge::LOAD); 85 | g->solveWorklist(); 86 | 87 | std::map> results = { 88 | {2, {1}}, 89 | {3, {1}}, 90 | {4, {3}}, 91 | {5, {3}}, 92 | {6, {1}}, 93 | }; 94 | 95 | for (auto res : results) { 96 | if (res.second != g->getPts(res.first)) { 97 | std::cerr << "Test 2: Your result is not correct!" << std::endl; 98 | return false; 99 | } 100 | } 101 | return true; 102 | } 103 | 104 | bool Test3() { 105 | /* 106 | * 11-(Addr)-> 1 2 <-(Addr)- 12 107 | * | | 108 | * (Store) (Store) 109 | * | | 110 | * v v 111 | * 13-(Addr)-> 3 (13) 4 <-(Addr)- 14 112 | * | | 113 | * (Copy) (Copy) 114 | * | | 115 | * v v 116 | * 5 <-- -->6 117 | * | | | | 118 | * | | | (Load) 119 | * | (Store) | v 120 | * (Load) |--------|--8 121 | * v | 122 | * 7-(Store)----| 123 | * */ 124 | // init nodes 125 | CGNode* node1 = new CGNode(1); 126 | CGNode* node2 = new CGNode(2); 127 | CGNode* node3 = new CGNode(3); 128 | CGNode* node4 = new CGNode(4); 129 | CGNode* node5 = new CGNode(5); 130 | CGNode* node6 = new CGNode(6); 131 | CGNode* node7 = new CGNode(7); 132 | CGNode* node8 = new CGNode(8); 133 | 134 | CGNode* node11 = new CGNode(11); 135 | CGNode* node12 = new CGNode(12); 136 | CGNode* node13 = new CGNode(13); 137 | CGNode* node14 = new CGNode(14); 138 | 139 | // init Graph 140 | CGraph* g = new CGraph(); 141 | g->addNode(node1); 142 | g->addNode(node2); 143 | g->addNode(node3); 144 | g->addNode(node4); 145 | g->addNode(node5); 146 | g->addNode(node6); 147 | g->addNode(node7); 148 | g->addNode(node8); 149 | 150 | g->addNode(node11); 151 | g->addNode(node12); 152 | g->addNode(node13); 153 | g->addNode(node14); 154 | 155 | // init edges 156 | g->addEdge(node11, node1, CGEdge::ADDR); 157 | g->addEdge(node12, node2, CGEdge::ADDR); 158 | g->addEdge(node13, node3, CGEdge::ADDR); 159 | g->addEdge(node14, node4, CGEdge::ADDR); 160 | 161 | g->addEdge(node1, node3, CGEdge::STORE); 162 | g->addEdge(node3, node5, CGEdge::COPY); 163 | g->addEdge(node5, node7, CGEdge::LOAD); 164 | g->addEdge(node2, node4, CGEdge::STORE); 165 | g->addEdge(node4, node6, CGEdge::COPY); 166 | g->addEdge(node6, node8, CGEdge::LOAD); 167 | g->addEdge(node8, node5, CGEdge::STORE); 168 | g->addEdge(node7, node6, CGEdge::STORE); 169 | 170 | g->solveWorklist(); 171 | 172 | std::map> results = { 173 | {1, {11}}, 174 | {2, {12}}, 175 | {3, {13}}, 176 | {4, {14}}, 177 | {5, {13}}, 178 | {6, {14}}, 179 | {7, {11, 12}}, 180 | {8, {11, 12}}, 181 | }; 182 | for (auto res : results) { 183 | if (res.second != g->getPts(res.first)) { 184 | std::cerr << "Test 2: Your result is not correct!" << std::endl; 185 | return false; 186 | } 187 | } 188 | return true; 189 | } 190 | 191 | /// Entry of the program 192 | int main(int argc, char** argv) { 193 | if (argc != 2) { 194 | std::cerr << "Usage: ./lab1 test1" << std::endl; 195 | return 1; 196 | } 197 | std::string test_name = argv[1]; 198 | if (test_name == "test1") { 199 | assert(Test1() && "Test 1 failed!"); 200 | } 201 | else if (test_name == "test2") { 202 | assert(Test2() && "Test 2 failed!"); 203 | } 204 | else if (test_name == "test3") { 205 | assert(Test3() && "Test 3 failed!"); 206 | } 207 | else { 208 | std::cerr << "Invalid test name" << std::endl; 209 | return 1; 210 | } 211 | } 212 | -------------------------------------------------------------------------------- /Lab-Exercise-2/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file (GLOB SOURCES 2 | CPP/*.cpp 3 | ) 4 | add_executable(lab2 ${SOURCES}) 5 | 6 | target_link_libraries(lab2 ${SVF_LIB} ${llvm_libs} ${Z3_LIBRARIES}) 7 | 8 | set_target_properties(lab2 PROPERTIES 9 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) 10 | 11 | foreach (i RANGE 0 10) 12 | add_test( 13 | NAME lab2_test${i} 14 | COMMAND lab2 test${i} 15 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin 16 | ) 17 | endforeach () 18 | -------------------------------------------------------------------------------- /Lab-Exercise-2/CPP/Z3Examples.h: -------------------------------------------------------------------------------- 1 | //===- Z3Examples.h -- Manual assertion-based verification (Z3 Example) ------------------// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2022> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===----------------------------------------------------------------------===// 22 | /* 23 | * Manual assertion-based verification (Z3 Example) 24 | * 25 | * Created on: Feb 19, 2024 26 | */ 27 | 28 | #ifndef SOFTWARE_SECURITY_ANALYSIS_Z3Examples_H 29 | #define SOFTWARE_SECURITY_ANALYSIS_Z3Examples_H 30 | 31 | #include "Z3Mgr.h" 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | 38 | namespace SVF { 39 | class Z3Examples : public Z3Mgr { 40 | public: 41 | Z3Examples(u32_t max) 42 | : Z3Mgr(max) 43 | , maxNumOfExpr(max) 44 | , currentExprIdx(0) {} 45 | 46 | // Return an z3 expr given an id 47 | inline z3::expr getZ3Expr(u32_t val) { 48 | return ctx.int_val(val); 49 | } 50 | 51 | // Return true if strToIDMap has this expression name 52 | inline bool hasZ3Expr(std::string exprName) { 53 | return strToIDMap.find(exprName) != strToIDMap.end(); 54 | } 55 | 56 | // Return an z3 expr given a string name 57 | inline z3::expr getZ3Expr(std::string exprName) { 58 | auto it = strToIDMap.find(exprName); 59 | if (it != strToIDMap.end()) 60 | return Z3Mgr::getZ3Expr(it->second); 61 | else { 62 | strToIDMap[exprName] = ++currentExprIdx; 63 | assert(maxNumOfExpr >= currentExprIdx && "creating more expression than upper limit"); 64 | z3::expr e = ctx.int_const(exprName.c_str()); 65 | updateZ3Expr(currentExprIdx, e); 66 | return e; 67 | } 68 | } 69 | 70 | // Return an z3 expr for an object given a string name 71 | inline z3::expr getMemObjAddress(std::string exprName) { 72 | z3::expr e = getZ3Expr(exprName); 73 | auto iter = strToIDMap.find(exprName); 74 | assert(iter != strToIDMap.end() && "address expr not found?"); 75 | e = getZ3Expr(Z3Mgr::getVirtualMemAddress(iter->second)); 76 | updateZ3Expr(iter->second, e); 77 | return e; 78 | } 79 | 80 | // Return a field object or array element object given a base pointer and an offset 81 | inline z3::expr getGepObjAddress(z3::expr pointer, u32_t offset) { 82 | std::string baseObjName = pointer.to_string(); 83 | auto iter = strToIDMap.find(baseObjName); 84 | assert(iter != strToIDMap.end() && "Gep BaseObject expr not found?"); 85 | u32_t baseObjID = iter->second; 86 | u32_t gepObj = baseObjID + offset; 87 | if (baseObjID == gepObj) { 88 | return pointer; 89 | } 90 | else { 91 | gepObj += maxNumOfExpr/2; // gep obj ID starts from maxNumOfExpr/2 in this lab exercise 92 | z3::expr e = getZ3Expr(Z3Mgr::getVirtualMemAddress(gepObj)); 93 | updateZ3Expr(gepObj, e); 94 | return e; 95 | } 96 | } 97 | 98 | // Add an z3 expression into solver for later satisfiability solving 99 | void addToSolver(z3::expr e) { 100 | solver.add(e); 101 | } 102 | 103 | // Reset solver's stack and clear up the maps 104 | void resetSolver() { 105 | solver.reset(); 106 | strToIDMap.clear(); 107 | currentExprIdx = 0; 108 | clearVarID2ExprMap(); 109 | } 110 | 111 | /// Print out all expressions' values after evaluation 112 | void printExprValues() { 113 | std::cout.flags(std::ios::left); 114 | std::cout << "-----------Var and Value-----------\n"; 115 | for (auto nIter = strToIDMap.begin(); nIter != strToIDMap.end(); nIter++) { 116 | z3::expr e = Z3Mgr::getEvalExpr(Z3Mgr::getZ3Expr(nIter->second)); 117 | if (e.is_numeral()) { 118 | s32_t value = e.get_numeral_int64(); 119 | std::stringstream exprName; 120 | exprName << "Var" << nIter->second << " (" << nIter->first << ")"; 121 | std::cout << std::setw(25) << exprName.str(); 122 | if (Z3Mgr::isVirtualMemAddress(value)) 123 | std::cout << "\t Value: " << std::hex << "0x" << value << "\n"; 124 | else 125 | std::cout << "\t Value: " << std::dec << value << "\n"; 126 | } 127 | } 128 | std::cout << "-----------------------------------------\n"; 129 | } 130 | 131 | /// To implement 132 | ///@{ 133 | void test0(); 134 | void test1(); 135 | void test2(); 136 | void test3(); 137 | void test4(); 138 | void test5(); 139 | void test6(); 140 | void test7(); 141 | void test8(); 142 | void test9(); 143 | void test10(); 144 | ///@} 145 | 146 | private: 147 | std::map strToIDMap; /// map a string name to its corresponding id (only used in Lab-Exercise-2) 148 | u32_t maxNumOfExpr; 149 | u32_t currentExprIdx; 150 | }; 151 | } // namespace SVF 152 | 153 | #endif // SOFTWARE_SECURITY_ANALYSIS_Z3Examples_H -------------------------------------------------------------------------------- /Lab-Exercise-2/CPP/Z3Mgr.cpp: -------------------------------------------------------------------------------- 1 | //===- Z3Mgr.cpp -- Z3 manager for software verification ------------------// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2022> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===----------------------------------------------------------------------===// 22 | /* 23 | * Z3 manager for software verification 24 | * 25 | * Created on: Feb 19, 2024 26 | */ 27 | 28 | #include "Z3Mgr.h" 29 | #include 30 | #include 31 | #include 32 | #include 33 | 34 | using namespace SVF; 35 | using namespace z3; 36 | using namespace std; 37 | 38 | /// Store and Select for Loc2ValMap, i.e., store and load 39 | /// The address needs to be evaluated to a value before accessing loc2ValMap 40 | z3::expr Z3Mgr::storeValue(const z3::expr loc, const z3::expr value) { 41 | z3::expr addr = getEvalExpr(loc); 42 | assert(isVirtualMemAddress(addr) && "Pointer operand is not a physical address?"); 43 | z3::expr loc2ValMap = varID2ExprMap[lastSlot]; 44 | loc2ValMap = z3::store(loc2ValMap, addr, value); 45 | varID2ExprMap.set(lastSlot, loc2ValMap); 46 | return loc2ValMap; 47 | } 48 | 49 | z3::expr Z3Mgr::loadValue(const z3::expr loc) { 50 | z3::expr addr = getEvalExpr(loc); 51 | assert(isVirtualMemAddress(addr) && "Pointer operand is not a physical address?"); 52 | z3::expr loc2ValMap = varID2ExprMap[lastSlot]; 53 | return z3::select(loc2ValMap, addr); 54 | } 55 | 56 | /// Return int value from an expression if it is a numeral, otherwise return an approximate value 57 | s32_t Z3Mgr::z3Expr2NumValue(z3::expr e) { 58 | z3::expr val = getEvalExpr(e); 59 | if (val.is_numeral()) 60 | return val.get_numeral_int64(); 61 | else { 62 | assert(false && "this expression is not numeral"); 63 | abort(); 64 | } 65 | } 66 | 67 | /// It checks if the constraints added to the Z3 solver are satisfiable. 68 | /// If they are, it retrieves the model that satisfies these constraints 69 | /// and evaluates the given complex expression e within this model, returning the evaluated result 70 | z3::expr Z3Mgr::getEvalExpr(z3::expr e) { 71 | z3::check_result res = solver.check(); 72 | assert(res != z3::unsat && "unsatisfied constraints! Check your contradictory constraints added to the solver"); 73 | z3::model m = solver.get_model(); 74 | return m.eval(e); 75 | } 76 | 77 | /// Print all expressions' values after evaluation 78 | void Z3Mgr::printExprValues() { 79 | std::cout.flags(std::ios::left); 80 | std::cout << "-----------Var and Value-----------\n"; 81 | for (u32_t i = 0; i < lastSlot; i++) { 82 | expr e = getEvalExpr(varID2ExprMap[i]); 83 | if (e.is_numeral()) { 84 | s32_t value = e.get_numeral_int64(); 85 | std::stringstream exprName; 86 | exprName << "Var" << i; 87 | std::cout << std::setw(25) << exprName.str(); 88 | if (isVirtualMemAddress(value)) 89 | std::cout << "\t Value: " << std::hex << "0x" << value << "\n"; 90 | else 91 | std::cout << "\t Value: " << std::dec << value << "\n"; 92 | } 93 | } 94 | std::cout << "-----------------------------------------\n"; 95 | } 96 | 97 | void Z3Mgr::printZ3Exprs() { 98 | std::cout << solver << "\n"; 99 | } 100 | -------------------------------------------------------------------------------- /Lab-Exercise-2/CPP/Z3Mgr.h: -------------------------------------------------------------------------------- 1 | //===- Z3Mgr.h -- Z3 manager for software verification ------------------// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2022> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===----------------------------------------------------------------------===// 22 | /* 23 | * Z3 manager for software verification 24 | * 25 | * Created on: Feb 19, 2024 26 | */ 27 | 28 | #ifndef SOFTWARE_SECURITY_ANALYSIS_Z3MGR_H 29 | #define SOFTWARE_SECURITY_ANALYSIS_Z3MGR_H 30 | 31 | #include "z3++.h" 32 | 33 | namespace SVF { 34 | 35 | #ifdef DEBUGINFO 36 | # define DBOP(X) X; 37 | #else 38 | # define DBOP(X) 39 | #endif 40 | 41 | // an ObjVar's ID in SVFIR will be marked using AddressMask (0x7f000000) to mimic the virtual memory address. 42 | // Note that this is not a physical runtime address but an abstract address to easy debugging purposes 43 | // FlippedAddressMask is used to strip off the mask 44 | #define AddressMask 0x7f000000 45 | #define FlippedAddressMask (AddressMask ^ 0xffffffff) 46 | 47 | typedef unsigned u32_t; 48 | typedef signed s32_t; 49 | 50 | /// Z3 manager interface 51 | class Z3Mgr { 52 | public: 53 | /// Constructor 54 | Z3Mgr(u32_t numOfMapElems) 55 | : solver(ctx) 56 | , varID2ExprMap(ctx) 57 | , lastSlot(numOfMapElems) { 58 | resetZ3ExprMap(); 59 | } 60 | 61 | /// reset and reinitialize Z3Exprs. 62 | /// varID2ExprMap: maps a variable id to its z3 expression 63 | /// loc2ValMap: maps an address location to its stored value, e.g., loc2ValMap[addr] = val 64 | inline void resetZ3ExprMap() { 65 | varID2ExprMap.resize(lastSlot + 1); 66 | z3::expr loc2ValMap = ctx.constant("loc2ValMap", ctx.array_sort(ctx.int_sort(), ctx.int_sort())); 67 | updateZ3Expr(lastSlot, loc2ValMap); 68 | } 69 | 70 | /// Store and Select for Loc2ValMap, i.e., store and load 71 | z3::expr storeValue(const z3::expr loc, const z3::expr value); 72 | z3::expr loadValue(const z3::expr loc); 73 | 74 | /// The physical address starts with 0x7f...... + idx 75 | inline u32_t getVirtualMemAddress(u32_t idx) const { 76 | return AddressMask + idx; 77 | } 78 | 79 | inline bool isVirtualMemAddress(u32_t val) { 80 | return (val > 0 && (val & AddressMask) == AddressMask); 81 | // return ((val & AddressMask) > 0); 82 | } 83 | 84 | inline bool isVirtualMemAddress(z3::expr e) { 85 | z3::expr val = getEvalExpr(e); 86 | if (val.is_numeral()) { 87 | return isVirtualMemAddress(z3Expr2NumValue(val)); 88 | } 89 | else { 90 | return false; 91 | } 92 | } 93 | 94 | /// Return the internal index if idx is an address otherwise return the value of idx 95 | inline u32_t getInternalID(u32_t idx) const { 96 | return (idx & FlippedAddressMask); 97 | } 98 | 99 | /// Return Z3 expression based on SVFVar ID 100 | inline z3::expr getZ3Expr(u32_t idx) const { 101 | assert(getInternalID(idx) == idx && "SVFVar idx overflow > 0x7f000000?"); 102 | assert(varID2ExprMap.size() >= idx + 1 && "idx out of bound for map access, increase map size!"); 103 | return varID2ExprMap[getInternalID(idx)]; 104 | } 105 | 106 | /// Update expression when assignments 107 | inline void updateZ3Expr(u32_t idx, z3::expr target) { 108 | assert(varID2ExprMap.size() >= idx + 1 && "idx out of bound for map access, increase map size!"); 109 | varID2ExprMap.set(getInternalID(idx), target); 110 | } 111 | 112 | /// Return int value from an expression if it is a numeral, otherwise return an approximate value 113 | s32_t z3Expr2NumValue(z3::expr e); 114 | 115 | /// It checks if the constraints added to the Z3 solver are satisfiable. 116 | /// If they are, it retrieves the model that satisfies these constraints 117 | /// and evaluates the given complex expression e within this model, returning the evaluated result 118 | z3::expr getEvalExpr(z3::expr e); 119 | 120 | /// Print all expressions' values after evaluation 121 | void printExprValues(); 122 | 123 | // Print all Z3 expressions 124 | void printZ3Exprs(); 125 | 126 | /// Return the z3 solver 127 | inline z3::solver& getSolver() { 128 | return solver; 129 | } 130 | /// Return the z3 solver context (typically corresponding to a program) 131 | inline z3::context& getCtx() { 132 | return ctx; 133 | } 134 | 135 | // Clean up the maps 136 | inline void clearVarID2ExprMap() { 137 | while (!varID2ExprMap.empty()) 138 | varID2ExprMap.pop_back(); 139 | 140 | resetZ3ExprMap(); 141 | } 142 | 143 | // For assert (Q), add ¬Q to the solver to prove the absence of counterexamples; 144 | // return true means there is no counterexample, false means there is at least one counterexample 145 | bool checkNegateAssert(z3::expr q) { 146 | // negative check 147 | getSolver().push(); 148 | getSolver().add(!q); 149 | getSolver().check(); 150 | bool res = getSolver().check() == z3::unsat; 151 | getSolver().pop(); 152 | return res; 153 | } 154 | 155 | protected: 156 | z3::context ctx; 157 | z3::solver solver; 158 | 159 | private: 160 | z3::expr_vector varID2ExprMap; /// var to z3 expression 161 | u32_t lastSlot; /// the last slot in the map for the z3 expression. 162 | }; 163 | 164 | } // namespace SVF 165 | 166 | #endif // SOFTWARE_SECURITY_ANALYSIS_Z3MGR_H 167 | -------------------------------------------------------------------------------- /Lab-Exercise-2/CPP/test.cpp: -------------------------------------------------------------------------------- 1 | //===- test.cpp -- Manual assertion-based verification (Z3 Example) ------------------// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2022> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===----------------------------------------------------------------------===// 22 | /* 23 | * Manual symbolic execution for assertion-based verification test cases 24 | * 25 | * Created on: Feb 19, 2024 26 | */ 27 | 28 | #include "Util/Options.h" 29 | #include "Z3Examples.h" 30 | 31 | using namespace z3; 32 | using namespace SVF; 33 | using namespace SVFUtil; 34 | 35 | /* 36 | // Please set the "program": "${workspaceFolder}/bin/ass3" in file '.vscode/launch.json' 37 | // To run your testcase from 1-7, please set the string number for "args" in file'.vscode/launch.json' 38 | // e.g. To run test0, set "args": ["0"] in file'.vscode/launch.json' 39 | */ 40 | int main(int argc, char** argv) { 41 | if (argc != 2) { 42 | std::cerr << "Usage: ./lab2 test1" << std::endl; 43 | return 1; 44 | } 45 | Z3Examples* z3Mgr = new Z3Examples(1000); 46 | bool result; 47 | std::string test_name = argv[1]; 48 | if (test_name == "test0") { 49 | z3Mgr->test0(); 50 | // assert(x==5); 51 | z3::expr assert_cond = (z3Mgr->getZ3Expr("x") == z3Mgr->getZ3Expr(5)); 52 | result = z3Mgr->checkNegateAssert(assert_cond); 53 | } 54 | else if (test_name == "test1") { 55 | z3Mgr->test1(); 56 | // assert(b > 0); 57 | // You are suggested to write your own results checking here 58 | result = false; 59 | } 60 | else if (test_name == "test2") { 61 | z3Mgr->test2(); 62 | // assert(b > 3); 63 | // You are suggested to write your own results checking here 64 | result = false; 65 | } 66 | else if (test_name == "test3") { 67 | z3Mgr->test3(); 68 | // assert(x==10); 69 | // You are suggested to write your own results checking here 70 | result = false; 71 | } 72 | else if (test_name == "test4") { 73 | z3Mgr->test4(); 74 | // assert((a + b)>20); 75 | // You are suggested to write your own results checking here 76 | result = false; 77 | } 78 | else if (test_name == "test5") { 79 | z3Mgr->test5(); 80 | // assert(b1 >= 5); 81 | // You are suggested to write your own results checking here 82 | result = false; 83 | } 84 | else if (test_name == "test6") { 85 | z3Mgr->test6(); 86 | // assert(*p == 5); 87 | // You are suggested to write your own results checking here 88 | result = false; 89 | } 90 | else if (test_name == "test7") { 91 | z3Mgr->test7(); 92 | // assert(d == 5); 93 | // You are suggested to write your own results checking here 94 | result = false; 95 | } 96 | else if (test_name == "test8") { 97 | z3Mgr->test8(); 98 | // assert(*p == 0); 99 | // You are suggested to write your own results checking here 100 | result = false; 101 | } 102 | else if (test_name == "test9") { 103 | z3Mgr->test9(); 104 | //assert(z == 15); 105 | // You are suggested to write your own results checking here 106 | result = false; 107 | } 108 | else if (test_name == "test10") { 109 | z3Mgr->test10(); 110 | // assert(x == 3 && y == 2); 111 | // You are suggested to write your own results checking here 112 | result = false; 113 | } 114 | else { 115 | std::cerr << "Invalid test name" << std::endl; 116 | return 1; 117 | } 118 | 119 | if (result) { 120 | std::cout << test_name << " passed!!" << std::endl; 121 | } 122 | else { 123 | std::cout << SVFUtil::errMsg(test_name) 124 | << SVFUtil::errMsg(" assertion is unsatisfiable!!") << std::endl; 125 | assert(result); 126 | } 127 | z3Mgr->resetSolver(); 128 | delete z3Mgr; 129 | return 0; 130 | } -------------------------------------------------------------------------------- /Lab-Exercise-3/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file (GLOB SOURCES 2 | CPP/*.cpp 3 | ) 4 | add_executable(lab3 ${SOURCES}) 5 | 6 | target_link_libraries(lab3 ${SVF_LIB} ${llvm_libs} ${Z3_LIBRARIES}) 7 | 8 | set_target_properties(lab3 PROPERTIES 9 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) 10 | 11 | foreach (i RANGE 1 8) 12 | add_test( 13 | NAME lab3_test${i} 14 | COMMAND lab3 test${i} 15 | WORKING_DIRECTORY ${CMAKE_BINARY_DIR}/bin 16 | ) 17 | endforeach () -------------------------------------------------------------------------------- /Lab-Exercise-3/CPP/test.cpp: -------------------------------------------------------------------------------- 1 | //===- test.cpp -- Abstract Execution -------------------------------------// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-2017> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU Affero General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU Affero General Public License for more details. 17 | 18 | // You should have received a copy of the GNU Affero General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===-----------------------------------------------------------------------===// 22 | 23 | /* 24 | // Abstract Execution tests 25 | // 26 | */ 27 | #include "SVF-LLVM/SVFIRBuilder.h" 28 | #include "Util/CommandLine.h" 29 | #include "Util/Options.h" 30 | #include "WPA/WPAPass.h" 31 | 32 | #include "AEMgr.h" 33 | 34 | using namespace SVF; 35 | using namespace SVFUtil; 36 | 37 | int main(int argc, char** argv) { 38 | if (argc != 2) { 39 | std::cerr << "Usage: ./lab3 test1" << std::endl; 40 | return 1; 41 | } 42 | 43 | AbstractExecutionMgr& mgr = AbstractExecutionMgr::getInstance(); 44 | 45 | std::string test_name = argv[1]; 46 | if (test_name == "test0") { 47 | SVFUtil::outs() << "Test 0: \n"; 48 | AEState as = mgr.test0(); 49 | // assert(x==5); 50 | // svf_assert(as[x].getInterval() == IntervalValue(5,5)); 51 | mgr.svf_assert(as[mgr.getNodeID("x")].getInterval() == IntervalValue(5, 5)); 52 | mgr.reset(); 53 | } 54 | else if (test_name == "test1") { 55 | SVFUtil::outs() << "Test 1: \n"; 56 | AEState as = mgr.test1(); 57 | // assert(b>0); 58 | // svf_assert(as[b].getInterval() > IntervalValue(0,0)); 59 | mgr.svf_assert(as[mgr.getNodeID("b")].getInterval() > IntervalValue(0, 0)); 60 | mgr.reset(); 61 | } 62 | else if (test_name == "test2") { 63 | SVFUtil::outs() << "Test 2: \n"; 64 | AEState as = mgr.test2(); 65 | // assert(b>3); 66 | // svf_assert(as[b].getInterval() > IntervalValue(3,3)); 67 | mgr.svf_assert(as[mgr.getNodeID("b")].getInterval() > IntervalValue(3, 3)); 68 | mgr.reset(); 69 | } 70 | else if (test_name == "test3") { 71 | SVFUtil::outs() << "Test 3: \n"; 72 | AEState as = mgr.test3(); 73 | // assert(x==10); 74 | // svf_assert(as[x].getInterval() == IntervalValue(10, 10)); 75 | mgr.svf_assert(as[mgr.getNodeID("x")].getInterval() == IntervalValue(10, 10)); 76 | mgr.reset(); 77 | } 78 | else if (test_name == "test4") { 79 | SVFUtil::outs() << "Test 4: \n"; 80 | AEState as = mgr.test4(); 81 | // assert((a + b)>20); 82 | // svf_assert(as[a].getInterval() + as[b].getInterval() > IntervalValue(20, 20)); 83 | mgr.svf_assert(as[mgr.getNodeID("a")].getInterval() + as[mgr.getNodeID("b")].getInterval() 84 | > IntervalValue(20, 20)); 85 | mgr.reset(); 86 | } 87 | else if (test_name == "test5") { 88 | SVFUtil::outs() << "Test 5: \n"; 89 | AEState as = mgr.test5(); 90 | // assert(z==15); 91 | // svf_assert(as[z].getInterval() == IntervalValue(15, 15)); 92 | mgr.svf_assert(as[mgr.getNodeID("z")].getInterval() == IntervalValue(15, 15)); 93 | mgr.reset(); 94 | } 95 | else if (test_name == "test6") { 96 | SVFUtil::outs() << "Test 6: \n"; 97 | AEState as = mgr.test6(); 98 | // assert(b>=5); 99 | // svf_assert(as[b].getInterval() >= IntervalValue(5, 5)); 100 | mgr.svf_assert(as[mgr.getNodeID("b")].getInterval() >= IntervalValue(5, 5)); 101 | mgr.reset(); 102 | } 103 | else if (test_name == "test7") { 104 | SVFUtil::outs() << "Test 7: \n"; 105 | AEState as = mgr.test7(); 106 | // assert(x== 3 && y==2); 107 | // AbstractValue cmp1 = as[x].getInterval() == IntervalValue(3, 3); 108 | // AbstractValue cmp2 = as[y].getInterval() == IntervalValue(2, 2); 109 | mgr.svf_assert(as[mgr.getNodeID("x")].getInterval() == IntervalValue(3, 3)); 110 | mgr.svf_assert(as[mgr.getNodeID("y")].getInterval() == IntervalValue(2, 2)); 111 | mgr.reset(); 112 | } 113 | else if (test_name == "test8") { 114 | SVFUtil::outs() << "Test 8: \n"; 115 | AEState as = mgr.test8(); 116 | // assert(x == 0); 117 | // svf_assert(as[x].getInterval() == IntervalValue(0, 0)); 118 | mgr.svf_assert(as[mgr.getNodeID("x")].getInterval() == IntervalValue(0, 0)); 119 | mgr.reset(); 120 | } 121 | else { 122 | std::cerr << "Invalid test name" << std::endl; 123 | return 1; 124 | } 125 | return 0; 126 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Static Analysis Course / Software Security Analysis Course 2 | [Course Content](https://github.com/SVF-tools/Software-Security-Analysis/wiki) 3 | 4 | If you fork this repository, please make it as private and do not disclose your solutions. 5 | -------------------------------------------------------------------------------- /SVFIR/CMakeLists.txt: -------------------------------------------------------------------------------- 1 | file (GLOB SOURCES 2 | *.cpp 3 | ) 4 | add_executable(svfir ${SOURCES}) 5 | 6 | target_link_libraries(svfir ${SVF_LIB} ${llvm_libs}) 7 | 8 | set_target_properties( svfir PROPERTIES 9 | RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin ) 10 | -------------------------------------------------------------------------------- /SVFIR/SVFIR.cpp: -------------------------------------------------------------------------------- 1 | //===- SVF IR and CodeGraph -- -------------------------------------// 2 | // 3 | // SVF: Static Value-Flow Analysis 4 | // 5 | // Copyright (C) <2013-> 6 | // 7 | 8 | // This program is free software: you can redistribute it and/or modify 9 | // it under the terms of the GNU General Public License as published by 10 | // the Free Software Foundation, either version 3 of the License, or 11 | // (at your option) any later version. 12 | 13 | // This program is distributed in the hope that it will be useful, 14 | // but WITHOUT ANY WARRANTY; without even the implied warranty of 15 | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 16 | // GNU General Public License for more details. 17 | 18 | // You should have received a copy of the GNU General Public License 19 | // along with this program. If not, see . 20 | // 21 | //===-----------------------------------------------------------------------===// 22 | 23 | /* 24 | // CodeGraphs including PAG, ICFG and ConstraintGraph 25 | // 26 | */ 27 | 28 | #include "Graphs/SVFG.h" 29 | #include "SABER/LeakChecker.h" 30 | #include "SVF-LLVM/LLVMUtil.h" 31 | #include "SVF-LLVM/SVFIRBuilder.h" 32 | #include "WPA/Andersen.h" 33 | 34 | using namespace SVF; 35 | using namespace llvm; 36 | using namespace std; 37 | 38 | int main(int argc, char** argv) { 39 | int arg_num = 0; 40 | int extraArgc = 4; 41 | char** arg_value = new char*[argc + extraArgc]; 42 | for (; arg_num < argc; ++arg_num) { 43 | arg_value[arg_num] = argv[arg_num]; 44 | } 45 | std::vector moduleNameVec; 46 | 47 | int orgArgNum = arg_num; 48 | arg_value[arg_num++] = (char*)"-model-arrays=true"; 49 | arg_value[arg_num++] = (char*)"-pre-field-sensitive=false"; 50 | arg_value[arg_num++] = (char*)"-model-consts=true"; 51 | arg_value[arg_num++] = (char*)"-stat=false"; 52 | assert(arg_num == (orgArgNum + extraArgc) && "more extra arguments? Change the value of extraArgc"); 53 | 54 | moduleNameVec = OptionBase::parseOptions(arg_num, arg_value, "SVF IR", "[options] "); 55 | 56 | LLVMModuleSet::getLLVMModuleSet()->buildSVFModule(moduleNameVec); 57 | 58 | /// Build Program Assignment Graph (SVFIR or PAG) 59 | SVFIRBuilder builder; 60 | SVFIR* pag = builder.build(); 61 | // Dump pag 62 | pag->dump(pag->getModuleIdentifier() + ".pag"); 63 | /// ICFG 64 | ICFG* icfg = pag->getICFG(); 65 | /// Dump icfg 66 | icfg->dump(pag->getModuleIdentifier() + ".icfg"); 67 | /// Create and dump ConstraintGraph 68 | ConstraintGraph* consCG = new ConstraintGraph(pag); 69 | consCG->dump(pag->getModuleIdentifier() + ".consG"); 70 | 71 | std::cout << "\n\nPrinting code graphs...\n\n"; 72 | 73 | /// iterate each ICFGNode on ICFG, 74 | /// where each node represents a SVFStatement (statement/instruction) and each edge represent a control-flow 75 | /// (execution order) between two statement 76 | std::cout << "\n\n####Printing ICFG (Interprocedural Control-Flow Graph)###\n\n"; 77 | for (ICFG::iterator it = icfg->begin(); it != icfg->end(); it++) { 78 | std::cout << it->second->toString() << "\n\n"; 79 | } 80 | std::cout << "######################################################\n"; 81 | 82 | /// iterate each node on PAG, 83 | /// where each node represents an SVFVar (variable) and each edge represents a SVFStatement 84 | std::cout << "\n\n#######Printing PAG (Program Assignment Graph)#######\n\n"; 85 | for (SVFIR::iterator it = pag->begin(); it != pag->end(); it++) { 86 | std::cout << it->second->toString() << "\n\n"; 87 | } 88 | std::cout << "#################################################\n"; 89 | 90 | /// iterate each node on Constraint Graph which is a subgraph of PAG. 91 | /// Constraint Graph only contains SVFVars are either pointers or objects (stack,global,heap and function objects) 92 | std::cout << "\n\n#############Printing Constraint Graph##########\n\n"; 93 | for (ConstraintGraph::iterator it = consCG->begin(); it != consCG->end(); it++) { 94 | std::cout << it->second->toString() << "\n\n"; 95 | } 96 | std::cout << "#################################################\n"; 97 | 98 | return 0; 99 | } 100 | -------------------------------------------------------------------------------- /SVFIR/compile.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Check if an argument (expected to be a .c file) is provided 4 | if [ -n "$1" ]; then 5 | # Extract the directory where the .c file is located 6 | dir=$(dirname "$1") 7 | 8 | # Extract the base name from the provided file and trim the .c extension 9 | file=$(basename "$1" .c) 10 | 11 | # Construct the full path for the output .ll file in the same directory as the .c file 12 | ll_file="$dir/$file.ll" 13 | 14 | # Use clang to compile the .c file to LLVM IR (.ll file), preserving variable names 15 | # and disabling optimizations that may discard value names 16 | clang -g -S -c -Xclang -disable-O0-optnone -fno-discard-value-names -emit-llvm "$1" -o "$ll_file" 17 | 18 | # Use LLVM's 'opt' tool to apply the mem2reg pass, which promotes memory to register 19 | # and outputs the transformed LLVM IR to the same .ll file 20 | opt -S -p=mem2reg "$ll_file" -o "$ll_file" 21 | else 22 | # If no file is provided as an argument, output an error message 23 | echo "Please provide a .c file as input." 24 | fi 25 | -------------------------------------------------------------------------------- /SVFIR/overflow/branch.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | #include 3 | int main(int argc) { 4 | int buf[10]; 5 | int *loc = malloc(sizeof(int)); 6 | int i = argc % 10; 7 | if (argc > 0) { 8 | *loc = i; 9 | } else { 10 | *loc = ++i; 11 | } 12 | int idx = *loc; 13 | buf[idx] = 1; 14 | } -------------------------------------------------------------------------------- /SVFIR/overflow/branch_safe.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | #include 3 | int main(int argc) { 4 | int buf[10]; 5 | int *loc = malloc(sizeof(int)); 6 | int i = argc % 10; 7 | if (argc > 0) { 8 | *loc = i; 9 | } else { 10 | *loc = ++i; 11 | } 12 | int idx = *loc; 13 | if (idx >= 0 && idx < 10) { 14 | buf[idx] = 1; 15 | } 16 | free(loc); 17 | return 0; 18 | } -------------------------------------------------------------------------------- /SVFIR/overflow/interprocedural.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define BUFFER_SIZE 10 5 | void handle_client_request(char *input, 6 | int index) { 7 | int buffer[BUFFER_SIZE] = { 0 }; 8 | if (index >= 0) 9 | buffer[index] = input[index]; 10 | else 11 | printf("ERR: Array index is negative\n"); 12 | } 13 | void process_socket_data(char *input, 14 | int index) { 15 | handle_client_request(input, index); 16 | } 17 | int main(int index) { 18 | char inputBuffer[BUFFER_SIZE] = {0}; 19 | process_socket_data(inputBuffer, index); 20 | return 0; 21 | } -------------------------------------------------------------------------------- /SVFIR/overflow/interprocedural_safe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #define BUFFER_SIZE 10 5 | void handle_client_request(char *input, 6 | int index) { 7 | int buffer[BUFFER_SIZE] = { 0 }; 8 | if (index >= 0 && index < BUFFER_SIZE) 9 | buffer[index] = input[index]; 10 | else 11 | printf("ERR: Array index is out of bounds\n"); 12 | } 13 | void process_socket_data(char *input, 14 | int index) { 15 | handle_client_request(input, index); 16 | } 17 | int main(int index) { 18 | char inputBuffer[BUFFER_SIZE] = {0}; 19 | process_socket_data(inputBuffer, index); 20 | return 0; 21 | } -------------------------------------------------------------------------------- /SVFIR/overflow/loop_1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #define BUF_LEN 20 3 | void handle_buffer(char *input) { 4 | char buffer[BUF_LEN]; 5 | for (int i = 0; i < 30; ++i) { 6 | buffer[i] = input[i]; 7 | if (input[i] == '\0') 8 | break; 9 | } 10 | buffer[BUF_LEN-1] = '\0'; 11 | printf("Buffer content: %s\n", buffer); 12 | } 13 | int main() { 14 | char input[30] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123"; 15 | handle_buffer(input); 16 | return 0; 17 | } -------------------------------------------------------------------------------- /SVFIR/overflow/loop_2.c: -------------------------------------------------------------------------------- 1 | #include 2 | void process_input(char input[5][10]) { 3 | char buffer[50]; 4 | int i, j, k = 0; 5 | for (i = 0; i < 5; i++) { 6 | for (j = 0; j <= 10; j++) { 7 | buffer[k++] = input[i][j]; 8 | } 9 | } 10 | buffer[49] = '\0'; 11 | } 12 | int main() { 13 | char input[5][10] = { 14 | "1234567890", 15 | "abcdefghij", 16 | "ABCDEFGHIJ", 17 | "0987654321", 18 | "ZYXWVUTSRQ" }; 19 | process_input(input); 20 | return 0; 21 | } -------------------------------------------------------------------------------- /SVFIR/overflow/loop_3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define BUF_LEN 20 4 | bool continue_copying = true; 5 | void copy_data(char *input) { 6 | char buffer[BUF_LEN]; 7 | int i = 0; 8 | while (continue_copying) { 9 | buffer[i] = input[i]; 10 | i++; 11 | if (input[i] == '\0') { 12 | continue_copying = false; 13 | } 14 | } 15 | buffer[BUF_LEN-1] = '\0'; 16 | printf("Buffer content: %s\n", buffer); 17 | } 18 | int main() { 19 | char input[30] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ123"; 20 | copy_data(input); 21 | return 0; 22 | } -------------------------------------------------------------------------------- /SVFIR/overflow/struct_and_array_1.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define NFT_LEN 16 4 | typedef struct { 5 | char buffer[8]; 6 | } nft_set_elem; 7 | void nft_set_elem_init(nft_set_elem *elem, 8 | int len) { 9 | // Some initialization code is omitted here 10 | elem->buffer[len - 1] = '\0'; 11 | } 12 | int main() { 13 | // Call the initialization function 14 | nft_set_elem elem; 15 | nft_set_elem_init(&elem, NFT_LEN); 16 | return 0; 17 | } -------------------------------------------------------------------------------- /SVFIR/overflow/struct_and_array_2.c: -------------------------------------------------------------------------------- 1 | #include 2 | struct Data { 3 | int value; 4 | char name[5]; 5 | }; 6 | void process_data_array(struct Data *data_array, 7 | int size) { 8 | for (int i = 0; i < size; i++) { 9 | for (int j = 0; j < size; j++) { 10 | data_array[i].name[j] = 'A'; 11 | } 12 | data_array[i].name[size-1] = '\0'; 13 | } 14 | } 15 | int main() { 16 | struct Data data_array[10]; 17 | process_data_array(data_array, 10); 18 | return 0; 19 | } -------------------------------------------------------------------------------- /SVFIR/overflow/struct_and_array_safe.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #define NFT_LEN 16 4 | typedef struct { 5 | char buffer[8]; 6 | } nft_set_elem; 7 | void nft_set_elem_init(nft_set_elem *elem, 8 | int len) { 9 | // Ensure we do not overflow the buffer 10 | if (len > sizeof(elem->buffer)) 11 | elem->buffer[sizeof(elem->buffer)-1] = '\0'; 12 | else 13 | elem->buffer[len - 1] = '\0'; 14 | } 15 | int main() { 16 | // Call the initialization function 17 | nft_set_elem elem; 18 | nft_set_elem_init(&elem, NFT_LEN); 19 | return 0; 20 | } -------------------------------------------------------------------------------- /SVFIR/src/andersen.c: -------------------------------------------------------------------------------- 1 | struct S{ 2 | int* f1; 3 | int* f2; 4 | }; 5 | int main(){ 6 | struct S s; 7 | int a1, a2; 8 | s.f1 = &a1; 9 | s.f2 = &a2; 10 | int* p = s.f1; 11 | int* q = s.f2; 12 | } 13 | -------------------------------------------------------------------------------- /SVFIR/src/branch.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | extern void svf_assert(bool); 3 | 4 | int main(int x){ 5 | int y; 6 | if(x > 10) 7 | y = x + 1; 8 | else 9 | y = 10; 10 | svf_assert(y>=x+1); 11 | } 12 | -------------------------------------------------------------------------------- /SVFIR/src/control-flow.c: -------------------------------------------------------------------------------- 1 | extern int source(); 2 | extern int sink(int); 3 | int bar(int s){ 4 | return s; 5 | } 6 | int main(){ 7 | int a = source(); 8 | if (a > 0){ 9 | int p = bar(a); 10 | sink(p); 11 | } 12 | else{ 13 | int q = bar(a); 14 | sink(q); 15 | } 16 | } 17 | 18 | -------------------------------------------------------------------------------- /SVFIR/src/demo.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include "stdbool.h" 4 | 5 | extern void broadcast(char* num); 6 | 7 | char *tgetstr(){ 8 | // e.g. sql injection init 9 | static char initstr[25] = "select* From City .."; 10 | return initstr; 11 | } 12 | 13 | extern void svf_assert(bool); 14 | 15 | 16 | int main(){ 17 | 18 | // Assignment-1 19 | char *injection = tgetstr(); 20 | char* s = injection; 21 | char* b = s; 22 | broadcast(b); 23 | 24 | // Assignment-2 25 | int *p; 26 | int a = 1; 27 | p = &a; 28 | *p = 3; 29 | svf_assert(a == 3); 30 | 31 | // Assignment-3 32 | int arr[5]; 33 | int i = 0; 34 | while(i < 5) { 35 | arr[++i]=10; 36 | } 37 | 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /SVFIR/src/example.c: -------------------------------------------------------------------------------- 1 | int foo(int b){ 2 | return b; 3 | } 4 | int main(){ 5 | int a = foo(0); 6 | } -------------------------------------------------------------------------------- /SVFIR/src/interprocedural.c: -------------------------------------------------------------------------------- 1 | #include "stdbool.h" 2 | extern void svf_assert(bool); 3 | 4 | int foo(int p) { 5 | return p; 6 | } 7 | int main(int argc) { 8 | int x; 9 | int y; 10 | x = foo(3); // ctx_7 11 | y = foo(argc); // ctx_8 12 | svf_assert(y == argc); 13 | } 14 | -------------------------------------------------------------------------------- /SVFIR/src/swap.c: -------------------------------------------------------------------------------- 1 | void swap(char **p, char **q){ 2 | char* t = *p; 3 | *p = *q; 4 | *q = t; 5 | } 6 | int main(){ 7 | char a1; 8 | char b1; 9 | char *a; 10 | char *b; 11 | a = &a1; 12 | b = &b1; 13 | swap(&a,&b); 14 | } 15 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Source the environment variables from the env.sh script 4 | source ./env.sh 5 | 6 | # Run cmake to configure the project with a Debug build type 7 | cmake -DCMAKE_BUILD_TYPE=Debug . 8 | 9 | # Compile the project using make 10 | make -j4 11 | -------------------------------------------------------------------------------- /env.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # Get the current working directory and store it in PROJECTHOME 4 | PROJECTHOME=$(pwd) 5 | 6 | # Detect the operating system type and store it in sysOS 7 | sysOS=`uname -s` 8 | 9 | # Set the major version of LLVM 10 | MajorLLVMVer=16 11 | 12 | # Define the full LLVM version 13 | LLVMVer=${MajorLLVMVer}.0.0 14 | 15 | # Set the home directories for LLVM and Z3 16 | LLVMHome="llvm-${LLVMVer}.obj" 17 | Z3Home="z3.obj" 18 | 19 | # Change this to your SVF root directory 20 | svf_root=`pwd`/../SVF 21 | 22 | # Export the paths for the LLVM, Z3, and SVF directories 23 | export LLVM_DIR=$svf_root/$LLVMHome 24 | export Z3_DIR=$svf_root/$Z3Home 25 | export SVF_DIR=$svf_root 26 | 27 | # Update the PATH to include the binary directories for SVF, LLVM, and the project 28 | export PATH=$SVF_DIR/Release-build/bin:$PATH 29 | export PATH=$LLVM_DIR/bin:$PATH 30 | export PATH=$PROJECTHOME/bin:$PATH 31 | 32 | # Print the paths to the terminal for verification 33 | echo "SVF_DIR="$SVF_DIR 34 | echo "LLVM_DIR="$LLVM_DIR 35 | echo "Z3_DIR="$Z3_DIR 36 | --------------------------------------------------------------------------------