├── .dockerignore ├── .github ├── ISSUE_TEMPLATE │ └── tool-report.md └── workflows │ └── testing.yml ├── .gitignore ├── Dockerfile ├── LICENSE ├── Makefile ├── README.md ├── av-rule-17 ├── descr └── recipe.scm ├── av-rule-174 ├── .merlin ├── api │ └── c │ │ └── errno_location.h ├── check-deref.lisp ├── descr ├── info ├── null_ptr_deref.ml ├── recipe.scm ├── stderr ├── stdin └── stdout ├── av-rule-189 ├── descr └── recipe.scm ├── av-rule-19 ├── descr ├── info └── recipe.scm ├── av-rule-20 ├── descr └── recipe.scm ├── av-rule-21 ├── descr └── recipe.scm ├── av-rule-22 ├── descr └── recipe.scm ├── av-rule-23 ├── descr └── recipe.scm ├── av-rule-24 ├── descr └── recipe.scm ├── av-rule-25 ├── descr └── recipe.scm ├── av-rule-3 ├── descr └── recipe.scm ├── build.sh ├── defective-symbol ├── descr └── recipe.scm ├── double-free ├── descr ├── double-free.lisp ├── recipe.scm ├── stdin └── stdout ├── find-symbol ├── .merlin ├── find_symbol.ml ├── find_symbol_rec.ml ├── find_symbol_rec.mli ├── find_symbol_report.ml ├── find_symbol_report.mli ├── find_symbol_types.ml ├── find_symbol_utils.ml ├── find_symbol_utils.mli └── info ├── forbidden-symbol ├── descr └── recipe.scm ├── heap-overflow ├── recipe.scm ├── stdin └── stdout ├── jpl-rule-11 ├── descr └── recipe.scm ├── jpl-rule-14 ├── .merlin ├── descr ├── info ├── recipe.scm ├── stderr ├── stdin ├── stdout ├── subroutines_info.ml ├── unused-return.lisp └── unused_return_value.ml ├── jpl-rule-4 ├── descr └── recipe.scm ├── must-check-value ├── .merlin ├── descr ├── info ├── must-check-value.lisp ├── must_check_value.ml ├── recipe.scm ├── stderr ├── stdin └── stdout ├── opam ├── pack.sh ├── primus-checks ├── descr ├── limit-malloc.lisp ├── recipe.scm ├── stdin └── stdout ├── restrictness-check ├── .merlin ├── descr ├── info ├── recipe.scm ├── restrict.lisp ├── restrictness_check.ml ├── stderr ├── stdin └── stdout ├── results.html ├── spectre ├── ddtbd.ml ├── descr ├── gather-spectre.lisp ├── info ├── limit-malloc.lisp ├── recipe.scm ├── stdin ├── stdout └── taint-inputs.lisp ├── tests ├── .dockerignore ├── Dockerfile ├── Makefile ├── README.md ├── artifacts │ ├── cron-3.0pl1-127 │ │ └── CVE-2019-9706 │ │ │ ├── expected │ │ │ └── run │ ├── gifsicle-1.89 │ │ └── CVE-2017-1000421 │ │ │ ├── expected │ │ │ └── run │ ├── juliet-cwe-122 │ │ └── heap-overflow │ │ │ ├── expected │ │ │ └── run │ ├── juliet-cwe-252 │ │ └── jpl-rule-14 │ │ │ ├── expected │ │ │ └── run │ ├── juliet-cwe-415 │ │ └── double-free │ │ │ ├── expected │ │ │ └── run │ ├── juliet-cwe-416 │ │ └── use-after-free │ │ │ ├── expected │ │ │ └── run │ ├── juliet-cwe-476 │ │ └── av-rule-174 │ │ │ ├── expected │ │ │ └── run │ ├── libgd-2.2.5 │ │ └── CVE-2018-1000222 │ │ │ ├── expected │ │ │ └── run │ ├── libssh-0.5.2 │ │ ├── CVE-2012-4559 │ │ │ ├── expected │ │ │ └── run │ │ └── CVE-2012-6063 │ │ │ ├── expected │ │ │ └── run │ ├── ntpd-4.2.8p12 │ │ └── CVE-2019-8936 │ │ │ ├── expected │ │ │ └── run │ └── tcpreplay-4.3.1 │ │ └── CVE-2019-8377 │ │ ├── expected │ │ └── run ├── copy_artifacts.sh ├── litmus-tests │ ├── bin │ │ ├── av-rule-17 │ │ ├── av-rule-174 │ │ ├── av-rule-189 │ │ ├── av-rule-19 │ │ ├── av-rule-20 │ │ ├── av-rule-21 │ │ ├── av-rule-22 │ │ ├── av-rule-23 │ │ ├── av-rule-24 │ │ ├── av-rule-25 │ │ ├── av-rule-3 │ │ ├── double-free │ │ ├── heap-overflow │ │ ├── jpl-rule-14 │ │ ├── jpl-rule-4 │ │ ├── must-check-value │ │ ├── restrictness-check │ │ ├── untrusted-argument │ │ ├── use-after-free │ │ └── warn-unused │ ├── data │ │ ├── av-rule-17 │ │ │ └── expected │ │ ├── av-rule-174 │ │ │ └── expected │ │ ├── av-rule-189 │ │ │ └── expected │ │ ├── av-rule-19 │ │ │ └── expected │ │ ├── av-rule-20 │ │ │ └── expected │ │ ├── av-rule-21 │ │ │ └── expected │ │ ├── av-rule-22 │ │ │ └── expected │ │ ├── av-rule-23 │ │ │ └── expected │ │ ├── av-rule-24 │ │ │ └── expected │ │ ├── av-rule-25 │ │ │ └── expected │ │ ├── av-rule-3 │ │ │ └── expected │ │ ├── double-free │ │ │ └── expected │ │ ├── heap-overflow │ │ │ └── expected │ │ ├── jpl-rule-14 │ │ │ └── expected │ │ ├── jpl-rule-4 │ │ │ └── expected │ │ ├── must-check-value │ │ │ └── expected │ │ ├── restrictness-check │ │ │ ├── api │ │ │ │ └── c │ │ │ │ │ └── myapi.h │ │ │ └── expected │ │ ├── untrusted-argument │ │ │ └── expected │ │ ├── use-after-free │ │ │ └── expected │ │ └── warn-unused │ │ │ └── expected │ └── src │ │ ├── av-rule-17.c │ │ ├── av-rule-174.c │ │ ├── av-rule-189.c │ │ ├── av-rule-19.c │ │ ├── av-rule-20.c │ │ ├── av-rule-21.c │ │ ├── av-rule-22.c │ │ ├── av-rule-23.c │ │ ├── av-rule-24.c │ │ ├── av-rule-25.c │ │ ├── av-rule-3.c │ │ ├── double-free.c │ │ ├── heap-overflow.c │ │ ├── jpl-rule-14.c │ │ ├── jpl-rule-4.c │ │ ├── must-check-value.c │ │ ├── restrictness-check.c │ │ ├── untrusted-argument.c │ │ ├── use-after-free.c │ │ └── warn-unused.c ├── run.sh ├── src │ ├── Makefile │ ├── compare_incidents.ml │ ├── compare_incidents.mli │ ├── dune │ └── dune-project └── update_dockerfile.sh ├── untrusted-argument ├── descr ├── limit-malloc.lisp ├── recipe.scm ├── stdin └── stdout ├── use-after-free ├── descr ├── recipe.scm ├── stdin ├── stdout └── use-after-free.lisp ├── warn-unused ├── .merlin ├── descr ├── info ├── recipe.scm ├── stderr ├── stdin ├── stdout ├── warn-unused-result.asd ├── warn-unused-result.lisp ├── warn_unused_result.ml └── warn_unused_result.mli └── with-no-return ├── .merlin ├── info └── with_no_return.ml /.dockerignore: -------------------------------------------------------------------------------- 1 | git 2 | .gitignore 3 | LICENSE 4 | VERSION 5 | README.md 6 | Changelog.md 7 | docker-compose.yml 8 | docs 9 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/tool-report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Tool Report 3 | about: 'Reporting false positives and false negatives ' 4 | title: " --? " 5 | labels: '' 6 | assignees: '' 7 | 8 | --- 9 | 10 | Note. Delete this message after you read it! If bap fails with an error, you have problems with installation, or need feedback, please use our main issue tracker. We reserve this one to track issues with tools capabilities. In the title, substitute: 11 | - - with a tool name, e.g., av-rule-17 12 | - - architecture of the target binary (the one being analyzed), e.g., arm 13 | - - the operating system for which the binary is compiled, if known, e.g., linux 14 | - - the environment for which the binary is compiled, if known, e.g., gnu 15 | - - the abi that the target binary, if known, e.g., eabi 16 | - ? - if the tools is not reporting an incident when there is one, then write false-negative, if it reports an incident in a benign case, write false-positive, other wise use other-problem. 17 | 18 | Here is an example of a title, 19 | ``` 20 | av-rule-17 arm-linux-gnueabi false-negative 21 | ``` 22 | Too upload the additional information zip it into an archive and attach to the issue. 23 | 24 | ---<--- Cut the message above ---<---- 25 | 26 | 27 | 1. What incidents are expected to be reported, in case of a false negative, or what incidents are reported but are not expected? What are the presumed locations of the weaknesses in the binary? 28 | 29 | 2. Upload the binary if possible. 30 | 31 | 3. Upload all files generated by the check, i.e., `log` files, `incidents`, `stdout`, `stderr`, etc (some may be missing depending on a tool) 32 | 33 | Additional Information 34 | ================= 35 | 36 | 1. The output of the following commands: 37 | ``` 38 | bap --version 39 | bap --llvm-version 40 | bap list plugins 41 | ``` 42 | 43 | 2. The set of symbols that bap detects in the binary 44 | ``` 45 | bap ./binary -dsymbols > binary.symbols 46 | ``` 47 | (substitute `binary` with the name of your binary) 48 | -------------------------------------------------------------------------------- /.github/workflows/testing.yml: -------------------------------------------------------------------------------- 1 | name: Daily test 2 | 3 | on: 4 | schedule: 5 | - cron: '0 0 * * *' # Every day at 00:00 UTC, 8 p.m. EDT 6 | workflow_dispatch: 7 | 8 | jobs: 9 | run-tests: 10 | runs-on: ubuntu-20.04 11 | name: run tests 12 | steps: 13 | 14 | - name: Install System Dependencies 15 | run: | 16 | sudo add-apt-repository ppa:ivg/ghidra -y 17 | sudo apt-get update -y 18 | sudo apt-get install libghidra-dev -y 19 | sudo apt-get install libghidra-data -y 20 | sudo apt-get install jq curl -y 21 | 22 | - name: Checkout BAP 23 | uses: actions/checkout@v3 24 | with: 25 | repository: BinaryAnalysisPlatform/bap 26 | 27 | - name: Install OCaml 28 | uses: ocaml/setup-ocaml@v2 29 | with: 30 | ocaml-compiler: 4.14.x 31 | dune-cache: true 32 | opam-disable-sandboxing: true 33 | 34 | - name: Install BAP 35 | run: opam install . 36 | 37 | - name: Checkout toolkit 38 | uses: actions/checkout@v3 39 | with: 40 | path: bap-toolkit 41 | 42 | - name: Install Toolkit 43 | run: | 44 | cd bap-toolkit 45 | opam exec -- make 46 | 47 | - name: Run tests 48 | run: | 49 | cd bap-toolkit 50 | opam exec -- make test 51 | 52 | - uses: actions/upload-artifact@v3 53 | if: ${{ always() }} 54 | with: 55 | name: toolkit-log 56 | path: /tmp/bap-toolkit/tests/toolkit.log 57 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | *.annot 2 | *.cmo 3 | *.cma 4 | *.cmi 5 | *.a 6 | *.o 7 | *.cmx 8 | *.cmxs 9 | *.cmxa 10 | *.recipe 11 | *.plugin 12 | *.incidents 13 | 14 | # ocamlbuild working directory 15 | _build/ 16 | 17 | # ocamlbuild targets 18 | *.byte 19 | *.native 20 | 21 | # oasis generated files 22 | setup.data 23 | setup.log 24 | 25 | # Merlin configuring file for Vim and Emacs 26 | #.merlin 27 | 28 | log 29 | artifact 30 | incidents 31 | tests/toolkit.log 32 | tests/compare-incidents -------------------------------------------------------------------------------- /Dockerfile: -------------------------------------------------------------------------------- 1 | FROM binaryanalysisplatform/bap:latest as base 2 | 3 | RUN sudo apt-get install zip --yes 4 | 5 | COPY --chown=opam:nogroup . /bap-toolkit 6 | WORKDIR /bap-toolkit 7 | RUN eval $(opam env) && make && make install 8 | 9 | 10 | FROM ubuntu:18.04 11 | RUN apt-get update && apt-get install libgmp-dev binutils --yes 12 | WORKDIR /bap-toolkit 13 | COPY --from=base /home/opam/.opam/4.09/bin/bap /usr/bin/ 14 | COPY --from=base /home/opam/.opam/4.09/lib/bap/*.plugin /home/opam/.opam/4.09/lib/bap/ 15 | COPY --from=base /home/opam/.opam/4.09/share/bap /home/opam/.opam/4.09/share/bap 16 | 17 | RUN cp -l /usr/bin/arch /artifact 18 | CMD ["bap", "disassemble", "/artifact", "--recipe=defective-symbol"] 19 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2018 BinaryAnalysisPlatform 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | all: build install 2 | 3 | install: 4 | sh build.sh install $(TARGET) 5 | 6 | build: clean 7 | sh build.sh build $(TARGET) 8 | 9 | test: 10 | make -C tests 11 | 12 | clean: 13 | sh build.sh clean $(TARGET) 14 | 15 | 16 | .PHONY: all install build clean test 17 | -------------------------------------------------------------------------------- /av-rule-17/descr: -------------------------------------------------------------------------------- 1 | The error indicator errno shall not be used. 2 | 3 | Motivation 4 | ========== 5 | 6 | Using errno as an indicator of an error condition is fragile and may lead to an undefined behavior. 7 | 8 | Exceptions 9 | ========== 10 | 11 | It is fine to use `errno` for diagnostic messages and in rare cases when it is the only 12 | and well-documented way to detect whether an error has occured. We will not try to handle 13 | the latter exception. 14 | 15 | Implementation Details 16 | ====================== 17 | 18 | Given that `errno` is an implementation-defined macro, it may not appear in binary's symbol table, 19 | and could be implemented either as an externally defined symbol, e.g., `__libc_errno` or a function 20 | returning a pointer to the `errno` location. Therefore while `errno` is a standard symbol in the 21 | source code, it is ABI specific, and we will gradually add support for different ABIs. Currently, 22 | we support the following ABI: 23 | 24 | - Linux SysV ABI (which uses the `__errno_location` function) 25 | 26 | The current implementation only checks if this symbol is imported. If it is, then `errno` is potentially 27 | used. It could be a benign diagnostic message, though. Later, we will extend the analysis to check 28 | if the `errno` variable actually induces any control dependencies. 29 | -------------------------------------------------------------------------------- /av-rule-17/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter verbosity 1 "the level of verbosity") 2 | 3 | (command find-symbol) 4 | (option names errno __errno_location) 5 | (option verbose $verbosity) 6 | -------------------------------------------------------------------------------- /av-rule-174/.merlin: -------------------------------------------------------------------------------- 1 | PKG core_kernel 2 | PKG bap 3 | PKG bap-primus 4 | PKG bap-x86-cpu 5 | PKG bap-taint 6 | 7 | S . 8 | B _build/ -------------------------------------------------------------------------------- /av-rule-174/api/c/errno_location.h: -------------------------------------------------------------------------------- 1 | 2 | 3 | int *__errno_location(void); 4 | -------------------------------------------------------------------------------- /av-rule-174/check-deref.lisp: -------------------------------------------------------------------------------- 1 | ;; 2 | ;; The algorithm itself is quite simple: 3 | ;; We taint every static zero that is saved into a register or a memory location 4 | ;; via stored/written methods. If the taint reaches any condition then we 5 | ;; consider this constant checked and no worries needed. Finally, if 6 | ;; there is a loading/storing operation with unchecked and tainted constant 7 | ;; then we trigger an incident. 8 | ;; 9 | ;; Analysis is written with keeping in mind that if a programmer 10 | ;; checked a pointer somehow - no matter if it was a correct check or not - 11 | ;; then using of the pointer is considered as a safe one. For example, 12 | ;; we apply this approach in the next case: mem [RAX + RBX] := 42, 13 | ;; when both registers hold zero and only one of them was checked - 14 | ;; in this case no incident will be emited 15 | 16 | (require taint) 17 | 18 | (defun notify-null-deref (taint) 19 | (let ((pc (get-current-program-counter)) 20 | (start (dict-get 'intro taint)) 21 | (intro (dict-get 'intro/location taint))) 22 | (when (not (is-reported-deref pc)) 23 | (when start 24 | (msg "pointer was introduced at $0 from taint $1" start taint)) 25 | (notify-null-ptr-dereference start pc) 26 | (incident-report 'null-ptr-deref (incident-location) intro)))) 27 | 28 | (defun is-null (ptr) 29 | (and (not ptr) (all-static-constant ptr))) 30 | 31 | (defun check-deref-null-ptr (ptr) 32 | (when (is-null ptr) 33 | (let ((taint (taint-get-direct 'const-ptr ptr)) 34 | (checked (dict-get 'checked-pointer taint))) 35 | (when (and taint (not checked)) 36 | (notify-null-deref taint))))) 37 | 38 | (defmethod jumping (x _) 39 | (let ((taint (taint-get-direct 'const-ptr x))) 40 | (when taint 41 | (dict-add 'checked-pointer taint taint)))) 42 | 43 | (defmethod written (v x) 44 | (when (not (taint-get-direct 'const-ptr x)) 45 | (when (and (is-null x) (not (is-cpu-flag v))) 46 | (let ((taint (taint-introduce-directly 'const-ptr x))) 47 | (dict-add 'intro taint (get-current-program-counter)) 48 | (dict-add 'intro/location taint (incident-location)))))) 49 | 50 | (defmethod stored (a x) 51 | (when (is-null x) 52 | (let ((taint (taint-introduce-directly 'const-ptr x))) 53 | (dict-add 'intro taint (get-current-program-counter)) 54 | (dict-add 'intro/location taint (incident-location))))) 55 | 56 | (defmethod storing (ptr) 57 | (check-deref-null-ptr ptr)) 58 | 59 | (defmethod loading (ptr) 60 | (check-deref-null-ptr ptr)) 61 | -------------------------------------------------------------------------------- /av-rule-174/descr: -------------------------------------------------------------------------------- 1 | The null pointer shall not be de-referenced 2 | 3 | The algorithm. 4 | Every static constant in a program becomes a source of a taint. 5 | And if there is a load from or store by the tainted address, then 6 | a null pointer is actually dereferenced. Additionally, 7 | we check if the tainted value reaches any conditional 8 | block. And if does and there is a control dependency between 9 | pointer dereferencing and condition, we don't consider such 10 | case as real null pointer dereferencing, because it is under 11 | the check. 12 | 13 | All checks are reported: 14 | - to stdout in the user friendly format 15 | - via the incident report system and are stored 16 | in the working directory in the `incidents' file. 17 | The file could be loaded in IDA Pro for further analysis. 18 | -------------------------------------------------------------------------------- /av-rule-174/info: -------------------------------------------------------------------------------- 1 | main: null_ptr_deref.ml 2 | depends: bap bap-main bap-primus bap-x86-cpu bap-taint -------------------------------------------------------------------------------- /av-rule-174/null_ptr_deref.ml: -------------------------------------------------------------------------------- 1 | open Core_kernel 2 | open Bap.Std 3 | open Bap_primus.Std 4 | 5 | include Self () 6 | 7 | let check_name = "null pointer dereference" 8 | 9 | type verbose = 10 | | Brief 11 | | Detail 12 | 13 | let verbose_of_int = function 14 | | 1 -> Brief 15 | | _ -> Detail 16 | 17 | type state = { 18 | derefs : Addr.Set.t; 19 | verbose : verbose; 20 | } 21 | 22 | let state = Primus.Machine.State.declare 23 | ~uuid:"3e065801-3af7-41f0-af1c-e20b9407da11" 24 | ~name:"null-ptr-dereference" 25 | (fun _ -> { 26 | derefs = Set.empty (module Addr); 27 | verbose = Brief;}) 28 | 29 | let atos = sprintf "%a" Addr.pps 30 | 31 | let pp_bold ppf = Format.fprintf ppf "\027[1m" 32 | let pp_norm ppf = Format.fprintf ppf "\027[0m" 33 | 34 | module Reporter(Machine : Primus.Machine.S) = struct 35 | module Value = Primus.Value.Make(Machine) 36 | open Machine.Syntax 37 | 38 | let print_ok () = Format.printf "%s OK\n" check_name 39 | let print_fail () = Format.printf "%s FAIL\n" check_name 40 | 41 | let on_exit () = 42 | Machine.Global.get state >>| fun s -> 43 | if Set.is_empty s.derefs then print_ok () 44 | 45 | let print_header = function 46 | | Detail -> 47 | Format.printf "\n%t%-10s %s\n%t" pp_bold "Address" "Introduced" pp_norm 48 | | _ -> () 49 | 50 | let report_deref intro addr = function 51 | | Detail -> 52 | Format.printf "%-10s %s\n%!" (atos addr) (atos intro) 53 | | _ -> () 54 | 55 | let update intro addr = 56 | let intro = Value.to_word intro in 57 | let addr = Value.to_word addr in 58 | Machine.Global.update state ~f:(fun s -> 59 | if Set.mem s.derefs addr then s 60 | else 61 | let () = 62 | if Set.is_empty s.derefs then 63 | let () = print_fail () in 64 | print_header s.verbose in 65 | let () = report_deref addr intro s.verbose in 66 | {s with derefs = Set.add s.derefs addr}) >>= fun () -> 67 | Value.b0 68 | end 69 | 70 | module Notify(Machine : Primus.Machine.S) = struct 71 | module Reporter = Reporter(Machine) 72 | 73 | [@@@warning "-P"] 74 | let run [intro; addr] = Reporter.update intro addr 75 | end 76 | 77 | 78 | module Init_reports(S : sig val verbose : verbose end)(Machine : Primus.Machine.S) = struct 79 | module Reporter = Reporter(Machine) 80 | open Machine.Syntax 81 | 82 | let on_stop _ = Reporter.on_exit () 83 | 84 | let init () = 85 | Machine.Global.update state 86 | ~f:(fun s -> {s with verbose = S.verbose}) >>= fun () -> 87 | Primus.System.stop >>> on_stop 88 | 89 | end 90 | 91 | module IsReported(Machine : Primus.Machine.S) = struct 92 | module Value = Primus.Value.Make(Machine) 93 | open Machine.Syntax 94 | 95 | [@@@warning "-P"] 96 | let run [a] = 97 | Machine.Global.get state >>= fun {derefs} -> 98 | Value.of_bool (Set.mem derefs (Value.to_word a)) 99 | end 100 | 101 | let flags = 102 | Primus.Machine.State.declare 103 | ~uuid:"9b2c0dff-5adf-44e5-8257-d7cfb956165c" 104 | ~name:"cpu-flags" 105 | (fun _ -> Set.empty (module String)) 106 | 107 | module Flags(Machine : Primus.Machine.S) = struct 108 | open Machine.Syntax 109 | 110 | let init () = 111 | Machine.arch >>= fun a -> 112 | let module T = (val target_of_arch a) in 113 | let known = 114 | T.CPU.([sp; zf; cf; vf; nf]) |> 115 | List.map ~f:Var.name |> 116 | Set.of_list (module String) in 117 | Machine.Global.put flags known 118 | end 119 | 120 | module IsFlag(Machine : Primus.Machine.S) = struct 121 | module Value = Primus.Value.Make(Machine) 122 | open Machine.Syntax 123 | 124 | [@@@warning "-P"] 125 | let run [x] = 126 | Value.Symbol.of_value x >>= fun name -> 127 | Machine.Global.get flags >>= fun s -> 128 | Value.of_bool (Set.mem s name) 129 | end 130 | 131 | module Lisp(Machine : Primus.Machine.S) = struct 132 | module Lisp = Primus.Lisp.Make(Machine) 133 | open Primus.Lisp.Type.Spec 134 | 135 | let def name types docs closure = Lisp.define ~docs ~types name closure 136 | 137 | let init () = 138 | Machine.sequence Primus.Interpreter.[ 139 | 140 | def "is-reported-deref" (tuple [a] @-> bool) 141 | "(is-reported-deref ADDR) returns true if 142 | a null pointer dereference at ADDR is the known 143 | incident and was reported before" 144 | (module IsReported); 145 | 146 | def "is-cpu-flag" (tuple [a] @-> bool) 147 | "(is-cpu-flag X) returns true if X is a flag variable" 148 | (module IsFlag); 149 | 150 | def "notify-null-ptr-dereference" (tuple [a;b] @-> any) 151 | "(notify-null-ptr-dereference INTRO ADDR) 152 | print message to stdout when pointer that was 153 | introduced at address INTRO is dereferenced at 154 | address ADDR" 155 | (module Notify); 156 | ] 157 | end 158 | 159 | open Bap_main 160 | 161 | let enabled = 162 | Extension.Configuration.flag 163 | ~doc:"Enables the analysis" 164 | "enable" 165 | 166 | let verbose = 167 | Extension.Configuration.parameter 168 | ~doc:"Level of verbosity. Currently supported 169 | 1 - prints a result message, if the check passed or not; 170 | >1 - prints locations of null pointer dereferences" 171 | Extension.Type.(int =? 1) 172 | "verbose" 173 | 174 | let () = 175 | let open Extension.Syntax in 176 | Extension.declare 177 | @@ fun ctxt -> 178 | if ctxt --> enabled then 179 | begin 180 | Primus.Machine.add_component (module Lisp); 181 | Primus.Machine.add_component (module Flags); 182 | Primus.Machine.add_component 183 | (module Init_reports(struct 184 | let verbose = verbose_of_int (ctxt --> verbose) 185 | end)); 186 | end; 187 | Ok () 188 | [@@warning "-D"] 189 | -------------------------------------------------------------------------------- /av-rule-174/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter depth 32768 "a depth of analysis") 2 | (parameter entry-points all-subroutines "where to search") 3 | (parameter optimization 2 "optimization level") 4 | (parameter verbosity 1 "verbosity level") 5 | 6 | (option passes 7 | with-no-return 8 | run) 9 | 10 | (option primus-lisp-load 11 | posix 12 | check-deref) 13 | 14 | (option api-path $prefix/api) 15 | 16 | (option run-entry-points ${entry-points}) 17 | 18 | (option constant-tracker-enable) 19 | (option report-progress) 20 | (option null-ptr-deref-enable) 21 | (option null-ptr-deref-verbose $verbosity) 22 | 23 | (option primus-lisp-add $prefix) 24 | (option primus-promiscuous-mode) 25 | (option primus-greedy-scheduler) 26 | (option primus-limit-max-length $depth) 27 | (option primus-print-output incidents) 28 | 29 | (option optimization-level $optimization) 30 | 31 | (option primus-lisp-channel-redirect 32 | :$prefix/stdin 33 | :$prefix/stdout 34 | :$prefix/stderr) 35 | 36 | (option primus-print-observations 37 | written 38 | stored 39 | exception 40 | pc-changed 41 | jumping 42 | call 43 | call-return 44 | lisp-message 45 | machine-switch 46 | machine-fork 47 | incident 48 | incident-location) 49 | 50 | (option log-dir log) 51 | -------------------------------------------------------------------------------- /av-rule-174/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/av-rule-174/stderr -------------------------------------------------------------------------------- /av-rule-174/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/av-rule-174/stdin -------------------------------------------------------------------------------- /av-rule-174/stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/av-rule-174/stdout -------------------------------------------------------------------------------- /av-rule-189/descr: -------------------------------------------------------------------------------- 1 | The goto statement shall not be used 2 | 3 | This rule means that a control flow graph of each subroutine 4 | should be reducible. Or, as vice versa, there should not be 5 | any subroutine with non-reducible control flow graph. 6 | 7 | The CFG is considered as a reducible one if if doesn't contain 8 | strongly connected components with two and more entries. 9 | -------------------------------------------------------------------------------- /av-rule-189/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter verbosity 1 "the level of verbosity") 2 | 3 | (option pass find-symbol) 4 | (option find-symbol-non-structured) 5 | (option find-symbol-verbose $verbosity) 6 | -------------------------------------------------------------------------------- /av-rule-19/descr: -------------------------------------------------------------------------------- 1 | and the setlocale function shall not be used 2 | 3 | Checks the program for a usage of the functions defined in the file : 4 | - setlocale 5 | - localeconv 6 | 7 | The algorithm is pretty straightforward: we check the input edges for every subroutine 8 | in the program callgraph, and if there are some then the subroutine is considered as a used one, 9 | i.e. there is at least one call of the given subroutine. 10 | -------------------------------------------------------------------------------- /av-rule-19/info: -------------------------------------------------------------------------------- 1 | descr: detects a usage of the setlocale function from 2 | -------------------------------------------------------------------------------- /av-rule-19/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter verbosity 1 "the level of verbosity") 2 | 3 | (command find-symbol) 4 | (option names setlocale localeconv) 5 | (option verbose $verbosity) 6 | -------------------------------------------------------------------------------- /av-rule-20/descr: -------------------------------------------------------------------------------- 1 | The setjmp macro and the longjmp function shall not be used 2 | 3 | Checks the program for a usage of the next functions defined in the file : 4 | - setjmp 5 | - longjmp 6 | 7 | The algorithm is pretty straightforward: we check the input edges for every subroutine 8 | in the program callgraph, and if there are some then the subroutine is considered as a used one, 9 | i.e. there is at least one call of the given subroutine. 10 | -------------------------------------------------------------------------------- /av-rule-20/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter verbosity 1 "the level of verbosity") 2 | 3 | (command find-symbol) 4 | (option names setjmp longjmp) 5 | (option verbose $verbosity) 6 | -------------------------------------------------------------------------------- /av-rule-21/descr: -------------------------------------------------------------------------------- 1 | The signal handling facilities of shall not be used 2 | 3 | 4 | Checks the program for a usage of the next functions defined in the file : 5 | - signal 6 | - raise 7 | 8 | The algorithm is pretty straightforward: we check the input edges for every subroutine 9 | in the program callgraph, and if there are some then the subroutine is considered as a used one, 10 | i.e. there is at least one call of the given subroutine. -------------------------------------------------------------------------------- /av-rule-21/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter verbosity 1 "the level of verbosity") 2 | 3 | (command find-symbol) 4 | (option names signal raise) 5 | (option verbose $verbosity) 6 | -------------------------------------------------------------------------------- /av-rule-22/descr: -------------------------------------------------------------------------------- 1 | The input/output library shall not be used 2 | 3 | Checks the program for a usage of the next functions defined in the file : 4 | - fclose 5 | - clearerr 6 | - feof 7 | - ferror 8 | - fflush 9 | - fgetpos 10 | - fopen 11 | - fread 12 | - freopen 13 | - fseek 14 | - fsetpos 15 | - ftell 16 | - fwrite 17 | - remove 18 | - rename 19 | - rewind 20 | - setbuf 21 | - setvbuf 22 | - tmpfile 23 | - tmpnam 24 | - fprintf 25 | - printf 26 | - sprintf 27 | - vfprintf 28 | - vprintf 29 | - vsprintf 30 | - fscanf 31 | - scanf 32 | - sscanf 33 | - fgetc 34 | - fgets 35 | - fputc 36 | - fputs 37 | - getc 38 | - getchar 39 | - gets 40 | - putc 41 | - putchar 42 | - puts 43 | - ungetc 44 | - perror 45 | 46 | The algorithm is pretty straightforward: we check the input edges for every subroutine 47 | in the program callgraph, and if there are some then the subroutine is considered as a used one, 48 | i.e. there is at least one call of the given subroutine. -------------------------------------------------------------------------------- /av-rule-22/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter verbosity 1 "the level of verbosity") 2 | 3 | (command find-symbol) 4 | (option names 5 | fclose 6 | clearerr 7 | feof 8 | ferror 9 | fflush 10 | fgetpos 11 | fopen 12 | fread 13 | freopen 14 | fseek 15 | fsetpos 16 | ftell 17 | fwrite 18 | remove 19 | rename 20 | rewind 21 | setbuf 22 | setvbuf 23 | tmpfile 24 | tmpnam 25 | fprintf 26 | printf 27 | sprintf 28 | vfprintf 29 | vprintf 30 | vsprintf 31 | fscanf 32 | scanf 33 | sscanf 34 | fgetc 35 | fgets 36 | fputc 37 | fputs 38 | getc 39 | getchar 40 | gets 41 | putc 42 | putchar 43 | puts 44 | ungetc 45 | perror) 46 | (option verbose $verbosity) 47 | -------------------------------------------------------------------------------- /av-rule-23/descr: -------------------------------------------------------------------------------- 1 | The library functions atof, atoi and atol from library shall not be used 2 | 3 | 4 | Checks the program for a usage of the next functions defined in the file : 5 | - atof 6 | - atoi 7 | - atol 8 | 9 | The algorithm is pretty straightforward: we check the input edges for every subroutine 10 | in the program callgraph, and if there are some then the subroutine is considered as a used one, 11 | i.e. there is at least one call of the given subroutine. -------------------------------------------------------------------------------- /av-rule-23/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter verbosity 1 "the level of verbosity") 2 | 3 | (command find-symbol) 4 | (option names atof atoi atol) 5 | (option verbose $verbosity) 6 | -------------------------------------------------------------------------------- /av-rule-24/descr: -------------------------------------------------------------------------------- 1 | The library functions abort, exit, getenv and system from library shall not be used 2 | 3 | Checks the program for a usage of the next functions defined in the file : 4 | - abort 5 | - exit 6 | - getenv 7 | - system 8 | 9 | The algorithm is pretty straightforward: we check the input edges for every subroutine 10 | in the program callgraph, and if there are some then the subroutine is considered as a used one, 11 | i.e. there is at least one call of the given subroutine. -------------------------------------------------------------------------------- /av-rule-24/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter verbosity 1 "the level of verbosity") 2 | 3 | (command find-symbol) 4 | (option name abort exit getenv system) 5 | (option verbose $verbosity) 6 | -------------------------------------------------------------------------------- /av-rule-25/descr: -------------------------------------------------------------------------------- 1 | The time handling functions of library shall not be used 2 | 3 | Checks the program for a usage of the next functions defined in the file : 4 | - asctime 5 | - clock 6 | - ctime 7 | - difftime 8 | - gmtime 9 | - localtime 10 | - mktime 11 | - strftime 12 | - time 13 | 14 | The algorithm is pretty straightforward: we check the input edges for every subroutine 15 | in the program callgraph, and if there are some then the subroutine is considered as a used one, 16 | i.e. there is at least one call of the given subroutine. -------------------------------------------------------------------------------- /av-rule-25/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter verbosity 1 "the level of verbosity") 2 | 3 | (command find-symbol) 4 | (option names 5 | asctime 6 | clock 7 | ctime 8 | difftime 9 | gmtime 10 | localtime 11 | mktime 12 | strftime 13 | time) 14 | (option verbose $verbosity) 15 | -------------------------------------------------------------------------------- /av-rule-3/descr: -------------------------------------------------------------------------------- 1 | All functions shall have a cyclomatic complexity number of 50 or less. 2 | 3 | The cyclomatic complexity number is a metric that is used to determine a 4 | number of linearly independent paths in a subroutine control flow graph (CFG). 5 | The number is computed using the following formula, 6 | 7 | C = E - N + P 8 | 9 | where `E` is the number of edges, `N` is the number of nodes, and `P` is 10 | the number of strongly connected components. The CFG exit node is connected 11 | to its entry node, so that an acyclic function will have one connected component. 12 | 13 | The threshold 50 is a parameter. 14 | -------------------------------------------------------------------------------- /av-rule-3/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter threshold 50 "the maximum allowed complexity") 2 | (parameter verbosity 1 "the level of verbosity") 3 | 4 | (option pass find-symbol) 5 | (option find-symbol-complexity $threshold) 6 | (option find-symbol-verbose $verbosity) 7 | -------------------------------------------------------------------------------- /build.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | PLUGIN_MAIN="" 4 | PLUGIN_DEPS="" 5 | PLUGIN_DESC="" 6 | HAS_BUILD_TOOLS="FALSE" 7 | 8 | # checks that necessary build tools are installed 9 | check_build_tools() { 10 | if [ "no-$(which bapbuild)" != "no-" ] && [ "no-$(which bapbundle)" != "no-" ]; then 11 | HAS_BUILD_TOOLS="TRUE" 12 | fi 13 | } 14 | 15 | # reads line env variable and extracts main, depends, descr fields 16 | parse_line() { 17 | field=`echo $line | cut -d':' -f1 | sed 's/^[ *]//g;s/[ *]*$//'` 18 | 19 | if [ "no-$field" != "no-" ]; then 20 | if [ "$field" = "main" ]; then 21 | PLUGIN_MAIN=`echo $line | cut -d':' -f2` 22 | fi 23 | if [ "$field" = "depends" ]; then 24 | PLUGIN_DEPS=`echo $line | cut -d':' -f2 | sed 's/^[ *]//g'` 25 | fi 26 | if [ "$field" = "descr" ]; then 27 | PLUGIN_DESC=`echo $line | cut -d':' -f2` 28 | fi 29 | fi 30 | } 31 | 32 | # reads info file if exists 33 | # pre: already in the directory with a check 34 | read_info() { 35 | unset PLUGIN_MAIN 36 | unset PLUGIN_DEPS 37 | unset PLUGIN_DESC 38 | 39 | PLUGIN_MAIN=`echo $1 | sed 's/-/_/g'` 40 | if [ -e info ]; then 41 | while IFS= read -r line 42 | do 43 | parse_line $line 44 | done < info 45 | parse_line $line 46 | fi 47 | } 48 | 49 | 50 | # packs a recipe folder into a zip file for the ease of sharing 51 | # Usage: pack_recipe 52 | # pre: already in the directory with a check 53 | pack_recipe() { 54 | NAME=`basename "$1"` 55 | recipe=`find . -name "*.scm" | head -n 1` 56 | if [ "no-$recipe" != "no-" ]; then 57 | zip -r $NAME.recipe * -x \*.ml \*.mli \*.plugin _build/* >/dev/null 58 | fi 59 | } 60 | 61 | build() { 62 | set -e 63 | OLD=`pwd` 64 | echo "Entering directory \`$1'" 65 | cd $1 66 | read_info $1 67 | mlfiles=`find . -name "*.ml" | head -n 1` 68 | 69 | if [ "no$mlfiles" != "no" ]; then 70 | if [ "$HAS_BUILD_TOOLS" = "TRUE" ]; then 71 | 72 | 73 | NAME=`echo "$PLUGIN_MAIN" | cut -d'.' -f1` 74 | DEPS=`echo "$PLUGIN_DEPS" | sed 's/ */,/g' ` 75 | 76 | if [ "has-no$DEPS" != "has-no" ]; then 77 | echo bapbuild -pkgs $DEPS $NAME.plugin 78 | bapbuild -pkgs $DEPS $NAME.plugin 79 | else 80 | bapbuild $NAME.plugin 81 | fi 82 | 83 | if [ "no-$PLUGIN_DESC" != "no-" ]; then 84 | bapbundle update -desc \"$PLUGIN_DESC\" $NAME.plugin 85 | fi 86 | else 87 | echo "SKIP TARGET $1: bapbuild/bapbundle not found" 88 | fi 89 | fi 90 | 91 | pack_recipe $1 92 | echo "Leaving directory \`$1'" 93 | cd $OLD 94 | } 95 | 96 | 97 | install() { 98 | OLD=`pwd` 99 | cd $1 100 | 101 | DST=$(bap config sysdatadir) 102 | plugin=`find . -name "*.plugin" | head -n 1` 103 | recipe=`find . -name "*.recipe" | head -n 1` 104 | 105 | if [ "no-$plugin" != "no-" ]; then 106 | bapbundle install $plugin 107 | fi 108 | if [ "no-$recipe" != "no-" ]; then 109 | cp *.recipe $DST 110 | fi 111 | cd $OLD 112 | } 113 | 114 | 115 | clean() { 116 | OLD=`pwd` 117 | cd $1 118 | rm -f *.recipe 119 | bapbuild -clean > /dev/null 120 | cd $OLD 121 | } 122 | 123 | 124 | process_cmd() { 125 | CMD=$1 126 | DST=$2 127 | case $CMD in 128 | build) 129 | build $DST 130 | ;; 131 | install) 132 | install $DST 133 | ;; 134 | clean) 135 | clean $DST 136 | ;; 137 | *) 138 | echo "Usage: $0 {build|install|clean} with an optional check name " 139 | exit 1 140 | esac 141 | 142 | } 143 | 144 | check() { 145 | path=`which $1` 146 | if [ "no$path" = "no" ]; then 147 | echo "can't find $1, exiting ... " 148 | exit 1 149 | fi 150 | } 151 | 152 | # usage: 153 | # run check 154 | run() { 155 | check zip 156 | check sed 157 | check bapbundle 158 | check bapbuild 159 | 160 | COMMAND=$1 161 | TARGET=$2 162 | check_build_tools 163 | 164 | if [ "all$TARGET" = "all" ]; then 165 | for d in `ls`; do 166 | if [ -d "$d" ] && [ "$d" != "tests" ]; then 167 | process_cmd $COMMAND $d 168 | fi 169 | done 170 | wait 171 | else 172 | process_cmd $COMMAND $TARGET 173 | fi 174 | } 175 | 176 | run "$@" 177 | -------------------------------------------------------------------------------- /defective-symbol/descr: -------------------------------------------------------------------------------- 1 | runs all the analysis that checks static properties of subroutines 2 | 3 | The next checks are run: 4 | - av-rule-3 - All functions shall have a cyclomatic complexity number of 50 or less 5 | - av-rule-189 - The goto statement shall not be used 6 | - jpl-rule-4 - There shall be no direct or indirect use of recursive function calls 7 | -------------------------------------------------------------------------------- /defective-symbol/recipe.scm: -------------------------------------------------------------------------------- 1 | (extend av-rule-3) 2 | (extend av-rule-189) 3 | (extend jpl-rule-4) 4 | 5 | (parameter verbosity 1 "the level of verbosity") 6 | 7 | (option find-symbol-verbose $verbosity) 8 | (option log-dir log) 9 | -------------------------------------------------------------------------------- /double-free/descr: -------------------------------------------------------------------------------- 1 | detects a double call to 'free' on the same memory address 2 | 3 | This check covers CWE-415 Double Free entry. 4 | 5 | Motivation 6 | ========== 7 | 8 | Calling 'free' twice on the same address can crash the program. 9 | Also, in some cases, it could cause two subsequent calls to 10 | 'malloc' to return the same pointer, which potentially can 11 | give an atacker a control over the data written into this memory. 12 | -------------------------------------------------------------------------------- /double-free/double-free.lisp: -------------------------------------------------------------------------------- 1 | (require memcheck) 2 | 3 | (defmethod call (name ptr) 4 | (when (and ptr (= name 'free) 5 | (not (= ptr *malloc-zero-sentinel*))) 6 | (memcheck-release 'alloc ptr))) 7 | 8 | (defmethod call-return (name len ptr) 9 | (when (and len ptr (= name 'malloc)) 10 | (memcheck-acquire 'alloc ptr len))) 11 | -------------------------------------------------------------------------------- /double-free/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter depth 32768 "a depth of analysis") 2 | (parameter visits 128 "maximum number of executions of the same block") 3 | (parameter entry-points all-subroutines "where to search") 4 | (parameter optimization 0 "optimization level") 5 | 6 | (option primus-lisp-load 7 | posix 8 | double-free) 9 | 10 | (option primus-lisp-add $prefix) 11 | 12 | (option primus-lisp-channel-redirect 13 | :$prefix/stdin 14 | :$prefix/stdout) 15 | 16 | (option report-progress) 17 | (option log-dir log) 18 | 19 | (option passes 20 | with-no-return 21 | run) 22 | 23 | (option run-entry-points ${entry-points}) 24 | 25 | (option primus-promiscuous-mode) 26 | (option primus-greedy-scheduler) 27 | (option primus-print-output incidents) 28 | (option primus-limit-max-length $depth) 29 | (option primus-limit-max-visited $visits) 30 | 31 | (option optimization-level $optimization) 32 | 33 | (option primus-print-obs 34 | exception 35 | pc-changed 36 | jumping 37 | call 38 | call-return 39 | machine-switch 40 | machine-fork 41 | lisp-message 42 | incident 43 | incident-location) 44 | -------------------------------------------------------------------------------- /double-free/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/double-free/stdin -------------------------------------------------------------------------------- /double-free/stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/double-free/stdout -------------------------------------------------------------------------------- /find-symbol/.merlin: -------------------------------------------------------------------------------- 1 | PKG bap 2 | PKG monads 3 | PKG ogre 4 | PKG bap-main 5 | PKG bap-llvm 6 | 7 | B _build/ 8 | S . 9 | REC -------------------------------------------------------------------------------- /find-symbol/find_symbol.ml: -------------------------------------------------------------------------------- 1 | open Core_kernel 2 | open Bap.Std 3 | open Bap_main 4 | open Monads.Std 5 | 6 | include Self() 7 | 8 | module Utils = Find_symbol_utils 9 | module Report = Find_symbol_report 10 | 11 | open Find_symbol_types 12 | 13 | module Symbols = struct 14 | include Ogre.Make(Monad.Ident) 15 | open Image.Scheme 16 | 17 | let collect_externals = 18 | collect Ogre.Query.(select (from external_reference)) >>= fun s -> 19 | Seq.fold s ~init:(Map.empty (module String)) 20 | ~f:(fun syms (addr,name) -> 21 | return @@ Map.set syms name {name; addr = None}) 22 | 23 | let collect_symbols = 24 | collect Ogre.Query.(select (from named_symbol)) >>= fun s -> 25 | Seq.fold s ~init:(Map.empty (module String)) 26 | ~f:(fun syms (addr,name) -> 27 | return @@ Map.set syms name 28 | {name; addr = Some (Addr.of_int64 addr)}) 29 | 30 | let symbols = 31 | collect_externals >>= fun exts -> 32 | collect_symbols >>= fun syms -> 33 | return @@ 34 | Map.merge exts syms ~f:(fun ~key:_ -> function 35 | | `Left x | `Right x -> Some x 36 | | `Both (x,_) -> Some x) 37 | 38 | let find doc = eval symbols doc 39 | end 40 | 41 | let empty_results = Map.empty (module Symbol) 42 | 43 | let add syms sym ?data check = 44 | Map.add_multi syms sym {data; check} 45 | 46 | let find_forbidden file requested = 47 | let symbols_of_file path = 48 | Or_error.( 49 | Image.create ~backend:"llvm" path >>= fun (im,_) -> 50 | Symbols.find (Image.spec im)) |> function 51 | | Ok xs -> xs 52 | | Error er -> 53 | error "Can't find symbols: %s\n" (Error.to_string_hum er); 54 | Map.empty (module String) in 55 | let symbols = symbols_of_file file in 56 | List.fold requested ~init:empty_results ~f:(fun forb sym -> 57 | match Map.find symbols sym with 58 | | None -> forb 59 | | Some sym -> add forb sym Forbidden_function) 60 | 61 | let find_recursive proj = 62 | let syms = Find_symbol_rec.find (Project.program proj) in 63 | List.fold syms ~init:empty_results ~f:(fun syms sym -> 64 | add syms sym Recursive_function) 65 | 66 | let find_complex threshold proj = match threshold with 67 | | None -> empty_results 68 | | Some threshold -> 69 | let symtab = Project.symbols proj in 70 | Symtab.to_sequence symtab |> 71 | Seq.fold ~init:empty_results ~f:(fun syms (name,entry,cfg) -> 72 | let c = Utils.complexity cfg entry in 73 | if c > threshold then 74 | add syms {name;addr=Some (Block.addr entry)} 75 | ~data:(Complexity c) Complex_function 76 | else syms) 77 | 78 | let find_non_structured proj = 79 | Project.symbols proj |> 80 | Symtab.to_sequence |> 81 | Seq.fold ~init:empty_results ~f:(fun syms (name,entry,cfg) -> 82 | match Utils.find_nonstructural_component cfg entry with 83 | | None -> syms 84 | | Some addr -> 85 | add syms {name;addr=Some (Block.addr entry)} 86 | ~data:(Non_structural_block addr) Non_structural_cfg) 87 | 88 | let with_project recursive non_structural complex level proj = 89 | let merge a b = 90 | Map.merge a b ~f:(fun ~key:_ -> function 91 | | `Left x | `Right x -> Some x 92 | | `Both (x,y) -> Some (x @ y)) in 93 | let (++) a f = merge a (f proj) in 94 | let checks = [ 95 | recursive, Recursive_function, find_recursive; 96 | Option.is_some complex, Complex_function, find_complex complex; 97 | non_structural, Non_structural_cfg, find_non_structured; 98 | ] in 99 | let checks = 100 | List.filter_map checks ~f:(fun (test,f,check) -> 101 | Option.some_if test (f, check)) in 102 | let requested = List.map checks ~f:fst in 103 | let checks = List.map checks ~f:snd in 104 | let results = List.fold checks ~init:empty_results ~f:(++) in 105 | Report.dump ~requested ~level results; 106 | Report.dump_incidents results 107 | 108 | let verbosity_level xs = 109 | let level = Option.value ~default:1 @@ 110 | List.max_elt xs ~compare:Int.compare in 111 | Report.level_of_int level 112 | 113 | let input = Extension.Command.argument 114 | ~doc:"The input file" Extension.Type.("FILE" %: string) 115 | 116 | let names = 117 | Extension.Command.parameters 118 | ~doc:"Look for symbols from the provided list" 119 | Extension.Type.("NAMES" %: list string) "names" 120 | 121 | let verbose = 122 | Extension.Command.parameters 123 | ~as_flag:1 124 | ~doc:"Dumps the results" 125 | Extension.Type.int 126 | "verbose" 127 | 128 | let recursive = 129 | Extension.Configuration.flag 130 | ~doc:"Find recursive (and mutually recursive) subroutines" 131 | "recursive" 132 | 133 | let non_structured = 134 | Extension.Configuration.flag 135 | ~doc:"Find symbols that are not well-structured" 136 | "non-structured" 137 | 138 | let complexity = 139 | Extension.Configuration.parameter 140 | ~doc:"Find symbols with cyclomatic complexity > threshold" 141 | Extension.Type.(some int) "complexity" 142 | 143 | let verbose' = 144 | Extension.Configuration.parameters 145 | ~as_flag:1 146 | ~doc:"Dumps the results" 147 | Extension.Type.int 148 | "verbose" 149 | 150 | let () = 151 | Extension.Command.(begin 152 | declare "find-symbol" ~requires:[] (args $input $names $verbose) 153 | end) @@ fun input requested verbose ctxt -> 154 | let level = verbosity_level verbose in 155 | let results = find_forbidden input @@ List.concat requested in 156 | Report.dump ~level ~print_addrs:false 157 | ~requested:[Forbidden_function] results; 158 | Report.dump_incidents results; 159 | Ok () 160 | 161 | let () = 162 | let open Extension.Syntax in 163 | Extension.declare 164 | @@ fun ctxt -> 165 | let level = verbosity_level (ctxt --> verbose') in 166 | let pass = with_project 167 | (ctxt --> recursive) 168 | (ctxt --> non_structured) 169 | (ctxt --> complexity) 170 | level in 171 | Ok (Project.register_pass' ~runonce:true pass) 172 | -------------------------------------------------------------------------------- /find-symbol/find_symbol_rec.ml: -------------------------------------------------------------------------------- 1 | open Core_kernel 2 | open Bap.Std 3 | open Regular.Std 4 | open Graphlib.Std 5 | 6 | open Find_symbol_types 7 | 8 | type signal = 9 | | Hi 10 | | Lo 11 | [@@deriving compare, sexp] 12 | 13 | let signal_equal s s' = compare_signal s s' = 0 14 | 15 | module G = Graphlib.Make(Tid)(Unit) 16 | 17 | let dsts_of_blk b = 18 | Seq.filter_map (Blk.elts b) ~f:(function 19 | | `Def _ | `Phi _ -> None 20 | | `Jmp j -> 21 | match Jmp.kind j with 22 | | Int _ | Ret _ | Goto (Indirect _) -> None 23 | | Goto (Direct t) -> Some (t, None) 24 | | Call c -> 25 | match Call.target c with 26 | | Direct t -> Some (t, Call.return c) 27 | | _ -> None) 28 | 29 | let string_of_signal s = Sexp.to_string (sexp_of_signal s) 30 | 31 | let to_seq = Term.to_sequence 32 | let subs = Term.to_sequence sub_t 33 | let blks = Term.to_sequence blk_t 34 | 35 | type program = { 36 | g : G.t; 37 | entries : Tid.Set.t; 38 | callers : Tid.Set.t; 39 | entry : tid; 40 | names : (string * addr) Tid.Map.t; 41 | } 42 | 43 | let of_subs subs = 44 | let program_entry = Tid.create () in 45 | let empty_prog = { 46 | g = G.Node.insert program_entry G.empty; 47 | entries = Set.empty (module Tid); 48 | callers = Set.empty (module Tid); 49 | entry = program_entry; 50 | names = Map.empty (module Tid); 51 | } in 52 | let connect g tid tid' = 53 | let e = G.Edge.create tid tid' () in 54 | G.Edge.insert e g in 55 | let connect_with_entry g tid = 56 | G.Edge.insert (G.Edge.create program_entry tid ()) g in 57 | Seq.fold subs ~init:empty_prog 58 | ~f:(fun p sub -> 59 | let entries = Set.add p.entries (Term.tid sub) in 60 | let names = match Term.get_attr sub address with 61 | | None -> p.names 62 | | Some addr -> 63 | Map.set p.names (Term.tid sub) (Sub.name sub, addr) in 64 | let blks = blks sub in 65 | match Seq.hd blks with 66 | | None -> { p with entries; names } 67 | | Some fst -> 68 | let fst = Term.tid fst in 69 | let sub = Term.tid sub in 70 | let g = connect_with_entry p.g sub in 71 | let g,callers = 72 | Seq.fold blks ~init:(g,p.callers) 73 | ~f:(fun acc blk -> 74 | let src = 75 | if Tid.(Term.tid blk = fst) then sub 76 | else Term.tid blk in 77 | Seq.fold (dsts_of_blk blk) ~init:acc 78 | ~f:(fun (g,callers) (dst,ret) -> 79 | match ret with 80 | | None | Some (Indirect _) -> connect g src dst, callers 81 | | Some Direct dst' -> 82 | let g = connect g src dst' in 83 | let hi_node = Tid.create () in 84 | let g = connect g src hi_node in 85 | connect g hi_node dst, 86 | Set.add callers hi_node)) in 87 | { p with entries; names; callers; g }) 88 | 89 | 90 | let meet x y = match x,y with 91 | | Hi,_ | _,Hi -> Hi 92 | | x,_ -> x 93 | 94 | let raise_signal data = 95 | Map.map data ~f:(fun signal -> 96 | match signal with 97 | | Lo -> Hi 98 | | x -> x) 99 | 100 | let merge data data'= 101 | Map.merge data data' ~f:(fun ~key:_ -> function 102 | | `Left x | `Right x -> Some x 103 | | `Both (x,y) -> Some (meet x y)) 104 | 105 | let transfer entries callers blk signals = 106 | let signals = 107 | if Set.mem entries blk then 108 | Map.update signals blk 109 | ~f:(function 110 | | Some Hi -> Hi 111 | | _ -> Lo) 112 | else signals in 113 | if Set.mem callers blk then raise_signal signals 114 | else signals 115 | 116 | let initial_solution = 117 | Solution.create (Map.empty (module Tid)) (Map.empty (module Tid)) 118 | 119 | let calls_of_path entries path = 120 | let rec collect acc = function 121 | | [] -> acc 122 | | e :: edges when Set.mem entries (G.Edge.src e) -> 123 | collect (G.Edge.src e :: acc) edges 124 | | _ :: edges -> collect acc edges in 125 | collect [] (Seq.to_list (Path.edges path)) 126 | 127 | let find_gen ~init ~f prog = 128 | let subs = subs prog in 129 | let p = of_subs subs in 130 | let sol = Graphlib.fixpoint (module G) p.g 131 | ~start:p.entry 132 | ~equal:(Tid.Map.equal signal_equal) 133 | ~init:initial_solution 134 | ~merge 135 | ~f:(fun blk data -> transfer p.entries p.callers blk data) in 136 | Set.fold p.entries ~init ~f:(fun acc blk -> 137 | let x = Solution.get sol blk in 138 | match Map.find x blk with 139 | | None | Some Lo -> acc 140 | | Some Hi -> f acc p blk) 141 | 142 | let find prog = 143 | find_gen prog ~init:[] ~f:(fun acc p blk -> 144 | match Map.find p.names blk with 145 | | Some (name,addr) -> {name;addr=Some addr} :: acc 146 | | None -> acc) 147 | 148 | (** [find' prog] returns a list of tids of recursive subroutines 149 | and a recursive path for each one. *) 150 | let find' prog = 151 | find_gen prog ~init:[] ~f:(fun acc p blk -> 152 | let inputs = G.Node.inputs blk p.g in 153 | let path = 154 | Seq.find_map inputs 155 | ~f:(fun inp -> 156 | if Tid.(p.entry = G.Edge.src inp) then None 157 | else 158 | Graphlib.shortest_path (module G) 159 | p.g ~rev:true (G.Edge.src inp) blk) in 160 | match path with 161 | | None -> acc 162 | | Some path -> (blk, calls_of_path p.entries path) :: acc) 163 | -------------------------------------------------------------------------------- /find-symbol/find_symbol_rec.mli: -------------------------------------------------------------------------------- 1 | open Bap.Std 2 | open Find_symbol_types 3 | 4 | (** [find prog] returns a list of recursive subroutines along with an address *) 5 | val find : program term -> symbol list 6 | -------------------------------------------------------------------------------- /find-symbol/find_symbol_report.ml: -------------------------------------------------------------------------------- 1 | open Core_kernel 2 | open Bap.Std 3 | open Find_symbol_types 4 | open Format 5 | 6 | module Incidents = struct 7 | 8 | let output_sexp ch s = 9 | let fmt = Format.formatter_of_out_channel ch in 10 | Format.fprintf fmt "%a\n%!" Sexp.pp_hum s 11 | 12 | let sexp_of_addr addr = 13 | Sexp.Atom 14 | (sprintf "0x%s" @@ Addr.string_of_value ~hex:true addr) 15 | 16 | let sexp_of_check check = 17 | Sexp.Atom 18 | (Sexp.to_string (sexp_of_check check) |> 19 | String.lowercase |> 20 | String.map ~f:(fun c -> if Char.(c = '_') then '-' else c)) 21 | 22 | let sexp_of_incident check sym addr = 23 | let open Sexp in 24 | let data = match addr with 25 | | None -> [sexp_of_check check; Atom sym] 26 | | Some addr -> 27 | [ sexp_of_check check; Atom sym; sexp_of_addr addr] in 28 | List [Atom "incident-static"; List data] 29 | 30 | 31 | let output ch check name addr = 32 | output_sexp ch (sexp_of_incident check name addr); 33 | Out_channel.flush ch 34 | 35 | let dump results = 36 | Out_channel.with_file "incidents" ~f:(fun ch -> 37 | Map.iteri results ~f:(fun ~key:{name;addr} ~data:results -> 38 | List.iter results ~f:(fun {check} -> 39 | output ch check name addr))) 40 | end 41 | 42 | module Ansi = struct 43 | let pp_bold ppf = fprintf ppf "\027[1m" 44 | let pp_norm ppf = fprintf ppf "\027[0m" 45 | end 46 | 47 | type level = 48 | | Brief 49 | | Total 50 | 51 | let level_of_int x = 52 | if x > 1 then Total 53 | else Brief 54 | 55 | let string_of_result r = 56 | let string_of_data = function 57 | | None -> "" 58 | | Some (Complexity x) -> sprintf "%d" x 59 | | Some (Non_structural_block a) -> sprintf "at %a" Addr.pps a in 60 | match r.check with 61 | | Complex_function -> sprintf "Complexity %s" (string_of_data r.data) 62 | | Forbidden_function -> sprintf "Forbidden" 63 | | Recursive_function -> sprintf "Recursive-call" 64 | | Non_structural_cfg -> sprintf "Non-structural cfg %s" (string_of_data r.data) 65 | 66 | let string_of_check = function 67 | | x -> 68 | Sexp.to_string (sexp_of_check x) |> 69 | String.lowercase |> 70 | String.tr ~target:'_' ~replacement:' ' 71 | 72 | let print_table fmt ~print_addrs rs = 73 | let print_sym name addr results = 74 | fprintf fmt "%-25s " name; 75 | if print_addrs then 76 | begin 77 | match addr with 78 | | Some addr -> fprintf fmt "%a " Addr.pp addr 79 | | None -> () 80 | end; 81 | fprintf fmt "["; 82 | match results with 83 | | [] -> fprintf fmt "]\n" 84 | | [r] -> fprintf fmt "%s]\n" @@ string_of_result r 85 | | rs -> 86 | List.fold rs ~init:[] ~f:(fun ac r -> string_of_result r :: ac) |> 87 | List.rev |> 88 | String.concat ~sep:"; " |> 89 | fprintf fmt "%s]\n" in 90 | fprintf fmt "\n%t%-25s " Ansi.pp_bold "Symbol found"; 91 | if print_addrs then 92 | fprintf fmt "%-8s " "Address"; 93 | fprintf fmt "Criteria\n%t" Ansi.pp_norm; 94 | Map.iteri rs ~f:(fun ~key:{name;addr} ~data:results -> 95 | print_sym name addr results) 96 | 97 | let brief_report fmt requested rs = 98 | let output status check = 99 | fprintf fmt "%-25s %s\n" (string_of_check check) status in 100 | let fails = 101 | Map.fold rs ~init:(Set.empty (module Check)) 102 | ~f:(fun ~key:_ ~data:results checks -> 103 | List.fold results ~init:checks ~f:(fun rs {check} -> 104 | Set.add rs check)) in 105 | let requested = Set.of_list (module Check) requested in 106 | let oks = Set.diff requested fails in 107 | fprintf fmt "%t%-25s %s\n%t" Ansi.pp_bold "Check" "Status" Ansi.pp_norm; 108 | Set.iter fails ~f:(output "FAIL"); 109 | Set.iter oks ~f:(output "OK") 110 | 111 | let dump_results ?(print_addrs=true) ~level requested rs = 112 | let open Format in 113 | brief_report std_formatter requested rs; 114 | match level with 115 | | Total -> 116 | if not (Map.is_empty rs) then 117 | print_table std_formatter ~print_addrs rs 118 | | Brief -> () 119 | 120 | let dump ?(print_addrs=true) ?(requested=[]) ~level results = 121 | dump_results ~print_addrs ~level requested results 122 | 123 | let dump_incidents = Incidents.dump 124 | -------------------------------------------------------------------------------- /find-symbol/find_symbol_report.mli: -------------------------------------------------------------------------------- 1 | open Find_symbol_types 2 | 3 | type level 4 | 5 | (** [level_of_int x] returns a level of verbosity 6 | for dump function. There are two levels: 7 | level 1: outputs results in a brief format (for x <= 1) 8 | level 2: also outputs results in a table format (for all other x) *) 9 | val level_of_int : int -> level 10 | 11 | (** [dump ~print_addrs ~requested ~level results] 12 | dumps all the results into stdout. 13 | 14 | @print_addrs is true by default *) 15 | val dump : 16 | ?print_addrs:bool -> 17 | ?requested : check list -> 18 | level:level -> 19 | results -> unit 20 | 21 | (** [dump_incidents results] dumps results in "incidents.static" file *) 22 | val dump_incidents : results -> unit 23 | -------------------------------------------------------------------------------- /find-symbol/find_symbol_types.ml: -------------------------------------------------------------------------------- 1 | open Core_kernel 2 | open Bap.Std 3 | 4 | type symbol = { 5 | name : string; 6 | addr : Addr.t option; 7 | } [@@deriving compare,bin_io,hash,sexp] 8 | 9 | type check = 10 | | Forbidden_function 11 | | Recursive_function 12 | | Non_structural_cfg 13 | | Complex_function 14 | [@@deriving bin_io,compare,hash,sexp] 15 | 16 | type symbol_data = 17 | | Complexity of int 18 | | Non_structural_block of addr 19 | [@@deriving sexp] 20 | 21 | type result = { 22 | data : symbol_data option; 23 | check : check; 24 | } 25 | 26 | module Symbol = struct 27 | type t = symbol [@@deriving bin_io,compare,hash,sexp] 28 | module T = struct 29 | type nonrec t = t [@@deriving bin_io,compare,hash,sexp] 30 | let module_name = "Find_symbol.Types.Symbol" 31 | let to_string t = Sexp.to_string (sexp_of_t t) 32 | let of_string s = t_of_sexp (Sexp.of_string s) 33 | end 34 | include Identifiable.Make(T) 35 | end 36 | 37 | module Check = struct 38 | type t = check [@@deriving bin_io,compare,hash,sexp] 39 | module T = struct 40 | type nonrec t = t [@@deriving bin_io,compare,hash,sexp] 41 | let module_name = "Find_symbol.Types.Check" 42 | let to_string t = Sexp.to_string (sexp_of_t t) 43 | let of_string s = t_of_sexp (Sexp.of_string s) 44 | end 45 | include Identifiable.Make(T) 46 | end 47 | 48 | type results = result list Symbol.Map.t 49 | -------------------------------------------------------------------------------- /find-symbol/find_symbol_utils.ml: -------------------------------------------------------------------------------- 1 | open Core_kernel 2 | open Graphlib.Std 3 | open Bap.Std 4 | 5 | module Cfg = Graphs.Cfg 6 | module Callgraph = Graphs.Callgraph 7 | 8 | let connect_graph g entry = 9 | Cfg.nodes g |> Seq.fold ~init:g ~f:(fun g n -> 10 | if Cfg.Node.degree ~dir:`Out n g = 0 11 | then Cfg.Edge.insert (Cfg.Edge.create n entry `Jump) g 12 | else g) 13 | 14 | let complexity graph entry = 15 | let graph = connect_graph graph entry in 16 | let edges = Seq.length (Cfg.edges graph) in 17 | let nodes = Seq.length (Cfg.nodes graph) in 18 | let parts = Graphlib.strong_components (module Cfg) graph |> 19 | Partition.number_of_groups in 20 | edges - nodes + parts 21 | 22 | let scc_entries cfg group = 23 | let nodes = Group.enum group |> 24 | Seq.to_list |> 25 | Set.of_list (module Cfg.Node) in 26 | Set.fold nodes ~init:0 ~f:(fun entries node -> 27 | let inputs = Cfg.Node.inputs node cfg in 28 | let srcs = Seq.map inputs ~f:Cfg.Edge.src in 29 | let srcs = Seq.filter srcs ~f:(fun s -> not (Set.mem nodes s)) in 30 | entries + Seq.length srcs) 31 | 32 | (* A flowgraph is reducible when it does NOT have 33 | a strongly connected subgraph with two (or more) entries. *) 34 | let is_reducible cfg start = 35 | let cfg = connect_graph cfg start in 36 | let xs = Graphlib.strong_components (module Cfg) cfg in 37 | let groups = Partition.groups xs in 38 | not @@ Seq.exists groups ~f:(fun g -> scc_entries cfg g >= 2) 39 | 40 | 41 | let find_nonstructural_component cfg start = 42 | let cfg = connect_graph cfg start in 43 | let xs = Graphlib.strong_components (module Cfg) cfg in 44 | let groups = Partition.groups xs in 45 | Option.( 46 | Seq.find groups ~f:(fun g -> scc_entries cfg g >= 2) >>= fun g -> 47 | Some (Block.addr (Group.top g))) 48 | -------------------------------------------------------------------------------- /find-symbol/find_symbol_utils.mli: -------------------------------------------------------------------------------- 1 | open Core_kernel 2 | open Graphlib.Std 3 | open Bap.Std 4 | open Graphs 5 | 6 | 7 | (** [complexity cfg entry] *) 8 | val complexity : Cfg.t -> Block.t -> int 9 | 10 | (** [is_reducible cfg entry] *) 11 | val is_reducible : Cfg.t -> Block.t -> bool 12 | 13 | (** [find_nonstructural_component cfg entry ] *) 14 | val find_nonstructural_component : Cfg.t -> Block.t -> addr option 15 | -------------------------------------------------------------------------------- /find-symbol/info: -------------------------------------------------------------------------------- 1 | main: find_symbol.ml 2 | depends: bap bap-main monads ogre -------------------------------------------------------------------------------- /forbidden-symbol/descr: -------------------------------------------------------------------------------- 1 | runs all the analysis that check the program for a presence of certain functions 2 | 3 | The next checks are run: 4 | - av-rule-17 - The error indicator `errno` shall not be used 5 | - av-rule-19 - `` and the `setlocale` function shall not be used. 6 | - av-rule-20 - The `setjmp` macro and the `longjmp` function shall not be used. 7 | - av-rule-21 - The signal handling facilities of `` shall not be used. 8 | - av-rule-22 - The input/output library `` shall not be used. 9 | - av-rule-23 - The library functions `atof`, `atoi` and `atol` from library `` shall not be used. 10 | - av-rule-24 - The library functions `abort`, `exit`, `getenv` and `system` from library `` shall not be used 11 | - av-rule-25 - The time handling functions of library `` shall not be used. 12 | -------------------------------------------------------------------------------- /forbidden-symbol/recipe.scm: -------------------------------------------------------------------------------- 1 | (command find-symbol) 2 | (extend av-rule-17) 3 | (extend av-rule-19) 4 | (extend av-rule-20) 5 | (extend av-rule-21) 6 | (extend av-rule-22) 7 | (extend av-rule-23) 8 | (extend av-rule-24) 9 | (extend av-rule-25) 10 | 11 | (parameter verbosity 1 "the level of verbosity") 12 | 13 | (option verbose $verbosity) 14 | 15 | (option log-dir log) 16 | -------------------------------------------------------------------------------- /heap-overflow/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter depth 32768 "a depth of analysis") 2 | (parameter entry-points all-subroutines "where to search") 3 | (parameter optimization 0 "optimization level") 4 | 5 | (option primus-lisp-load 6 | posix 7 | memcheck-malloc) 8 | 9 | (option primus-lisp-add $prefix) 10 | 11 | (option passes 12 | with-no-return 13 | run) 14 | 15 | (option primus-lisp-channel-redirect 16 | :$prefix/stdin 17 | :$prefix/stdout) 18 | 19 | (option report-progress) 20 | (option log-dir log) 21 | 22 | (option run-entry-points ${entry-points}) 23 | (option constant-tracker-enable) 24 | 25 | (option primus-promiscuous-mode) 26 | (option primus-greedy-scheduler) 27 | (option primus-print-output incidents) 28 | (option primus-limit-max-length $depth) 29 | 30 | (option primus-print-obs 31 | exception 32 | pc-changed 33 | jumping 34 | call 35 | call-return 36 | machine-switch 37 | machine-fork 38 | lisp-message 39 | incident 40 | incident-location) 41 | 42 | (option optimization-level $optimization) 43 | -------------------------------------------------------------------------------- /heap-overflow/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/heap-overflow/stdin -------------------------------------------------------------------------------- /heap-overflow/stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/heap-overflow/stdout -------------------------------------------------------------------------------- /jpl-rule-11/descr: -------------------------------------------------------------------------------- 1 | detects symbols with non-structural cfg 2 | 3 | This rule means that a control flow graph of each subroutine 4 | should be reducible. Or, as vice versa, there should not be 5 | any subroutine with non-reducible control flow graph. 6 | 7 | The CFG is considered as a reducible one if doesn't contain 8 | strongly connected components with two and more entries. 9 | -------------------------------------------------------------------------------- /jpl-rule-11/recipe.scm: -------------------------------------------------------------------------------- 1 | (option pass find-symbol) 2 | (option find-symbol-non-structured) 3 | -------------------------------------------------------------------------------- /jpl-rule-14/.merlin: -------------------------------------------------------------------------------- 1 | PKG core_kernel 2 | PKG bap 3 | PKG bap-primus 4 | PKG bap-taint 5 | PKG bap-x86-cpu 6 | 7 | S . 8 | B _build/ -------------------------------------------------------------------------------- /jpl-rule-14/descr: -------------------------------------------------------------------------------- 1 | detects unused values returned by functions 2 | 3 | The algorithm uses function's api information to determine it's output argument. 4 | Value assigned to the output argument becomes a source of a taint. 5 | And any read of the tainted value sanitizes this taint, meaning that 6 | an output argument is actually used. 7 | Otherwise, if the taint survives and is finalized by garbage collector, 8 | then a proof of unused result is obtainted. 9 | 10 | All checks are reported: 11 | - to stdout in the user friendly format 12 | - via the incident report system and are stored 13 | in the working directory in the `incidents' file. 14 | The file could be loaded in IDA Pro for further analysis. 15 | -------------------------------------------------------------------------------- /jpl-rule-14/info: -------------------------------------------------------------------------------- 1 | main : unused_return_value.ml 2 | depends: bap bap-main bap-primus bap-x86-cpu 3 | -------------------------------------------------------------------------------- /jpl-rule-14/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter depth 32768 "a depth of analysis") 2 | (parameter entry-points all-subroutines "where to search") 3 | (parameter verbosity 1 "verbosity level") 4 | 5 | (option primus-lisp-load 6 | unused-return 7 | posix) 8 | 9 | (option passes 10 | callsites 11 | run) 12 | 13 | (option unused-return-value-enable) 14 | (option unused-return-value-verbose $verbosity) 15 | 16 | (option primus-promiscuous-mode) 17 | (option primus-greedy-scheduler) 18 | (option primus-limit-max-length $depth) 19 | (option run-entry-points ${entry-points}) 20 | 21 | (option primus-lisp-add $prefix) 22 | (option primus-print-output incidents) 23 | (option primus-lisp-channel-redirect 24 | :$prefix/stdin 25 | :$prefix/stdout 26 | :$prefix/stderr) 27 | 28 | (option primus-print-observations 29 | exception 30 | pc-changed 31 | jumping 32 | call 33 | call-return 34 | machine-switch 35 | machine-fork 36 | lisp-message 37 | incident 38 | incident-location) 39 | 40 | (option log-dir log) 41 | -------------------------------------------------------------------------------- /jpl-rule-14/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/jpl-rule-14/stderr -------------------------------------------------------------------------------- /jpl-rule-14/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/jpl-rule-14/stdin -------------------------------------------------------------------------------- /jpl-rule-14/stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/jpl-rule-14/stdout -------------------------------------------------------------------------------- /jpl-rule-14/subroutines_info.ml: -------------------------------------------------------------------------------- 1 | open Core_kernel 2 | open Bap.Std 3 | open Bap_primus.Std 4 | open Monads.Std 5 | 6 | module Vid = Primus.Value.Id 7 | 8 | 9 | let arguments = 10 | Primus.Machine.State.declare 11 | ~name:"subroutines-arguments" 12 | ~uuid:"06f656ad-e922-4fa5-bc65-a3203b6819a2" 13 | (fun _ -> Map.empty (module String)) 14 | 15 | let return_values = Primus.Machine.State.declare 16 | ~name:"return-values" 17 | ~uuid:"3ab8d8ee-1304-46d3-9860-0960aaf2ac42" 18 | (fun _ -> Map.empty (module Primus.Value.Id)) 19 | 20 | 21 | type callsite = { 22 | calls : addr String.Map.t; 23 | pc : addr option; 24 | } 25 | 26 | let callsite = Primus.Machine.State.declare 27 | ~name:"unused-results-callsite" 28 | ~uuid:"1715922a-4e6d-4960-bbd4-a6fb8e239ddb" 29 | (fun _ -> { calls = Map.empty (module String); pc = None}) 30 | 31 | module Known_subs(Machine : Primus.Machine.S) = struct 32 | module Value = Primus.Value.Make(Machine) 33 | open Machine.Syntax 34 | 35 | let init () = 36 | Machine.get () >>= fun proj -> 37 | let subs = Term.to_sequence sub_t (Project.program proj) in 38 | let m = Seq.fold subs 39 | ~init:(Map.empty (module String)) 40 | ~f:(fun m sub -> 41 | match Term.to_sequence arg_t sub |> Seq.to_list with 42 | | [] -> m 43 | | args -> 44 | Map.set m (Sub.name sub) args) in 45 | Machine.Global.put arguments m 46 | end 47 | 48 | module Return_values(Machine : Primus.Machine.S) = struct 49 | module Env = Primus.Env.Make(Machine) 50 | module Value = Primus.Value.Make(Machine) 51 | 52 | open Machine.Syntax 53 | 54 | let on_call_return (name, args) = 55 | Machine.Global.get arguments >>= fun arguments -> 56 | if not (Map.mem arguments name) 57 | then Machine.return () 58 | else 59 | match List.last args with 60 | | None -> Machine.return () 61 | | Some value -> 62 | Machine.Local.update return_values ~f:(fun vals -> 63 | Map.set vals (Primus.Value.id value) name) 64 | 65 | let init() = 66 | Primus.Linker.Trace.return >>> on_call_return 67 | 68 | end 69 | 70 | module Has_known_api(Machine : Primus.Machine.S) = struct 71 | module Value = Primus.Value.Make(Machine) 72 | module Linker = Primus.Linker.Make(Machine) 73 | open Machine.Syntax 74 | 75 | [@@@warning "-P"] 76 | let run [addr] = 77 | let addr = `addr (Value.to_word addr) in 78 | Linker.resolve_symbol addr >>= function 79 | | None -> Value.b0 80 | | Some name -> 81 | Machine.Global.get arguments >>= fun subs -> 82 | Value.of_bool (Map.mem subs name) 83 | 84 | end 85 | 86 | 87 | module Callsite (Machine : Primus.Machine.S) = struct 88 | module Value = Primus.Value.Make(Machine) 89 | module Linker = Primus.Linker.Make(Machine) 90 | module Interp = Primus.Interpreter.Make(Machine) 91 | 92 | open Machine.Syntax 93 | 94 | let on_call (name,_) = 95 | Machine.Local.update callsite ~f:(fun s -> 96 | match s.pc with 97 | | None -> s 98 | | Some pc -> 99 | {calls = Map.set s.calls name pc; pc = None}) 100 | 101 | let on_jump j = 102 | match Jmp.kind j with 103 | | Goto _ | Int _ | Ret _ -> Machine.return () 104 | | Call c -> 105 | Interp.pc >>= fun pc -> 106 | Machine.Local.update callsite 107 | ~f:(fun s -> {s with pc = Some pc}) 108 | 109 | let init() = 110 | Machine.sequence [ 111 | Primus.Interpreter.enter_jmp >>> on_jump; 112 | Primus.Linker.Trace.call >>> on_call; 113 | ] 114 | 115 | end 116 | 117 | module Callsite_addr(Machine : Primus.Machine.S) = struct 118 | module Value = Primus.Value.Make(Machine) 119 | module Eval = Primus.Interpreter.Make(Machine) 120 | open Machine.Syntax 121 | 122 | [@@@warning "-P"] 123 | let run [sub] = 124 | Value.Symbol.of_value sub >>= fun name -> 125 | Machine.Local.get callsite >>= fun s -> 126 | match Map.find s.calls name with 127 | | Some addr -> Value.of_word addr 128 | | None -> Value.b0 129 | end 130 | 131 | 132 | module Find_by_return_value(Machine : Primus.Machine.S) = struct 133 | module Value = Primus.Value.Make(Machine) 134 | open Machine.Syntax 135 | 136 | [@@@warning "-P"] 137 | let run [v] = 138 | Machine.Local.get return_values >>= fun rets -> 139 | match Map.find rets (Primus.Value.id v) with 140 | | None -> Value.b0 141 | | Some name -> Value.Symbol.to_value name 142 | 143 | end 144 | 145 | 146 | let init () = 147 | Primus.Machine.add_component (module Known_subs); 148 | Primus.Machine.add_component (module Return_values); 149 | Primus.Machine.add_component (module Callsite); 150 | [@@warning "-D"] 151 | -------------------------------------------------------------------------------- /jpl-rule-14/unused-return.lisp: -------------------------------------------------------------------------------- 1 | 2 | (defmethod read (var val) 3 | (when (need-to-check val) 4 | (mark-used val) 5 | (dict-add 'addrs (get-current-program-counter) val))) 6 | 7 | (defmethod stored (addr byte) 8 | (let ((pc (get-current-program-counter))) 9 | (when (dict-has 'addrs pc) 10 | (let ((value (dict-get 'addrs pc))) 11 | (mark-unused value) 12 | (dict-add 'values addr value))))) 13 | 14 | (defmethod loaded (addr val) 15 | (when (dict-has 'values addr) 16 | (let ((value (dict-get 'values addr))) 17 | (mark-used value)))) 18 | 19 | (defmethod written (var val) 20 | (let ((name (sub-of-return-value val))) 21 | (when name 22 | (let ((addr (callsite-addr name)) 23 | (loc (get-location addr))) 24 | (when (and addr loc) 25 | (check-if-used val name addr)))))) 26 | 27 | (defmethod jumping (_ addr) 28 | (when (is-known-symbol addr) 29 | (save-location (get-current-program-counter) (incident-location)))) 30 | 31 | (defmethod notify-unused-return (addr) 32 | (incident-report 'unused-return-value (get-location addr))) 33 | -------------------------------------------------------------------------------- /jpl-rule-14/unused_return_value.ml: -------------------------------------------------------------------------------- 1 | open Core_kernel 2 | open Bap.Std 3 | open Bap_primus.Std 4 | 5 | module Subs = Subroutines_info 6 | 7 | let check_name = "unused return value" 8 | 9 | type verbose = Brief | Detail 10 | 11 | type status = Used | Unused 12 | 13 | type func = { 14 | name : string; 15 | status : status; 16 | callsite : addr; 17 | } 18 | 19 | type tracker = { 20 | locations : Primus.value Primus.Value.Map.t; 21 | functions : func Primus.Value.Id.Map.t; 22 | verbose : verbose; 23 | } 24 | 25 | let tracker = Primus.Machine.State.declare 26 | ~name:"unused-return-tracker" 27 | ~uuid:"16DF068F-14F2-44FF-B5E7-B0B5194073BE" 28 | (fun _ -> { 29 | locations = Map.empty (module Primus.Value); 30 | functions = Map.empty (module Primus.Value.Id); 31 | verbose = Brief 32 | }) 33 | 34 | let notify_unused, unused_return_value = 35 | Primus.Observation.provide 36 | ~inspect:Primus.sexp_of_value "notify-unused-return" 37 | 38 | let verbose_of_int = function 39 | | 1 -> Brief 40 | | _ -> Detail 41 | 42 | let pp_bold ppf = Format.fprintf ppf "\027[1m" 43 | let pp_norm ppf = Format.fprintf ppf "\027[0m" 44 | let print_ok () = Format.printf "%s OK\n" check_name 45 | let print_fail () = Format.printf "%s FAIL\n" check_name 46 | 47 | let print_header () = 48 | Format.printf "\n%t%-10s %s\n%t" pp_bold "Function" "Called at" pp_norm 49 | 50 | let print_incident name addr = 51 | Format.printf "%-10s %s\n%!" name (sprintf "%a" Addr.pps addr) 52 | 53 | module Notify 54 | (S : sig val verbose : verbose end) 55 | (Machine : Primus.Machine.S) = struct 56 | 57 | module Value = Primus.Value.Make(Machine) 58 | open Machine.Syntax 59 | 60 | let has_fails func = 61 | Map.to_sequence func |> 62 | Seq.exists ~f:(fun (_,{status}) -> Poly.(status = Unused)) 63 | 64 | let print_result verbose funcs = 65 | if has_fails funcs then print_fail () 66 | else print_ok (); 67 | match verbose with 68 | | Brief -> () 69 | | Detail -> print_header () 70 | 71 | let on_last_stop _ = 72 | Machine.Global.get tracker >>= fun {verbose; functions;} -> 73 | print_result verbose functions; 74 | Map.to_alist functions |> 75 | Machine.List.fold ~init:(Set.empty (module Addr)) 76 | ~f:(fun reported (_,{name;callsite=addr;status}) -> 77 | match status with 78 | | Unused when not (Set.mem reported addr) -> 79 | if Poly.(verbose = Detail) then 80 | print_incident name addr; 81 | Value.of_word addr >>= fun addr' -> 82 | Machine.Observation.make unused_return_value addr' >>= 83 | fun () -> 84 | Machine.return (Set.add reported addr) 85 | | _ -> Machine.return reported) >>= fun _ -> 86 | Machine.return () 87 | 88 | let on_stop () = 89 | Machine.forks () >>= fun forks -> 90 | if Seq.length forks = 1 then 91 | on_last_stop () 92 | else Machine.return () 93 | 94 | let init () = 95 | Machine.Global.update tracker ~f: 96 | (fun s -> { s with verbose = S.verbose }) >>= fun () -> 97 | Primus.System.fini >>> on_stop 98 | 99 | end 100 | 101 | module MaybeUnused(Machine : Primus.Machine.S) = struct 102 | module Value = Primus.Value.Make(Machine) 103 | open Machine.Syntax 104 | 105 | [@@@warning "-P"] 106 | let run [value; name; addr] = 107 | Value.Symbol.of_value name >>= fun name -> 108 | Machine.Global.update tracker ~f:(fun t -> 109 | { t with functions = 110 | Map.set t.functions 111 | (Value.id value) 112 | {name; 113 | callsite = Value.to_word addr; 114 | status = Unused } }) >>= fun () -> 115 | Value.b1 116 | end 117 | 118 | module Status (Machine : Primus.Machine.S) = struct 119 | module Value = Primus.Value.Make(Machine) 120 | open Machine.Syntax 121 | 122 | let update value status = 123 | Machine.Global.update tracker ~f:(fun t -> 124 | { t with functions = 125 | Map.change t.functions (Value.id value) 126 | ~f:(function 127 | | None -> None 128 | | Some x -> Some {x with status}) }) >>= 129 | fun () -> Value.b1 130 | 131 | end 132 | 133 | module MarkUsed(Machine : Primus.Machine.S) = struct 134 | module Status = Status(Machine) 135 | open Machine.Syntax 136 | 137 | [@@@warning "-P"] 138 | let run [value] = Status.update value Used 139 | end 140 | 141 | 142 | module MarkUnused(Machine : Primus.Machine.S) = struct 143 | module Status = Status(Machine) 144 | open Machine.Syntax 145 | 146 | [@@@warning "-P"] 147 | let run [value] = Status.update value Unused 148 | end 149 | 150 | module Marked(Machine : Primus.Machine.S) = struct 151 | module Value = Primus.Value.Make(Machine) 152 | open Machine.Syntax 153 | 154 | [@@@warning "-P"] 155 | let run [value] = 156 | Machine.Global.get tracker >>= fun {functions} -> 157 | Value.of_bool @@ Map.mem functions (Value.id value) 158 | 159 | end 160 | 161 | module SaveLocation(Machine : Primus.Machine.S) = struct 162 | module Value = Primus.Value.Make(Machine) 163 | open Machine.Syntax 164 | 165 | [@@@warning "-P"] 166 | let run [addr; loc] = 167 | Machine.Global.update tracker ~f:(fun t -> 168 | {t with locations = 169 | Map.set t.locations addr loc}) >>= fun () -> 170 | Value.b1 171 | end 172 | 173 | module GetLocation(Machine : Primus.Machine.S) = struct 174 | module Value = Primus.Value.Make(Machine) 175 | open Machine.Syntax 176 | 177 | [@@@warning "-P"] 178 | let run [addr;] = 179 | Machine.Global.get tracker >>= fun t -> 180 | match Map.find t.locations addr with 181 | | None -> Value.b0 182 | | Some loc -> Machine.return loc 183 | end 184 | 185 | module Interface(Machine : Primus.Machine.S) = struct 186 | module Lisp = Primus.Lisp.Make(Machine) 187 | open Primus.Lisp.Type.Spec 188 | 189 | let init () = 190 | Machine.sequence [ 191 | Lisp.define "check-if-used" (module MaybeUnused) 192 | ~types:(tuple [a;b;c] @-> b) 193 | ~docs:{|(check-if-used VAL SUB ADDR) 194 | marks for checking 195 | the return value VAL of SUB called at ADDR |}; 196 | 197 | Lisp.define "need-to-check" (module Marked) 198 | ~types:(tuple [a] @-> bool) 199 | ~docs:{|(need-to-check V) return true if the value V 200 | previously was marked for checking |}; 201 | 202 | Lisp.define "is-known-symbol" (module Subs.Has_known_api) 203 | ~types:(tuple [a] @-> b) 204 | ~docs: 205 | {|(is-known-symbol ADDR) returns true if there is a 206 | subroutine at ADDR with a known API. |}; 207 | 208 | Lisp.define "mark-used" (module MarkUsed) 209 | ~types:(tuple [a] @-> b) 210 | ~docs:"(mark-used Value) mark a value of as the used one"; 211 | 212 | Lisp.define "mark-unused" (module MarkUnused) 213 | ~types:(tuple [a] @-> b) 214 | ~docs:"(mark-unused V) mark the value V as unused one"; 215 | 216 | Lisp.define "callsite-addr" (module Subs.Callsite_addr) 217 | ~types:(tuple [a] @-> b) 218 | ~docs: 219 | ({|(callsite-addr SUB) returns the address of the 220 | callsite of the previous call to the subroutine SUB. |}); 221 | 222 | Lisp.define "sub-of-return-value" 223 | (module Subs.Find_by_return_value) 224 | ~types:(tuple [a] @-> b) 225 | ~docs: 226 | {|(return-from-sub V) returns a name of a function 227 | which return argument is V. Retruns nil if there is no 228 | such function. |}; 229 | 230 | Lisp.define "save-location" (module SaveLocation) 231 | ~types:(tuple [a; b] @-> c) 232 | ~docs: 233 | {|(save-location A L) saves the location L by address A |}; 234 | 235 | Lisp.define "get-location" (module GetLocation) 236 | ~types:(tuple [a;] @-> b) 237 | ~docs: 238 | {|(get-location A) returns location L saved by address A, 239 | or nil if the location not found |}; 240 | 241 | Lisp.signal 242 | ~doc:"Signal is raised when a new unused return value detected" 243 | notify_unused (fun t -> Machine.return [t]); 244 | ] 245 | end 246 | 247 | open Bap_main 248 | 249 | let enabled = 250 | Extension.Configuration.flag 251 | ~doc:"Enables the analysis" 252 | "enable" 253 | 254 | let verbose = 255 | Extension.Configuration.parameter 256 | ~doc:"Level of verbosity. Currently supported 257 | 1 - prints a result message, if the check passed or not; 258 | >1 - prints locations where unchecked values were introduced" 259 | Extension.Type.(int =? 1) 260 | "verbose" 261 | 262 | 263 | let () = 264 | let open Extension.Syntax in 265 | Extension.declare 266 | @@ fun ctxt -> 267 | if ctxt --> enabled then 268 | begin 269 | Subs.init (); 270 | Primus.Machine.add_component (module Interface); 271 | Primus.Machine.add_component (module Notify(struct 272 | let verbose = verbose_of_int (ctxt --> verbose) 273 | end)); 274 | end; 275 | Ok () 276 | [@@warning "-D"] 277 | -------------------------------------------------------------------------------- /jpl-rule-4/descr: -------------------------------------------------------------------------------- 1 | There shall be no direct or indirect use of recursive function calls 2 | 3 | The algorithm. 4 | 5 | Apply the depth first search (DFS) algotithm and determine if there are any 6 | back edges in the program callgraph. And if there are, then destinations 7 | of these edges are the recursive subroutines. 8 | -------------------------------------------------------------------------------- /jpl-rule-4/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter verbosity 1 "the level of verbosity") 2 | 3 | (option passes 4 | with-no-return 5 | find-symbol) 6 | 7 | (option find-symbol-recursive) 8 | (option find-symbol-verbose $verbosity) 9 | -------------------------------------------------------------------------------- /must-check-value/.merlin: -------------------------------------------------------------------------------- 1 | PKG core_kernel 2 | PKG bap 3 | PKG bap-primus 4 | PKG bap-x86-cpu 5 | PKG bap-taint 6 | 7 | S . 8 | B _build/ -------------------------------------------------------------------------------- /must-check-value/descr: -------------------------------------------------------------------------------- 1 | detects that a return value of certain functions is unchecked 2 | -------------------------------------------------------------------------------- /must-check-value/info: -------------------------------------------------------------------------------- 1 | main: must_check_value.ml 2 | depends: bap bap-main bap-primus -------------------------------------------------------------------------------- /must-check-value/must-check-value.lisp: -------------------------------------------------------------------------------- 1 | (require incident) 2 | 3 | (defun value-must-be-checked (name v) 4 | (let ((pc (dict-get 'caller name)) 5 | (loc (dict-get 'caller/location name)) 6 | (tid (taint-introduce-directly 'value-check/required v))) 7 | (when pc 8 | (dict-add 'value-check/required tid pc)) 9 | (dict-add 'value-check/location tid loc))) 10 | 11 | ;; infer an address of a callsite 12 | (defun update-callsite-addr (addr) 13 | (let ((pc (get-current-program-counter))) 14 | (dict-add 'callee addr pc) 15 | (dict-add 'callee/location addr (incident-location)))) 16 | 17 | (defun update-caller (name) 18 | (let ((pc (get-current-program-counter)) 19 | (called (dict-get 'callee pc)) 20 | (called-loc (dict-get 'callee/location pc))) 21 | (when called 22 | (dict-add 'caller name called) 23 | (dict-add 'caller/location name called-loc)))) 24 | 25 | (defmethod call (name _) 26 | (update-caller name)) 27 | 28 | (defmethod jumping (cnd _) 29 | (let ((taint (taint-get-direct 'value-check/required cnd)) 30 | (loc (dict-get 'value-check/location taint)) 31 | (pc (dict-get 'value-check/required taint))) 32 | (when taint 33 | (dict-add 'value-check/done taint taint) 34 | (taint-sanitize-direct 'value-check/required cnd)) 35 | (when pc 36 | (dict-del 'check-value/required taint) 37 | (dict-del 'check-value/location taint)))) 38 | 39 | (defmethod jumping (_ dst) 40 | (update-callsite-addr dst)) 41 | 42 | (defmethod taint-finalize (taint live) 43 | (let ((pc (dict-get 'value-check/required taint)) 44 | (loc (dict-get 'value-check/location taint)) 45 | (checked (dict-get 'value-check/done taint))) 46 | (when (and (not checked) pc) 47 | (incident-report 'value-was-not-checked loc) 48 | (notify-unchecked-value pc) 49 | (dict-del 'value-check/required taint)))) 50 | 51 | (defmethod call-return (name _ ret) 52 | (when (is-in name 53 | 'chdir 54 | 'malloc 'getenv 'mkdtemp 'mkstemp 55 | 'posix_openpt 'system 'gets 'fgets 'feof 56 | 'ferror 'fileno 'chdir 'pipe 'setuid) 57 | (value-must-be-checked name ret))) 58 | 59 | (defmethod call-return (name _ _ ret) 60 | (when (is-in name 'calloc 'realoc 'fdopen 'fopen 61 | 'realpath 'listen 'shutdown 'access 'getcwd 62 | 'symlink 'truncate 'popen) 63 | (value-must-be-checked name ret))) 64 | 65 | (defmethod call-return (name _ _ _ ret) 66 | (when (is-in name 67 | 'freopen 'strxfrm 'accept 'bind 'connect 68 | 'recvmsg 'sendmsg 'socket 'chown 'readv 69 | 'readlink 'write) 70 | (value-must-be-checked name ret))) 71 | 72 | (defmethod call-return (name _ _ _ _ ret) 73 | (when (is-in name 'fread 'fwrite 'recv 'send 'socketpair 74 | 'pread 'pwrite 'read) 75 | (value-must-be-checked name ret))) 76 | 77 | (defmethod call-return (name _ _ _ _ _ _ _ ret) 78 | (when (is-in name 'recvfrom 'sendto 'setsockopt) 79 | (value-must-be-checked name ret))) 80 | 81 | 82 | (defmethod call-return (name _ _ _ _ _ _ ret) 83 | (when (is-in name 'recvfrom 'sendto) 84 | (value-must-be-checked name ret))) 85 | -------------------------------------------------------------------------------- /must-check-value/must_check_value.ml: -------------------------------------------------------------------------------- 1 | 2 | open Core_kernel 3 | open Bap.Std 4 | open Bap_primus.Std 5 | open Bap_main 6 | 7 | let check_name = "must check value" 8 | 9 | type t = { 10 | addrs : Addr.Set.t; 11 | verbose : bool; 12 | } 13 | 14 | let state = 15 | Primus.Machine.State.declare 16 | ~name:"unchecked-return-value" 17 | ~uuid:"7390b60d-fac6-42f7-b13b-94b85bba7586" 18 | (fun _ -> {addrs = Set.empty (module Addr); verbose=false}) 19 | 20 | let atos a = sprintf "%a" Addr.pps a 21 | let print_ok () = Format.printf "%s OK\n" check_name 22 | let print_fail () = Format.printf "%s FAIL\n" check_name 23 | 24 | let print_header () = 25 | let pp_bold ppf = Format.fprintf ppf "\027[1m" in 26 | let pp_norm ppf = Format.fprintf ppf "\027[0m" in 27 | Format.printf "\n%tUnchecked value at address\n%t" pp_bold pp_norm 28 | 29 | let print_addr a = Format.printf "%s\n" @@ atos a 30 | 31 | module Init(S : sig val verbose : bool end)(Machine : Primus.Machine.S) = struct 32 | open Machine.Syntax 33 | 34 | let output _ = 35 | Machine.Global.get state >>= fun {addrs} -> 36 | if Set.is_empty addrs then 37 | print_ok (); 38 | Machine.return () 39 | 40 | 41 | let init () = 42 | Machine.Global.update state 43 | ~f:(fun s -> {s with verbose = S.verbose}) >>= fun () -> 44 | Primus.System.stop >>> output 45 | end 46 | 47 | 48 | module Notify(Machine : Primus.Machine.S) = struct 49 | module Value = Primus.Value.Make(Machine) 50 | open Machine.Syntax 51 | 52 | [@@@warning "-P"] 53 | let run [a] = 54 | let a = Value.to_word a in 55 | Machine.Global.get state >>= fun s -> 56 | if Set.is_empty s.addrs 57 | then print_fail (); 58 | if Set.is_empty s.addrs && s.verbose 59 | then print_header (); 60 | if not (Set.mem s.addrs a) && s.verbose 61 | then print_addr a; 62 | Machine.Global.put state 63 | { s with addrs = Set.add s.addrs a} >>= fun () -> 64 | Value.b0 65 | end 66 | 67 | 68 | module Interface(Machine : Primus.Machine.S) = struct 69 | module Lisp = Primus.Lisp.Make(Machine) 70 | open Primus.Lisp.Type.Spec 71 | 72 | let init () = Machine.sequence [ 73 | Lisp.define "notify-unchecked-value" (module Notify) 74 | ~types:(tuple [a] @-> b) 75 | ~docs: 76 | {|(notify-unchecked-value addr) prints message that value introduced 77 | at [addr] was never used. |}; 78 | ] 79 | end 80 | 81 | let enabled = Extension.Configuration.flag "enable" ~doc:"Enables the analysis" 82 | 83 | let verbose = 84 | Extension.Configuration.parameter 85 | ~as_flag:1 86 | ~doc:"Dumps the results" 87 | Extension.Type.("verbose" %: int) 88 | "verbose" 89 | 90 | let () = 91 | let open Extension.Syntax in 92 | Extension.declare 93 | @@ fun ctxt -> 94 | if ctxt --> enabled then 95 | begin 96 | Primus.Machine.add_component (module Interface); 97 | Primus.Machine.add_component 98 | (module Init(struct let verbose = (ctxt --> verbose) > 1 end)); 99 | end; 100 | Ok () 101 | [@@warning "-D"] 102 | -------------------------------------------------------------------------------- /must-check-value/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter depth 32768 "a depth of analysis") 2 | (parameter entry-points all-subroutines "where to search") 3 | (parameter verbosity 1 "the level of verbosity") 4 | 5 | (option primus-lisp-load 6 | posix 7 | must-check-value) 8 | 9 | (option primus-lisp-add $prefix) 10 | 11 | (option must-check-value-enable) 12 | 13 | (option passes 14 | with-no-return 15 | run) 16 | 17 | (option primus-lisp-channel-redirect 18 | :$prefix/stdin 19 | :$prefix/stdout) 20 | 21 | (option report-progress) 22 | (option log-dir log) 23 | 24 | (option run-entry-points ${entry-points}) 25 | 26 | (option primus-promiscuous-mode) 27 | (option primus-greedy-scheduler) 28 | (option primus-print-output incidents) 29 | (option primus-limit-max-length $depth) 30 | 31 | (option primus-taint-gc conservative) 32 | 33 | (option must-check-value-verbose $verbosity) 34 | 35 | (option primus-print-obs 36 | taint-finalize 37 | exception 38 | pc-changed 39 | jumping 40 | call 41 | call-return 42 | machine-switch 43 | machine-fork 44 | lisp-message 45 | incident 46 | incident-location) 47 | -------------------------------------------------------------------------------- /must-check-value/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/must-check-value/stderr -------------------------------------------------------------------------------- /must-check-value/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/must-check-value/stdin -------------------------------------------------------------------------------- /must-check-value/stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/must-check-value/stdout -------------------------------------------------------------------------------- /opam: -------------------------------------------------------------------------------- 1 | opam-version: "2.0" 2 | name: "bap-toolkit" 3 | version: "master" 4 | maintainer: "Ivan Gotovchits " 5 | authors: "BAP Team" 6 | license: "MIT" 7 | homepage: "https://github.com/BinaryAnalysisPlatform/bap-toolkit/" 8 | bug-reports: "https://github.com/BinaryAnalysisPlatform/bap-toolkit/issues" 9 | dev-repo: "git://github.com/BinaryAnalysisPlatform/bap-toolkit/" 10 | 11 | depends: [ 12 | "ocaml" {>= "4.07.0"} 13 | "bap" 14 | ] 15 | 16 | build: [ 17 | make 18 | ] 19 | 20 | install: [ 21 | make "install" 22 | ] 23 | 24 | 25 | synopsis: "Binary Analysis Platform Toolkit" 26 | description: "A variety of security checks using Bap" 27 | -------------------------------------------------------------------------------- /pack.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # packs a recipe folder into a zip file for the ease of sharing 4 | # Usage: pack 5 | 6 | OLD=`pwd` 7 | NAME=`basename "$1"` 8 | cd $1 9 | zip -r $NAME.recipe * 10 | mv $NAME.recipe $OLD 11 | cd $OLD 12 | -------------------------------------------------------------------------------- /primus-checks/descr: -------------------------------------------------------------------------------- 1 | runs a variety of security checks using Primus 2 | 3 | Microexecutes the program starting from each function and runs 4 | prebuilt security checks, that include: 5 | - use-after-free 6 | - buffer-overflow 7 | - information flow 8 | - hardcoded values 9 | - warn-unused-result 10 | 11 | In terms of the CWE it covers the following entries: 12 | - CWE-122 (Buffer Overwrite) 13 | - CWE-125 (Buffer Overread) 14 | - CWE-416 (Use after free) 15 | - CWE-415 (Double free) 16 | - CWE-798 (Use of Hard-coded Credentials) 17 | - CWE-259 (Use of Hard-coded Password) 18 | - CWE-822 (Untrusted Pointer Dereference) 19 | - CWE-291 (Relience on IP Address for Authentication) 20 | - CWE-170 (Improper Null Termination) 21 | - CWE-138 (Improper Neutralization) 22 | - CWE-74 (Command Injection) 23 | - CWE-690 (Unchecked Return Value to NULL Pointer Dereference) 24 | - CWE-252 (Unchecked Return Value) 25 | 26 | All checks are reported via the incident report system and are stored 27 | in the working directory in the `incidents' file. The file could be 28 | loaded in IDA Pro for further analysis. 29 | -------------------------------------------------------------------------------- /primus-checks/limit-malloc.lisp: -------------------------------------------------------------------------------- 1 | ;; up to 4 Mb each chunk, up to 128 Mbytes total 2 | 3 | (defmethod init () 4 | (set *malloc-max-chunk-size* (* 4 1024 1024)) 5 | (set *malloc-guard-edges* 0) 6 | (set *malloc-max-arena-size* (* 32 *malloc-max-chunk-size*)) 7 | (set *malloc-arena-start* brk) 8 | (set *malloc-zero-sentinel* 0)) 9 | -------------------------------------------------------------------------------- /primus-checks/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter depth 32768 "a depth of analysis") 2 | (parameter entry-points all-subroutines "where to search") 3 | (parameter optimization 0 "optimization level") 4 | 5 | (option primus-lisp-load 6 | posix 7 | memcheck-malloc 8 | limit-malloc 9 | taint-sources 10 | sensitive-sinks 11 | warn-unused 12 | check-hardcoded-values) 13 | 14 | (option primus-lisp-add $prefix) 15 | 16 | (option passes 17 | with-no-return 18 | run) 19 | 20 | (option primus-lisp-channel-redirect 21 | :$prefix/stdin 22 | :$prefix/stdout) 23 | 24 | (option report-progress) 25 | (option log-dir log) 26 | 27 | (option run-entry-points ${entry-points}) 28 | (option constant-tracker-enable) 29 | 30 | (option primus-promiscuous-mode) 31 | (option primus-greedy-scheduler) 32 | (option primus-print-output incidents) 33 | (option primus-limit-max-length $depth) 34 | 35 | (option primus-print-obs 36 | taint-finalize 37 | exception 38 | pc-changed 39 | jumping 40 | call 41 | call-return 42 | machine-switch 43 | machine-fork 44 | lisp-message 45 | incident 46 | incident-location) 47 | 48 | (option optimization-level $optimization) 49 | -------------------------------------------------------------------------------- /primus-checks/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/primus-checks/stdin -------------------------------------------------------------------------------- /primus-checks/stdout: -------------------------------------------------------------------------------- 1 | ELFELF 2 | ELF 3 | ELF 4 | -------------------------------------------------------------------------------- /restrictness-check/.merlin: -------------------------------------------------------------------------------- 1 | PKG core_kernel 2 | PKG bap 3 | PKG bap-primus 4 | PKG bap-taint 5 | PKG bap-x86-cpu 6 | 7 | S . 8 | B _build/ -------------------------------------------------------------------------------- /restrictness-check/descr: -------------------------------------------------------------------------------- 1 | detects an aliasing of functions arguments with 'restrict' type qualifier 2 | 3 | The analysis reports a software defect when a restrict-qualified pointer is assigned 4 | a value based on another restricted pointer whose associated block neither began execution 5 | before the block associated with this pointer nor ended before the assignment. -------------------------------------------------------------------------------- /restrictness-check/info: -------------------------------------------------------------------------------- 1 | main : restrictness_check.ml 2 | depends: bap bap-main bap-primus bap-c -------------------------------------------------------------------------------- /restrictness-check/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter depth 32768 "a depth of analysis") 2 | (parameter entry-points all-subroutines "where to search") 3 | 4 | (option primus-lisp-load 5 | posix 6 | restrict) 7 | 8 | (option passes 9 | with-no-return 10 | callsites 11 | run) 12 | 13 | (option restrictness-check-enable) 14 | 15 | (option primus-promiscuous-mode) 16 | (option primus-greedy-scheduler) 17 | (option primus-limit-max-length $depth) 18 | 19 | (option run-entry-points ${entry-points}) 20 | 21 | (option primus-lisp-add $prefix) 22 | (option primus-print-output incidents) 23 | (option primus-lisp-channel-redirect 24 | :$prefix/stdin 25 | :$prefix/stdout 26 | :$prefix/stderr) 27 | 28 | (option primus-print-observations 29 | exception 30 | pc-changed 31 | jumping 32 | call 33 | call-return 34 | machine-switch 35 | machine-fork 36 | lisp-message 37 | incident 38 | incident-location) 39 | 40 | (option log-dir log) 41 | -------------------------------------------------------------------------------- /restrictness-check/restrict.lisp: -------------------------------------------------------------------------------- 1 | 2 | 3 | (defmethod jumping(_ _ ) 4 | (when (is-restrictness-violation) 5 | (incident-report 'restrictness-violation (incident-location)))) 6 | -------------------------------------------------------------------------------- /restrictness-check/restrictness_check.ml: -------------------------------------------------------------------------------- 1 | (** Restrictness check 2 | 3 | The Algorithm 4 | 5 | For any pointer with the 'restrict' type qualifier, 6 | we check if there is another pointer among function 7 | arguments, which belongs to the same memory location in 8 | a heap or even exactly equal to the first one. *) 9 | 10 | open Core_kernel 11 | open Bap.Std 12 | open Bap_primus.Std 13 | open Bap_main 14 | open Bap_c.Std 15 | 16 | let check_name = "restrictness check" 17 | 18 | let is_restricted arg = match Term.get_attr arg C.t with 19 | | Some (`Pointer q) -> C.Type.Spec.(q.qualifier.restrict) 20 | | _ -> false 21 | 22 | let state = Primus.Machine.State.declare 23 | ~name:"restrictness-check-results" 24 | ~uuid:"ab02bbc9-5573-4bdf-a010-605dc6851b9d" 25 | (fun _ -> []) 26 | 27 | let print_results rs = 28 | let pp_bold ppf = Format.fprintf ppf "\027[1m" in 29 | let pp_norm ppf = Format.fprintf ppf "\027[0m" in 30 | match rs with 31 | | [] -> Format.printf "%s OK\n" check_name 32 | | rs -> 33 | Format.printf "%s FAIL\n\n" check_name; 34 | Format.printf "%t%-10s %-20s %s\n%t" pp_bold "Address" "Function" 35 | "Aliased arguments" pp_norm; 36 | let reported = Map.empty (module Addr) in 37 | Caml.ignore @@ 38 | List.fold rs ~init:reported ~f:(fun reported (addr,sub,aliases) -> 39 | let args = List.sort aliases ~compare:String.compare in 40 | let args = String.concat args ~sep:"," in 41 | match Map.find reported addr with 42 | | Some a when Set.mem a args -> reported 43 | | a -> 44 | let a = Option.value ~default:(Set.empty (module String)) a in 45 | let reported = Map.set reported addr (Set.add a args) in 46 | let addr = sprintf "%a" Addr.pps addr in 47 | Format.printf "%-10s %-20s %s\n" addr sub args; 48 | reported) 49 | 50 | module Regions = struct 51 | module I = Interval_tree.Make(struct 52 | type point = Primus.Value.t [@@deriving compare, sexp] 53 | type t = point * point [@@deriving compare, sexp] 54 | let lower = fst 55 | let upper = snd 56 | end) 57 | 58 | type t = unit I.t 59 | 60 | let empty = I.empty 61 | let alloc t start finish = I.add t (start, finish) () 62 | let find t addr = I.lookup t addr |> Seq.map ~f:fst |> Seq.hd 63 | 64 | let release t ptr = match find t ptr with 65 | | None -> t 66 | | Some key -> I.remove t key 67 | 68 | (** [find_origin t addr] 69 | For heap bases pointers returns a beginning of the 70 | allocated region. For stack pointers - a pointer 71 | itself *) 72 | let find_origin t addr = match find t addr with 73 | | None -> addr 74 | | Some key -> fst key 75 | 76 | (** [is_shared t addr addr'] returns true if addr and addr' share the same region *) 77 | let is_shared t addr addr' = 78 | Primus.Value.equal (find_origin t addr) (find_origin t addr') 79 | 80 | end 81 | 82 | let regions = Primus.Machine.State.declare 83 | ~name:"restrictness-mem-regions" 84 | ~uuid:"19826f38-24ce-42ef-bef5-8d4a54b5975d" 85 | (fun _ -> Regions.empty) 86 | 87 | module Regions_tracker(Machine : Primus.Machine.S) = struct 88 | module Value = Primus.Value.Make(Machine) 89 | module Eval = Primus.Interpreter.Make(Machine) 90 | module Env = Primus.Env.Make(Machine) 91 | 92 | open Machine.Syntax 93 | 94 | let alloc ptr len = 95 | if Value.is_zero ptr || Value.is_zero len 96 | then Machine.return () 97 | else 98 | Value.add ptr len >>= fun fin -> 99 | Value.pred fin >>= fun fin -> 100 | Machine.Local.update regions 101 | ~f:(fun regs -> Regions.alloc regs ptr fin) 102 | 103 | let release ptr = 104 | Machine.Local.update regions 105 | ~f:(fun regs -> Regions.release regs ptr) 106 | 107 | let on_call_return = function 108 | | "malloc", [len; ptr] -> alloc ptr len 109 | | "free", [ptr] -> release ptr 110 | | _ -> Machine.return () 111 | 112 | let init () = Machine.sequence [ 113 | Primus.Linker.Trace.return >>> on_call_return; 114 | ] 115 | end 116 | 117 | module Dump_results(Machine : Primus.Machine.S) = struct 118 | open Machine.Syntax 119 | 120 | let on_stop _ = 121 | Machine.Global.get state >>| fun s -> 122 | print_results s 123 | 124 | let init () = 125 | Primus.System.stop >>> on_stop 126 | end 127 | 128 | let is_out a = match Arg.intent a with 129 | | Some Out -> true 130 | | _ -> false 131 | 132 | module Is_violation(Machine : Primus.Machine.S) = struct 133 | module Env = Primus.Env.Make(Machine) 134 | module Eval = Primus.Interpreter.Make(Machine) 135 | module Value = Primus.Value.Make(Machine) 136 | open Machine.Syntax 137 | 138 | let is_alias regs arg arg' = 139 | Eval.get (Arg.lhs arg) >>= fun ptr -> 140 | Eval.get (Arg.lhs arg') >>= fun ptr' -> 141 | Machine.return (Regions.is_shared regs ptr ptr') 142 | 143 | let find_aliases args = 144 | let restricted = Seq.filter ~f:is_restricted args in 145 | if Seq.is_empty restricted then Machine.return [] 146 | else 147 | Machine.Local.get regions >>= fun regs -> 148 | Machine.Seq.fold restricted ~init:[] ~f:(fun fails res -> 149 | Machine.Seq.fold args ~init:fails ~f:(fun fails arg -> 150 | if Arg.equal res arg || is_out arg 151 | then Machine.return fails 152 | else 153 | is_alias regs res arg >>= fun is_alias -> 154 | Machine.return @@ 155 | if is_alias 156 | then 157 | (Arg.lhs res, Arg.lhs arg) :: fails 158 | else fails)) 159 | 160 | let find_sub jmp = 161 | match Jmp.kind Primus.Pos.(jmp.me) with 162 | | Goto _ | Ret _ | Int _ -> Machine.return None 163 | | Call c -> match Call.target c with 164 | | Indirect _ -> Machine.return None 165 | | Direct tid -> 166 | Machine.get () >>= fun proj -> 167 | Machine.return @@ 168 | Program.lookup sub_t (Project.program proj) tid 169 | 170 | let update_results sub aliases = 171 | Eval.pc >>= fun addr -> 172 | Machine.Global.update state (fun s -> 173 | List.fold aliases ~init:s 174 | ~f:(fun s (arg1,arg2) -> 175 | let names = [Var.name arg1; Var.name arg2] in 176 | (addr,sub,names) :: s)) 177 | 178 | let run _ = 179 | Eval.pos >>= fun pos -> 180 | match pos with 181 | | Primus.Pos.Jmp jmp -> 182 | begin 183 | find_sub jmp >>= function 184 | | None -> Value.b0 185 | | Some sub -> 186 | find_aliases (Term.enum arg_t sub) >>= function 187 | | [] -> 188 | Value.b0 189 | | aliases -> 190 | update_results (Sub.name sub) aliases >>= fun () -> 191 | Value.b1 192 | end 193 | | _ -> Value.b0 194 | 195 | end 196 | 197 | 198 | module Interface(Machine : Primus.Machine.S) = struct 199 | module Lisp = Primus.Lisp.Make(Machine) 200 | open Primus.Lisp.Type.Spec 201 | 202 | let init () = 203 | Lisp.define "is-restrictness-violation" (module Is_violation) 204 | ~types:(unit @-> bool) 205 | ~docs:{|(is-restrictness-violation) returns true if a current 206 | position is jump and arguments with 'restrict' keyword 207 | of a target subroutine are aliased|}; 208 | end 209 | 210 | let enabled = 211 | Extension.Configuration.flag "enable" ~doc:"Enables the analysis" 212 | 213 | let () = 214 | let open Extension.Syntax in 215 | Extension.declare 216 | @@ fun ctxt -> 217 | if ctxt --> enabled then 218 | begin 219 | Primus.Machine.add_component (module Regions_tracker); 220 | Primus.Machine.add_component (module Dump_results); 221 | Primus.Machine.add_component (module Interface); 222 | end; 223 | Ok () 224 | [@@warning "-D"] 225 | -------------------------------------------------------------------------------- /restrictness-check/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/restrictness-check/stderr -------------------------------------------------------------------------------- /restrictness-check/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/restrictness-check/stdin -------------------------------------------------------------------------------- /restrictness-check/stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/restrictness-check/stdout -------------------------------------------------------------------------------- /spectre/descr: -------------------------------------------------------------------------------- 1 | detects spectre vulnerability 2 | -------------------------------------------------------------------------------- /spectre/gather-spectre.lisp: -------------------------------------------------------------------------------- 1 | (defmethod spectre-hypot-partial (c) 2 | (spectre/register c)) 3 | 4 | (defmethod spectre-hypot-init (c) 5 | (spectre/register c)) 6 | 7 | (defmethod spectre-path (t c l s) 8 | (incident-report 'spectre-pattern 9 | (dict-get 'taint-sources/untrusted t) 10 | (dict-get 'spectre/locations c) 11 | (dict-get 'spectre/locations l) 12 | (incident-location))) 13 | 14 | (defun spectre/register (c) 15 | (dict-add 'spectre/locations c (incident-location))) 16 | 17 | 18 | (defun check-fail () 19 | (declare (external "__stack_chk_fail")) 20 | (error "stack check failed")) 21 | -------------------------------------------------------------------------------- /spectre/info: -------------------------------------------------------------------------------- 1 | main: ddtbd.ml 2 | depends: bap bap-primus bap-taint bap-future graphlib 3 | -------------------------------------------------------------------------------- /spectre/limit-malloc.lisp: -------------------------------------------------------------------------------- 1 | ;; up to 4 Mb each chunk, up to 128 Mbytes total 2 | 3 | (defmethod init () 4 | (set *malloc-max-chunk-size* (* 4 1024 1024)) 5 | (set *malloc-guard-edges* 0) 6 | (set *malloc-max-arena-size* (* 32 *malloc-max-chunk-size*)) 7 | (set *malloc-arena-start* brk) 8 | (set *malloc-zero-sentinel* 0)) 9 | -------------------------------------------------------------------------------- /spectre/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter decay 100 "the number of terms while the trail is hot") 2 | (parameter depth 32768 "a depth of analysis") 3 | (parameter entry-points all-subroutines "where to search") 4 | 5 | (option primus-lisp-load 6 | posix 7 | limit-malloc 8 | taint-inputs 9 | gather-spectre) 10 | 11 | (option primus-lisp-channel-redirect 12 | :$prefix/stdin 13 | :$prefix/stdout) 14 | 15 | (option report-progress) 16 | (option log-dir log) 17 | 18 | (option run) 19 | (option run-entry-points ${entry-points}) 20 | 21 | (option primus-promiscuous-mode) 22 | (option primus-greedy-scheduler) 23 | (option primus-print-output incidents) 24 | (option ddtbd-length $decay) 25 | (option ddtbd-enable) 26 | (option primus-limit-max-length $depth) 27 | (option primus-lisp-add $prefix) 28 | (option primus-print-obs 29 | spectre-path 30 | spectre-hypot-partial 31 | spectre-hypot-init 32 | pc-changed 33 | jumping 34 | call 35 | call-return 36 | machine-switch 37 | machine-fork 38 | undefined-input 39 | undefined-var 40 | undefined-ptr 41 | taint-attached 42 | lisp-message 43 | incident 44 | incident-location) 45 | -------------------------------------------------------------------------------- /spectre/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/spectre/stdin -------------------------------------------------------------------------------- /spectre/stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/spectre/stdout -------------------------------------------------------------------------------- /spectre/taint-inputs.lisp: -------------------------------------------------------------------------------- 1 | (require incident) 2 | (require taint-sources) 3 | 4 | ;; Rule: 5 | ;; undefined-input (x) |- T(x) 6 | ;; 7 | ;; Motivation: 8 | ;; We don't know anything about data that is defined externally, so we 9 | ;; will assume, that it is also controlled by a user. 10 | (defmethod undefined-input (x) 11 | (untrust/value x)) 12 | -------------------------------------------------------------------------------- /tests/.dockerignore: -------------------------------------------------------------------------------- 1 | incidents 2 | artifact 3 | log 4 | toolkit.log 5 | Makefile 6 | README.md 7 | src/_build 8 | *.o 9 | *.cmi 10 | *.cmo 11 | *.cmx 12 | src/compare_incidents.native -------------------------------------------------------------------------------- /tests/Dockerfile: -------------------------------------------------------------------------------- 1 | FROM binaryanalysisplatform/bap:latest as base 2 | 3 | COPY --chown=opam:nogroup src /src 4 | WORKDIR /src 5 | RUN eval "$(opam env)" && make build 6 | 7 | FROM binaryanalysisplatform/bap-toolkit:latest as toolkit 8 | 9 | COPY . /tests 10 | WORKDIR /tests 11 | COPY --from=base /src/compare-incidents /tests 12 | COPY --from=binaryanalysisplatform/bap-artifacts:cron-3.0pl1-127 /artifact artifacts/cron-3.0pl1-127 13 | COPY --from=binaryanalysisplatform/bap-artifacts:gifsicle-1.89 /artifact artifacts/gifsicle-1.89 14 | COPY --from=binaryanalysisplatform/bap-artifacts:juliet-cwe-122 /artifact artifacts/juliet-cwe-122 15 | COPY --from=binaryanalysisplatform/bap-artifacts:juliet-cwe-252 /artifact artifacts/juliet-cwe-252 16 | COPY --from=binaryanalysisplatform/bap-artifacts:juliet-cwe-415 /artifact artifacts/juliet-cwe-415 17 | COPY --from=binaryanalysisplatform/bap-artifacts:juliet-cwe-416 /artifact artifacts/juliet-cwe-416 18 | COPY --from=binaryanalysisplatform/bap-artifacts:juliet-cwe-476 /artifact artifacts/juliet-cwe-476 19 | COPY --from=binaryanalysisplatform/bap-artifacts:libgd-2.2.5 /artifact artifacts/libgd-2.2.5 20 | COPY --from=binaryanalysisplatform/bap-artifacts:libssh-0.5.2 /artifact artifacts/libssh-0.5.2 21 | COPY --from=binaryanalysisplatform/bap-artifacts:ntpd-4.2.8p12 /artifact artifacts/ntpd-4.2.8p12 22 | COPY --from=binaryanalysisplatform/bap-artifacts:tcpreplay-4.3.1 /artifact artifacts/tcpreplay-4.3.1 23 | RUN sh run.sh 24 | -------------------------------------------------------------------------------- /tests/Makefile: -------------------------------------------------------------------------------- 1 | 2 | test: build 3 | sh copy_artifacts.sh 4 | sh update_dockerfile.sh 5 | sh run.sh 6 | 7 | build: 8 | make -C src 9 | -------------------------------------------------------------------------------- /tests/README.md: -------------------------------------------------------------------------------- 1 | 2 | # Intro 3 | 4 | Tests are based on the incidents comparison: a new obtained set of incidents is 5 | compared with an expected one. 6 | There are the next three possible outcomes of the comparison: 7 | - false positive is a presence of an incident when there is no confirmed bug in the code. 8 | - false negative is an absence of an incident when there is a confirmed bug in the code. 9 | - true positive is a presence of an incident when there is a confirmed bug in the code. 10 | 11 | An expected incident is such one that was checked manually and points to the real bug, i.e. 12 | is a real true positivite. 13 | 14 | Tests are devided into the two categories: litmuses and artifacts. 15 | 16 | 17 | ## Litmus tests 18 | Litmus is a small program that covers only one check and usually contains just one simple test case 19 | that trigger only one incident. Given a simplicity of the test case, we don't allow neither false 20 | positivites nor false negativites and require 100% match between expected and testing set of the incidents. 21 | Litmus can't be used as a proof of a check's reliability, but serves as a fast test for 22 | an idea that stands behind it. 23 | 24 | For instance, the litmus for null pointer dereference contains two cases: 25 | ``` 26 | 1. void good() { 27 | 2. int *x = NULL; 28 | 3. int b = 0; 29 | 4. if (!x) 30 | 5. b = *x; 31 | 6. } 32 | 7 33 | 8. void bad() { 34 | 9. int *x = NULL; 35 | 10. int b = 0; 36 | 11. b = *x; 37 | 12. } 38 | ``` 39 | Our approach to this check is that if a pointer was checked - even in wrong way, like in the example 40 | above - then the usage of the pointer is considered as a safe one. And vice versa - if there was no 41 | check on the pointer, before derefence then we trigger an incident. 42 | Thus, if we have an incident by an address corresponded to line '5', we consider it as a false positive, 43 | meaning something went wrong. The same, if we don't have an incident on line `11`, we consider is 44 | as false negative - and again it means that we have a bug in our implementation. 45 | (or tests are outdated and need to be reviewed). 46 | 47 | ### Adding a new litmus 48 | To add a new litmus test for the check named `foo`, one need to: 49 | 1) add a source code to `tests/litmus-tests/src/foo.c` 50 | 2) add a binary to `tests/litmus-tests/bin/foo` 51 | 3) add expected incidents into `tests/litmus-tests/data/foo/expected` 52 | 53 | 54 | ## Artifacts 55 | Artifacts are more complex programs then litmuses and therefore it's harder to find a bug there. 56 | Some of them were taken from Juliet test set, some of them are real programs with known bugs. 57 | Given that, we slightly relax our comparison rules and allow checks to triger false positivites, 58 | though the bugs must be still discovered, i.e. expected incidents must be a subset of the new obtained 59 | incidents. 60 | 61 | ### Adding a new artifact 62 | 63 | Although we can customize it in future, but right now tests depend on the 64 | `binaryanalysisplatform/bap-artifacts` docker hub repository, where each artifact is represented by a tag, 65 | e.g.: `binaryanalysisplatform/bap-artifacts:cron-3.0pl1-127`. 66 | 67 | Basicaly, to add a new artifact `foo` one need to: 68 | 1) make `docker push binaryanalysisplatform/bap-artifacts:foo` 69 | 2) create a folder `tests/artifacts/foo` 70 | 3) create a subfolder with a desired check name (it's used for display purposes only), e.g. `tests/artifacts/foo/BAR` 71 | 4) create a `tests/artifacts/foo/BAR/run` file with parameters to `bap --recipe=` option 72 | 5) create a `tests/artifacts/foo/BAR/expected` file expected incidents 73 | 74 | Each artifact can contain more than one check, e.g. `libssh-0.5.2`. 75 | 76 | # Log 77 | For the debug purposes, log is stored in `tests/toolkit.log` file, which contains basic 78 | information for every check: time started/finished, status, missed incidents if any. 79 | 80 | 81 | # Expected results 82 | 83 | ``` 84 | LITMUS TESTS 85 | av-rule-17 .................................................. PASS 86 | av-rule-174 ................................................. PASS 87 | av-rule-189 ................................................. PASS 88 | av-rule-19 .................................................. PASS 89 | av-rule-20 .................................................. PASS 90 | av-rule-21 .................................................. PASS 91 | av-rule-22 .................................................. PASS 92 | av-rule-23 .................................................. PASS 93 | av-rule-24 .................................................. PASS 94 | av-rule-25 .................................................. PASS 95 | av-rule-3 ................................................... PASS 96 | double-free ................................................. PASS 97 | heap-overflow ............................................... PASS 98 | jpl-rule-14 ................................................. PASS 99 | jpl-rule-4 .................................................. PASS 100 | must-check-value ............................................ PASS 101 | restrictness-check .......................................... PASS 102 | untrusted-argument .......................................... PASS 103 | use-after-free .............................................. PASS 104 | warn-unused ................................................. PASS 105 | 106 | ARTIFACTS (patience!) 107 | CVE-2019-9706 ............................................... PASS 108 | CVE-2017-1000421 ............................................ PASS 109 | juliet-cwe-122/heap-overflow ................................ PASS 110 | juliet-cwe-252/jpl-rule-14 .................................. PASS 111 | juliet-cwe-415/double-free .................................. PASS 112 | juliet-cwe-416/use-after-free ............................... PASS 113 | juliet-cwe-476/av-rule-174 .................................. PASS 114 | CVE-2018-1000222 ............................................ PASS 115 | CVE-2012-4559 ............................................... PASS 116 | CVE-2012-6063 ............................................... PASS 117 | CVE-2019-8936 ............................................... PASS 118 | CVE-2019-8377 ............................................... PASS 119 | 120 | OK 121 | ``` 122 | -------------------------------------------------------------------------------- /tests/artifacts/cron-3.0pl1-127/CVE-2019-9706/expected: -------------------------------------------------------------------------------- 1 | (incident-location (23 2 | (12:403f30 12:404368 12:404361 12:404358 1:404358 3 | 1:404332 1:404321 1:403f26 1:4036b0 1:4036aa 1:403687 4 | 1:40367a 1:403659 1:403f1a 1:403f0a 1:403703 1:4036fd 5 | 1:4036e7 1:4036e7 1:4036e0 1:4036f9 1:4036cc 1:403efc))) 6 | (incident-location (25 7 | (25:403f76 25:403f6d 1:403f6d 1:403f52 1:403f3e 1:403f30 8 | 1:404368 1:404361 1:404358 1:404358 1:404332 1:404321 9 | 1:403f26 1:4036b0 1:4036aa 1:403687 1:40367a 1:403659 10 | 1:403f1a 1:403f0a 1:403703 1:4036fd 1:4036e7 1:4036e7 11 | 1:4036e0 1:4036f9 1:4036cc 1:403efc))) 12 | (incident-location (26 13 | (25:403f8e 25:403f80 25:403f7b 25:403f76 25:403f6d 14 | 1:403f6d 1:403f52 1:403f3e 1:403f30 1:404368 1:404361 15 | 1:404358 1:404358 1:404332 1:404321 1:403f26 1:4036b0 16 | 1:4036aa 1:403687 1:40367a 1:403659 1:403f1a 1:403f0a 17 | 1:403703 1:4036fd 1:4036e7 1:4036e7 1:4036e0 1:4036f9 18 | 1:4036cc 1:403efc))) 19 | (incident (memcheck-use-after-release 23 25 26)) -------------------------------------------------------------------------------- /tests/artifacts/cron-3.0pl1-127/CVE-2019-9706/run: -------------------------------------------------------------------------------- 1 | use-after-free:entry-points=force_rescan_user:depth=12000 2 | -------------------------------------------------------------------------------- /tests/artifacts/gifsicle-1.89/CVE-2017-1000421/expected: -------------------------------------------------------------------------------- 1 | (incident-location (2 2 | (7:407a82 7:407a6b 7:407a65 7:407a5f 7:407a57 7:407c2b 3 | 7:409f57 7:407c00 7:407bf4 7:407b93 7:407a90 7:407a8a 4 | 7:407a82 7:407a6b 7:407a65 7:407a5f 7:407a57 7:407b8b 5 | 7:409f4f 7:409f4c 7:409f46 7:409f40 7:40ac85 7:40ac6e 6 | 5:40ac69 5:40ac64 3:40ac5f 3:40ac5a 1:40ac55))) 7 | (incident-location (285 8 | (309:4086a2 309:40868c 309:408678 309:40866c 309:408666 9 | 309:408664 309:40865b 309:408645 309:408629 309:408450 10 | 309:4083f3 309:40861d 309:408614 309:4085d5 309:4085d3 11 | 309:408768 309:40871d 309:408710 309:4086e9 309:4086e2 12 | 309:40a7d6 309:40a54f 301:409dae 301:409d9f 301:40997c 13 | 301:409965 301:40994f 301:409b81 301:409925 301:401a50 14 | 301:409919 301:4098e1 301:409998 301:409996 270:40998e 15 | 270:409711 270:409706 270:4096fb 270:4096e7 270:4096c7 16 | 270:409896 270:40988c 270:4098cd 270:4098c8 270:4098a0 17 | 270:409697 270:409683 270:409668 270:40963e 270:409be5 18 | 270:409bbf 270:409af6 270:40983d 270:4095ed 270:4095e4 19 | 270:409d91 270:409d61 270:409253 270:409274 270:409272 20 | 270:40925e 270:4091f7 270:4091e5 270:407a90 270:407a8a 21 | 270:407a82 270:407a7c 270:407a76 270:407a6b 270:407a65 22 | 270:407a5f 270:407a57 270:4091da 270:4091bf 270:409008 23 | 270:408fee 270:408fec 270:408fe3 270:408fd7 270:4091b7 24 | 270:4092ed 270:407a90 270:407a8a 270:407a82 270:407a65 25 | 270:407a5f 270:407a57 270:4092d5 270:409d5a 270:40a548 26 | 270:40a53d 270:40a53b 45:40a531 45:40a51b 45:40a513 27 | 45:40a4cd 45:40a4ba 45:40a5ed 45:409367 45:409253 28 | 45:409274 45:409272 45:40925e 45:4091f7 45:4091e5 29 | 45:407a90 45:407a8a 45:407a82 45:407a7c 45:407a76 30 | 45:407a6b 45:407a65 45:407a5f 45:407a57 45:4091da 31 | 45:4091bf 45:409008 45:408fe3 45:408fd7 45:4091b7 32 | 45:4092ed 45:407a90 45:407a8a 45:407a82 45:407a65 33 | 45:407a5f 45:407a57 45:4092d5 45:409358 45:409310 34 | 45:409008 45:408fe3 45:408fd7 45:409304 45:40a5dc 35 | 45:40a928 45:40a5b7 45:40a5a6 45:40a498 45:40a492 36 | 45:40a480 45:40a46d 45:40a457 45:40a44d 45:40a43c 37 | 45:40a432 45:40a421 45:40a417 45:40a406 45:40a3fc 38 | 45:40a3f3 45:407fc5 45:407fbb 45:408003 45:407ffe 39 | 45:407a90 45:407a8a 45:407a82 45:407a7c 45:407a76 40 | 45:407a6b 45:407a65 45:407a5f 45:407a57 45:407ff3 41 | 45:407fdb 45:407fd2 45:407fa4 45:40a3ec 45:40a0b3 42 | 7:40a0ae 7:40a0a9 7:40a0a4 7:40a099 7:40a08d 7:40a082 43 | 7:40a07c 7:40a06f 7:40a066 7:40a055 7:40a04b 7:40a03a 44 | 7:40a030 7:40a023 7:40a01a 7:40a00b 7:409fff 7:409ff6 45 | 7:407a90 7:407a8a 7:407a82 7:407a7c 7:407a76 7:407a6b 46 | 7:407a65 7:407a5f 7:407a57 7:409fc0 7:407a90 7:407a8a 47 | 7:407a82 7:407a65 7:407a5f 7:407a57 7:409f9c 7:407a90 48 | 7:407a8a 7:407a82 7:407a7c 7:407a76 7:407a6b 7:407a65 49 | 7:407a5f 7:407a57 7:409f7b 7:407ce3 7:407cd8 7:407c33 50 | 7:407a90 7:407a8a 7:407a82 7:407a6b 7:407a65 7:407a5f 51 | 7:407a57 7:407c2b 7:409f57 7:407c00 7:407bf4 7:407b93 52 | 7:407a90 7:407a8a 7:407a82 7:407a6b 7:407a65 7:407a5f 53 | 7:407a57 7:407b8b 7:409f4f 7:409f4c 7:409f46 7:409f40 54 | 7:40ac85 7:40ac6e 5:40ac69 5:40ac64 3:40ac5f 3:40ac5a 55 | 1:40ac55))) 56 | (incident-location (286 57 | (309:40a112 309:40a10c 309:40a103 309:40a7db 309:408763 58 | 309:408761 309:408725 309:408770 309:4086a2 309:40868c 59 | 309:408678 309:40866c 309:408666 309:408664 309:40865b 60 | 309:408645 309:408629 309:408450 309:4083f3 309:40861d 61 | 309:408614 309:4085d5 309:4085d3 309:408768 309:40871d 62 | 309:408710 309:4086e9 309:4086e2 309:40a7d6 309:40a54f 63 | 301:409dae 301:409d9f 301:40997c 301:409965 301:40994f 64 | 301:409b81 301:409925 301:401a50 301:409919 301:4098e1 65 | 301:409998 301:409996 270:40998e 270:409711 270:409706 66 | 270:4096fb 270:4096e7 270:4096c7 270:409896 270:40988c 67 | 270:4098cd 270:4098c8 270:4098a0 270:409697 270:409683 68 | 270:409668 270:40963e 270:409be5 270:409bbf 270:409af6 69 | 270:40983d 270:4095ed 270:4095e4 270:409d91 270:409d61 70 | 270:409253 270:409274 270:409272 270:40925e 270:4091f7 71 | 270:4091e5 270:407a90 270:407a8a 270:407a82 270:407a7c 72 | 270:407a76 270:407a6b 270:407a65 270:407a5f 270:407a57 73 | 270:4091da 270:4091bf 270:409008 270:408fee 270:408fec 74 | 270:408fe3 270:408fd7 270:4091b7 270:4092ed 270:407a90 75 | 270:407a8a 270:407a82 270:407a65 270:407a5f 270:407a57 76 | 270:4092d5 270:409d5a 270:40a548 270:40a53d 270:40a53b 77 | 45:40a531 45:40a51b 45:40a513 45:40a4cd 45:40a4ba 78 | 45:40a5ed 45:409367 45:409253 45:409274 45:409272 79 | 45:40925e 45:4091f7 45:4091e5 45:407a90 45:407a8a 80 | 45:407a82 45:407a7c 45:407a76 45:407a6b 45:407a65 81 | 45:407a5f 45:407a57 45:4091da 45:4091bf 45:409008 82 | 45:408fe3 45:408fd7 45:4091b7 45:4092ed 45:407a90 83 | 45:407a8a 45:407a82 45:407a65 45:407a5f 45:407a57 84 | 45:4092d5 45:409358 45:409310 45:409008 45:408fe3 85 | 45:408fd7 45:409304 45:40a5dc 45:40a928 45:40a5b7 86 | 45:40a5a6 45:40a498 45:40a492 45:40a480 45:40a46d 87 | 45:40a457 45:40a44d 45:40a43c 45:40a432 45:40a421 88 | 45:40a417 45:40a406 45:40a3fc 45:40a3f3 45:407fc5 89 | 45:407fbb 45:408003 45:407ffe 45:407a90 45:407a8a 90 | 45:407a82 45:407a7c 45:407a76 45:407a6b 45:407a65 91 | 45:407a5f 45:407a57 45:407ff3 45:407fdb 45:407fd2 92 | 45:407fa4 45:40a3ec 45:40a0b3 7:40a0ae 7:40a0a9 7:40a0a4 93 | 7:40a099 7:40a08d 7:40a082 7:40a07c 7:40a06f 7:40a066 94 | 7:40a055 7:40a04b 7:40a03a 7:40a030 7:40a023 7:40a01a 95 | 7:40a00b 7:409fff 7:409ff6 7:407a90 7:407a8a 7:407a82 96 | 7:407a7c 7:407a76 7:407a6b 7:407a65 7:407a5f 7:407a57 97 | 7:409fc0 7:407a90 7:407a8a 7:407a82 7:407a65 7:407a5f 98 | 7:407a57 7:409f9c 7:407a90 7:407a8a 7:407a82 7:407a7c 99 | 7:407a76 7:407a6b 7:407a65 7:407a5f 7:407a57 7:409f7b 100 | 7:407ce3 7:407cd8 7:407c33 7:407a90 7:407a8a 7:407a82 101 | 7:407a6b 7:407a65 7:407a5f 7:407a57 7:407c2b 7:409f57 102 | 7:407c00 7:407bf4 7:407b93 7:407a90 7:407a8a 7:407a82 103 | 7:407a6b 7:407a65 7:407a5f 7:407a57 7:407b8b 7:409f4f 104 | 7:409f4c 7:409f46 7:409f40 7:40ac85 7:40ac6e 5:40ac69 105 | 5:40ac64 3:40ac5f 3:40ac5a 1:40ac55))) 106 | (incident (memcheck-use-after-release 2 285 286)) -------------------------------------------------------------------------------- /tests/artifacts/gifsicle-1.89/CVE-2017-1000421/run: -------------------------------------------------------------------------------- 1 | use-after-free:entry-points=read_gif -------------------------------------------------------------------------------- /tests/artifacts/juliet-cwe-122/heap-overflow/expected: -------------------------------------------------------------------------------- 1 | (incident-location (11 (112:6ab8))) 2 | (incident-location (12 (112:2c38 112:6ae2 112:6ac6 112:6ab8))) 3 | (incident (memcheck-out-of-bound 11 11 12)) 4 | (incident-location (16 (130:6ef6))) 5 | (incident-location (17 (130:53aa 130:6f1f 130:6f04 130:6ef6))) 6 | (incident (memcheck-out-of-bound 16 16 17)) 7 | (incident-location (21 (148:5620))) 8 | (incident-location (22 (148:833f 148:5649 148:562e 148:5620))) 9 | (incident (memcheck-out-of-bound 21 21 22)) 10 | (incident-location (26 (165:631d))) 11 | (incident-location (27 (165:5c36 165:6342 165:632b 165:631d))) 12 | (incident (memcheck-out-of-bound 26 26 27)) 13 | (incident-location (31 (182:558f))) 14 | (incident-location (32 (182:4d61 182:55b2 182:559f 182:558f))) 15 | (incident (memcheck-out-of-bound 31 31 32)) 16 | (incident-location (36 (200:8df7))) 17 | (incident-location (37 (200:7dc9 200:8e1a 200:8e07 200:8df7))) 18 | (incident (memcheck-out-of-bound 36 36 37)) 19 | (incident-location (41 (218:29b1 218:a25f))) 20 | (incident-location (42 (218:a2a3 218:29d0 218:29bf 218:29b1 218:a25f))) 21 | (incident (memcheck-out-of-bound 41 41 42)) 22 | (incident-location (46 (242:5d0a))) 23 | (incident-location 24 | (47 (242:921c 242:8e86 242:3236 242:48c3 242:5d2b 242:5d18 242:5d0a))) 25 | (incident (memcheck-out-of-bound 46 46 47)) 26 | (incident-location (51 (270:81d7))) 27 | (incident-location 28 | (52 (270:3526 270:5cd2 270:2820 270:81f8 270:81e5 270:81d7))) 29 | (incident (memcheck-out-of-bound 51 51 52)) 30 | (incident-location (56 (294:2795))) 31 | (incident-location (57 (294:7cee 294:9b37 294:27b6 294:27a3 294:2795))) 32 | (incident (memcheck-out-of-bound 56 56 57)) 33 | (incident-location (61 (314:36ca))) 34 | (incident-location (62 (314:288a 314:36eb 314:36d8 314:36ca))) 35 | (incident (memcheck-out-of-bound 61 61 62)) 36 | (incident-location (64 (325:37fc))) 37 | (incident-location (65 (325:37c6 325:3826 325:380a 325:37fc))) 38 | (incident (memcheck-out-of-bound 64 64 65)) 39 | (incident-location (69 (342:2048))) 40 | (incident-location (70 (342:2007 342:206d 342:2056 342:2048))) 41 | (incident (memcheck-out-of-bound 69 69 70)) 42 | (incident-location (73 (354:6b53 354:6b8a))) 43 | (incident-location (74 (354:6bce 354:6b72 354:6b61 354:6b53 354:6b8a))) 44 | (incident (memcheck-out-of-bound 73 73 74)) 45 | (incident-location (76 (368:79dc))) 46 | (incident-location (77 (368:79a6 368:79fd 368:79ea 368:79dc))) 47 | (incident (memcheck-out-of-bound 76 76 77)) 48 | (incident-location (81 (384:805a))) 49 | (incident-location (82 (384:80bf 384:8068 384:805a))) 50 | (incident (memcheck-out-of-bound 81 81 82)) 51 | (incident-location (86 (398:5018))) 52 | (incident-location (87 (398:5083 398:5026 398:5018))) 53 | (incident (memcheck-out-of-bound 86 86 87)) 54 | (incident-location (91 (412:63b7))) 55 | (incident-location (92 (412:641c 412:63c5 412:63b7))) 56 | (incident (memcheck-out-of-bound 91 91 92)) 57 | (incident-location (100 (440:5e3a 440:5e33 440:9b7b))) 58 | (incident-location 59 | (101 (440:9bbf 440:5e59 440:5e48 440:5e3a 440:5e33 440:9b7b))) 60 | (incident (memcheck-out-of-bound 100 100 101)) 61 | (incident-location (109 (471:86ea 471:86e3 471:872b))) 62 | (incident-location 63 | (110 (471:876f 471:8709 471:86f8 471:86ea 471:86e3 471:872b))) 64 | (incident (memcheck-out-of-bound 109 109 110)) 65 | (incident-location (114 (488:90c2))) 66 | (incident-location (115 (488:9117 488:90d0 488:90c2))) 67 | (incident (memcheck-out-of-bound 114 114 115)) 68 | (incident-location (119 (503:a48b 503:a4ad 503:a484))) 69 | (incident-location 70 | (120 (503:a4ea 503:a4ad 503:a4a5 503:a499 503:a48b 503:a4ad 503:a484))) 71 | (incident (memcheck-out-of-bound 119 119 120)) 72 | (incident-location (124 (518:56bd))) 73 | (incident-location (125 (518:5713 518:56cb 518:56bd))) 74 | (incident (memcheck-out-of-bound 124 124 125)) 75 | (incident-location (131 (539:64fe))) 76 | (incident-location (132 (539:6554 539:650c 539:64fe))) 77 | (incident (memcheck-out-of-bound 131 131 132)) 78 | (incident-location (140 (563:4e1d 563:4e16))) 79 | (incident-location (141 (563:4e72 563:4e2b 563:4e1d 563:4e16))) 80 | (incident (memcheck-out-of-bound 140 140 141)) 81 | (incident-location (149 (588:7adc 588:7ad5))) 82 | (incident-location (150 (588:7b31 588:7aea 588:7adc 588:7ad5))) 83 | (incident (memcheck-out-of-bound 149 149 150)) 84 | (incident-location 85 | (158 (610:978d 610:9786 608:aaae 608:1160 608:aa95 608:977f))) 86 | (incident-location 87 | (159 88 | (610:9801 610:979b 610:978d 610:9786 608:aaae 608:1160 608:aa95 608:977f))) 89 | (incident (memcheck-out-of-bound 158 158 159)) 90 | (incident-location (167 (638:22d5 638:22ce 638:aa85 638:22c7))) 91 | (incident-location 92 | (168 (638:232a 638:22e3 638:22d5 638:22ce 638:aa85 638:22c7))) 93 | (incident (memcheck-out-of-bound 167 167 168)) 94 | (incident-location (176 (664:2a21 664:2a1a))) 95 | (incident-location (177 (664:2a76 664:2a2f 664:2a21 664:2a1a))) 96 | (incident (memcheck-out-of-bound 176 176 177)) 97 | (incident-location (185 (689:7e7c 689:7e75))) 98 | (incident-location (186 (689:7ed1 689:7e8a 689:7e7c 689:7e75))) 99 | (incident (memcheck-out-of-bound 185 185 186)) 100 | (incident-location (194 (717:392e 717:3927 717:38ff 717:3920))) 101 | (incident-location 102 | (195 (717:3983 717:393c 717:392e 717:3927 717:38ff 717:3920))) 103 | (incident (memcheck-out-of-bound 194 194 195)) 104 | (incident-location (203 (744:71f9 744:71f2))) 105 | (incident-location (204 (744:724e 744:7207 744:71f9 744:71f2))) 106 | (incident (memcheck-out-of-bound 203 203 204)) 107 | (incident-location (212 (769:4b3e 769:4b37))) 108 | (incident-location (213 (769:4b93 769:4b4c 769:4b3e 769:4b37))) 109 | (incident (memcheck-out-of-bound 212 212 213)) 110 | (incident-location (221 (794:7796 794:778f))) 111 | (incident-location (222 (794:77eb 794:77a4 794:7796 794:778f))) 112 | (incident (memcheck-out-of-bound 221 221 222)) 113 | (incident-location (230 (819:5a28 819:5a21))) 114 | (incident-location (231 (819:5a7d 819:5a36 819:5a28 819:5a21))) 115 | (incident (memcheck-out-of-bound 230 230 231)) 116 | (incident-location (237 (841:8c3b))) 117 | (incident-location (238 (841:8c90 841:8c49 841:8c3b))) 118 | (incident (memcheck-out-of-bound 237 237 238)) 119 | (incident-location (244 (862:24bb))) 120 | (incident-location (245 (862:2510 862:24c9 862:24bb))) 121 | (incident (memcheck-out-of-bound 244 244 245)) 122 | (incident-location (249 (876:33cd))) 123 | (incident-location (250 (876:3422 876:33db 876:33cd))) 124 | (incident (memcheck-out-of-bound 249 249 250)) 125 | -------------------------------------------------------------------------------- /tests/artifacts/juliet-cwe-122/heap-overflow/run: -------------------------------------------------------------------------------- 1 | heap-overflow -------------------------------------------------------------------------------- /tests/artifacts/juliet-cwe-252/jpl-rule-14/run: -------------------------------------------------------------------------------- 1 | jpl-rule-14 -------------------------------------------------------------------------------- /tests/artifacts/juliet-cwe-415/double-free/run: -------------------------------------------------------------------------------- 1 | double-free -------------------------------------------------------------------------------- /tests/artifacts/juliet-cwe-416/use-after-free/run: -------------------------------------------------------------------------------- 1 | use-after-free -------------------------------------------------------------------------------- /tests/artifacts/juliet-cwe-476/av-rule-174/run: -------------------------------------------------------------------------------- 1 | av-rule-174 -------------------------------------------------------------------------------- /tests/artifacts/libgd-2.2.5/CVE-2018-1000222/run: -------------------------------------------------------------------------------- 1 | double-free:entry-points=gdImageBmpPtr:depth=50000 2 | -------------------------------------------------------------------------------- /tests/artifacts/libssh-0.5.2/CVE-2012-4559/expected: -------------------------------------------------------------------------------- 1 | (incident-location 2 | (3 3 | (1:f872 1:99fe 1:2244f 1:22445 1:22437 1:f940 1:f93c 1:f92f 1:f926 1:f91c 4 | 1:f8c6 1:f8b6 1:2242d 1:2241d 1:22357 1:33b4e 1:33ae7 1:86b0 1:33ad7 5 | 1:33ad5 1:22349 1:22332 1:f8a4 1:f89f 1:f89a 1:f880 1:f872 1:22324 1:99f5))) 6 | (incident-location 7 | (17 8 | (86:f92f 86:f926 86:f91c 86:f904 86:f8fb 86:f8ef 86:f8e0 86:f8c6 86:f8b6 9 | 86:9b1a 86:9afb 47:953c 47:952c 47:933f 47:26534 47:2652c 47:26450 10 | 47:2644e 47:26414 47:263fd 47:8620 47:263e7 47:26397 47:26350 47:9335 11 | 47:8400 47:930f 47:86b0 47:9306 47:927b 47:8fce 47:8fa0 47:8f81 47:86b0 12 | 47:8f77 47:8f75 47:86b0 47:8f6b 47:8f67 47:86b0 47:8f5d 47:8f54 47:8f48 13 | 47:8f43 47:8efa 47:8fc3 47:8ef1 47:8ee8 47:8edf 47:32c9d 47:8ecd 47:9272 14 | 47:8e9e 47:9248 47:26534 47:2652c 47:26450 47:2644e 47:26414 47:263fd 15 | 47:8620 47:263e7 47:26397 47:26350 47:9231 47:fe76 47:9203 47:91f6 47:9af4 16 | 47:9adc 47:f8a4 47:f89f 47:f89a 47:f880 47:f872 47:9ace 47:33d51 47:33d39 17 | 47:9ac9 47:9abc 47:fbd1 47:fbcb 47:fbc2 47:fb47 47:fb41 47:fb29 47:fac9 18 | 47:fbbb 47:9ab5 47:8b00 47:9aa5 47:9a9a 1:fe49 1:9a7e 1:9a71 1:fbd1 1:fbcb 19 | 1:fbc2 1:fb47 1:fb41 1:fb29 1:fb00 1:f9b7 1:f9b1 1:f993 1:f985 1:f96a 20 | 1:f961 1:f96a 1:f961 1:f96a 1:f961 1:f96a 1:f961 1:f96a 1:f95f 1:faf9 21 | 1:fad4 1:fac9 1:fbbb 1:9a6a 1:8b00 1:9a5a 1:fe76 1:9a4d 1:9a40 1:fb98 22 | 1:fb92 1:fb89 1:fb47 1:fb41 1:fb29 1:fb00 1:f9b7 1:f9b1 1:f993 1:f985 23 | 1:f96a 1:f961 1:f96a 1:f961 1:f96a 1:f961 1:f96a 1:f95f 1:faf9 1:fad4 24 | 1:fac9 1:fb82 1:33b80 1:33b6e 1:8320 1:33b67 1:33b60 1:fb66 1:9a39 1:9a25 25 | 1:fc82 1:fc7c 1:fc73 1:fb47 1:fb41 1:fb29 1:fb00 1:f9b7 1:f9b1 1:f993 26 | 1:f985 1:f96a 1:f961 1:f96a 1:f95f 1:faf9 1:fad4 1:fac9 1:fc6c 1:9a1e 27 | 1:9a0c 1:f8a4 1:f89f 1:f89a 1:f880 1:f872 1:99fe 1:2244f 1:22445 1:22437 28 | 1:f940 1:f93c 1:f92f 1:f926 1:f91c 1:f8c6 1:f8b6 1:2242d 1:2241d 1:22357 29 | 1:33b4e 1:33ae7 1:86b0 1:33ad7 1:33ad5 1:22349 1:22332 1:f8a4 1:f89f 30 | 1:f89a 1:f880 1:f872 1:22324 1:99f5))) 31 | (incident-location 32 | (18 33 | (86:f92f 86:f926 86:f91c 86:f904 86:f8fb 86:f8ef 86:f8e0 86:f8c6 86:f8b6 34 | 86:9c2b 86:33d51 86:33d39 86:9c1f 86:1e20e 86:26534 86:2652c 86:26450 35 | 86:2644e 86:26414 86:263fd 86:8620 86:263e7 86:26397 86:26350 86:1e207 36 | 86:8620 86:1e1ca 86:1e149 86:9c13 86:9bfa 86:9b35 86:ffc9 86:ff9f 86:ff61 37 | 86:ff5a 86:ff43 86:ffc3 86:9b2d 86:f940 86:f93c 86:f92f 86:f926 86:f91c 38 | 86:f904 86:f8fb 86:f8ef 86:f8e0 86:f8c6 86:f8b6 86:9b1a 86:9afb 47:953c 39 | 47:952c 47:933f 47:26534 47:2652c 47:26450 47:2644e 47:26414 47:263fd 40 | 47:8620 47:263e7 47:26397 47:26350 47:9335 47:8400 47:930f 47:86b0 47:9306 41 | 47:927b 47:8fce 47:8fa0 47:8f81 47:86b0 47:8f77 47:8f75 47:86b0 47:8f6b 42 | 47:8f67 47:86b0 47:8f5d 47:8f54 47:8f48 47:8f43 47:8efa 47:8fc3 47:8ef1 43 | 47:8ee8 47:8edf 47:32c9d 47:8ecd 47:9272 47:8e9e 47:9248 47:26534 47:2652c 44 | 47:26450 47:2644e 47:26414 47:263fd 47:8620 47:263e7 47:26397 47:26350 45 | 47:9231 47:fe76 47:9203 47:91f6 47:9af4 47:9adc 47:f8a4 47:f89f 47:f89a 46 | 47:f880 47:f872 47:9ace 47:33d51 47:33d39 47:9ac9 47:9abc 47:fbd1 47:fbcb 47 | 47:fbc2 47:fb47 47:fb41 47:fb29 47:fac9 47:fbbb 47:9ab5 47:8b00 47:9aa5 48 | 47:9a9a 1:fe49 1:9a7e 1:9a71 1:fbd1 1:fbcb 1:fbc2 1:fb47 1:fb41 1:fb29 49 | 1:fb00 1:f9b7 1:f9b1 1:f993 1:f985 1:f96a 1:f961 1:f96a 1:f961 1:f96a 50 | 1:f961 1:f96a 1:f961 1:f96a 1:f95f 1:faf9 1:fad4 1:fac9 1:fbbb 1:9a6a 51 | 1:8b00 1:9a5a 1:fe76 1:9a4d 1:9a40 1:fb98 1:fb92 1:fb89 1:fb47 1:fb41 52 | 1:fb29 1:fb00 1:f9b7 1:f9b1 1:f993 1:f985 1:f96a 1:f961 1:f96a 1:f961 53 | 1:f96a 1:f961 1:f96a 1:f95f 1:faf9 1:fad4 1:fac9 1:fb82 1:33b80 1:33b6e 54 | 1:8320 1:33b67 1:33b60 1:fb66 1:9a39 1:9a25 1:fc82 1:fc7c 1:fc73 1:fb47 55 | 1:fb41 1:fb29 1:fb00 1:f9b7 1:f9b1 1:f993 1:f985 1:f96a 1:f961 1:f96a 56 | 1:f95f 1:faf9 1:fad4 1:fac9 1:fc6c 1:9a1e 1:9a0c 1:f8a4 1:f89f 1:f89a 57 | 1:f880 1:f872 1:99fe 1:2244f 1:22445 1:22437 1:f940 1:f93c 1:f92f 1:f926 58 | 1:f91c 1:f8c6 1:f8b6 1:2242d 1:2241d 1:22357 1:33b4e 1:33ae7 1:86b0 59 | 1:33ad7 1:33ad5 1:22349 1:22332 1:f8a4 1:f89f 1:f89a 1:f880 1:f872 1:22324 60 | 1:99f5))) 61 | (incident (memcheck-double-release 3 17 18)) 62 | -------------------------------------------------------------------------------- /tests/artifacts/libssh-0.5.2/CVE-2012-4559/run: -------------------------------------------------------------------------------- 1 | double-free:entry-points=agent_sign_data:depth=50000 -------------------------------------------------------------------------------- /tests/artifacts/libssh-0.5.2/CVE-2012-6063/expected: -------------------------------------------------------------------------------- 1 | (incident-location (1 (1:f872 1:3b355))) 2 | (incident-location 3 | (12 4 | (10:f92f 10:f926 10:f91c 10:f904 10:f8fb 10:f8ef 10:f8e0 10:f8c6 10:f8b6 5 | 10:3b48e 10:3b482 10:35cde 10:35c88 10:35c81 10:13aec 10:13aae 10:1369c 6 | 10:26534 10:2652c 10:26450 10:2644e 10:26414 10:263fd 10:8620 10:263e7 7 | 10:26397 10:26350 10:13692 10:13654 10:1e20e 10:26534 10:2652c 10:26450 8 | 10:2644e 10:26414 10:263fd 10:8620 10:263e7 10:26397 10:26350 10:1e207 9 | 10:8620 10:1e1ca 10:1e149 10:13642 10:13611 10:135ef 10:135e6 10:2fa8a 10 | 10:135df 10:135d2 10:26534 10:2652c 10:26450 10:2644e 10:26414 10:263fd 11 | 10:8620 10:263e7 10:26397 10:26350 10:135bc 10:13595 10:1355a 10:13536 12 | 10:1351a 10:13513 10:13ae6 10:35c74 10:fe49 10:35c5c 10:fe76 10:35c4e 13 | 10:35c2c 10:fdc5 10:fdbf 10:fd91 10:fd78 10:fd05 10:fca0 10:35c25 10:8b00 14 | 10:35c0a 10:fe76 10:35c03 10:35be1 10:fdc5 10:fdbf 10:fd91 10:fd78 10:fd2e 15 | 10:f9b7 10:f9b1 10:f993 10:f985 10:f96a 10:f961 10:f96a 10:f961 10:f96a 16 | 10:f961 10:f96a 10:f961 10:f96a 10:f961 10:f96a 10:f95f 10:fd27 10:fd05 17 | 10:fca0 10:35bda 10:3b47b 10:3b463 10:3908e 10:39088 10:3903b 10:3902a 18 | 10:fbd1 10:fbcb 10:fbc2 10:fb47 10:fb41 10:fb29 10:fac9 10:fbbb 10:39023 19 | 10:8b00 10:39013 10:39008 10:38fb0 10:38f76 10:38f68 10:38f57 10:fbd1 20 | 10:fbcb 10:fbc2 10:fb47 10:fb41 10:fb29 10:fb00 10:f9b7 10:f9b1 10:f993 21 | 10:f985 10:f96a 10:f961 10:f96a 10:f961 10:f96a 10:f961 10:f96a 10:f961 22 | 10:f96a 10:f95f 10:faf9 10:fad4 10:fac9 10:fbbb 10:38f50 10:8b00 10:38f40 23 | 10:38f2d 10:38f24 10:3b45c 10:3b446 10:fb98 10:fb92 10:fb89 10:fb47 24 | 10:fb41 10:fb29 10:fac9 10:fb82 10:33b80 10:33b6e 10:8320 10:33b67 25 | 10:33b60 10:fb66 10:3b43f 10:3b429 10:fbd1 10:fbcb 10:fbc2 10:fb47 10:fb41 26 | 10:fb29 10:fb00 10:f9b7 10:f9b1 10:f993 10:f985 10:f96a 10:f961 10:f96a 27 | 10:f961 10:f96a 10:f961 10:f96a 10:f95f 10:faf9 10:fad4 10:fac9 10:fbbb 28 | 10:3b422 10:379c2 10:3b405 10:3b3e6 10:3b3a5 1:33b4e 1:33ae7 1:86b0 29 | 1:33ad7 1:33ad5 1:3b391 1:3b369 1:f8a4 1:f89f 1:f89a 1:f880 1:f872 30 | 1:3b355))) 31 | (incident-location 32 | (13 33 | (10:f92f 10:f926 10:f91c 10:f904 10:f8fb 10:f8ef 10:f8e0 10:f8c6 10:f8b6 34 | 10:3b4ac 10:33d51 10:33d39 10:3b49d 10:f940 10:f93c 10:f92f 10:f926 35 | 10:f91c 10:f904 10:f8fb 10:f8ef 10:f8e0 10:f8c6 10:f8b6 10:3b48e 10:3b482 36 | 10:35cde 10:35c88 10:35c81 10:13aec 10:13aae 10:1369c 10:26534 10:2652c 37 | 10:26450 10:2644e 10:26414 10:263fd 10:8620 10:263e7 10:26397 10:26350 38 | 10:13692 10:13654 10:1e20e 10:26534 10:2652c 10:26450 10:2644e 10:26414 39 | 10:263fd 10:8620 10:263e7 10:26397 10:26350 10:1e207 10:8620 10:1e1ca 40 | 10:1e149 10:13642 10:13611 10:135ef 10:135e6 10:2fa8a 10:135df 10:135d2 41 | 10:26534 10:2652c 10:26450 10:2644e 10:26414 10:263fd 10:8620 10:263e7 42 | 10:26397 10:26350 10:135bc 10:13595 10:1355a 10:13536 10:1351a 10:13513 43 | 10:13ae6 10:35c74 10:fe49 10:35c5c 10:fe76 10:35c4e 10:35c2c 10:fdc5 44 | 10:fdbf 10:fd91 10:fd78 10:fd05 10:fca0 10:35c25 10:8b00 10:35c0a 10:fe76 45 | 10:35c03 10:35be1 10:fdc5 10:fdbf 10:fd91 10:fd78 10:fd2e 10:f9b7 10:f9b1 46 | 10:f993 10:f985 10:f96a 10:f961 10:f96a 10:f961 10:f96a 10:f961 10:f96a 47 | 10:f961 10:f96a 10:f961 10:f96a 10:f95f 10:fd27 10:fd05 10:fca0 10:35bda 48 | 10:3b47b 10:3b463 10:3908e 10:39088 10:3903b 10:3902a 10:fbd1 10:fbcb 49 | 10:fbc2 10:fb47 10:fb41 10:fb29 10:fac9 10:fbbb 10:39023 10:8b00 10:39013 50 | 10:39008 10:38fb0 10:38f76 10:38f68 10:38f57 10:fbd1 10:fbcb 10:fbc2 51 | 10:fb47 10:fb41 10:fb29 10:fb00 10:f9b7 10:f9b1 10:f993 10:f985 10:f96a 52 | 10:f961 10:f96a 10:f961 10:f96a 10:f961 10:f96a 10:f961 10:f96a 10:f95f 53 | 10:faf9 10:fad4 10:fac9 10:fbbb 10:38f50 10:8b00 10:38f40 10:38f2d 54 | 10:38f24 10:3b45c 10:3b446 10:fb98 10:fb92 10:fb89 10:fb47 10:fb41 10:fb29 55 | 10:fac9 10:fb82 10:33b80 10:33b6e 10:8320 10:33b67 10:33b60 10:fb66 56 | 10:3b43f 10:3b429 10:fbd1 10:fbcb 10:fbc2 10:fb47 10:fb41 10:fb29 10:fb00 57 | 10:f9b7 10:f9b1 10:f993 10:f985 10:f96a 10:f961 10:f96a 10:f961 10:f96a 58 | 10:f961 10:f96a 10:f95f 10:faf9 10:fad4 10:fac9 10:fbbb 10:3b422 10:379c2 59 | 10:3b405 10:3b3e6 10:3b3a5 1:33b4e 1:33ae7 1:86b0 1:33ad7 1:33ad5 1:3b391 60 | 1:3b369 1:f8a4 1:f89f 1:f89a 1:f880 1:f872 1:3b355))) 61 | (incident (memcheck-double-release 1 12 13)) 62 | -------------------------------------------------------------------------------- /tests/artifacts/libssh-0.5.2/CVE-2012-6063/run: -------------------------------------------------------------------------------- 1 | double-free:entry-points=sftp_mkdir:depth=8192 2 | -------------------------------------------------------------------------------- /tests/artifacts/ntpd-4.2.8p12/CVE-2019-8936/expected: -------------------------------------------------------------------------------- 1 | 2 | (incident-location (50119 3 | (611:230f0 611:230cd 608:230c4 608:230d8 608:230b7 4 | 608:230af 7:230a3 7:2305a 7:23049 7:23047 7:2303a 5 | 7:23038 1:28ce7 1:27859 1:27853 1:27803 1:28cc5 1:28cbf))) 6 | (incident-location (50129 7 | (622:28e01 622:28dfa 622:28cfe 622:28cf5 622:28cef 8 | 622:23096 622:23082 622:23245 622:2322e 619:23229 9 | 619:23225 619:2320a 619:23203 611:231ff 611:231fb 10 | 611:231ef 611:231eb 611:231ef 611:231de 611:231d6 11 | 611:231c9 611:23263 611:230fb 611:230cd 608:230c4 12 | 608:230d8 608:230b7 608:230af 7:230a3 7:2305a 7:23049 13 | 7:23047 7:2303a 7:23038 1:28ce7 1:27859 1:27853 1:27803 14 | 1:28cc5 1:28cbf))) 15 | (incident (null-ptr-deref 50129 50119)) 16 | -------------------------------------------------------------------------------- /tests/artifacts/ntpd-4.2.8p12/CVE-2019-8936/run: -------------------------------------------------------------------------------- 1 | av-rule-174:entry-points=write_variables:depth=15000 -------------------------------------------------------------------------------- /tests/artifacts/tcpreplay-4.3.1/CVE-2019-8377/expected: -------------------------------------------------------------------------------- 1 | (incident-location (15 2 | (17:408eb0 17:408e6a 13:408e5b 13:408e48 13:408e3e 3 | 10:408e33 10:409020 10:409019 10:409013 10:40902b 4 | 10:409006 10:408ffd 10:409046 6:409019 6:409013 6:40902b 5 | 1:409006 1:408ffd 1:408ff2 1:408fe8 1:408fc4 1:401d00 6 | 1:408fbf 1:408ee1 1:408ed6))) 7 | (incident-location (16 8 | (17:409025 17:408eb2 17:408e6a 13:408e5b 13:408e48 9 | 13:408e3e 10:408e33 10:409020 10:409019 10:409013 10 | 10:40902b 10:409006 10:408ffd 10:409046 6:409019 11 | 6:409013 6:40902b 1:409006 1:408ffd 1:408ff2 1:408fe8 12 | 1:408fc4 1:401d00 1:408fbf 1:408ee1 1:408ed6))) 13 | (incident (null-ptr-deref 16 15)) 14 | -------------------------------------------------------------------------------- /tests/artifacts/tcpreplay-4.3.1/CVE-2019-8377/run: -------------------------------------------------------------------------------- 1 | av-rule-174:entry-points=get_layer4_v6:depth=16000 -------------------------------------------------------------------------------- /tests/copy_artifacts.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | ENDPOINT=https://registry.hub.docker.com/v2/repositories/binaryanalysisplatform/bap-artifacts/tags 4 | TAGS=$(curl -L $ENDPOINT) 5 | 6 | 7 | for name in `ls artifacts/`; do 8 | arti=artifacts/$name 9 | tag_exists=$(echo $TAGS | jq 'any(.results[].name; . == $x)' --arg x $name) 10 | echo "tag $name exists = $tag_exists" 11 | if [ ! -f $arti/artifact ] && [ "checked_$tag_exists" = "checked_true" ]; then 12 | docker run --rm -v `pwd`/$arti:/drive binaryanalysisplatform/bap-artifacts:$name cp /artifact /drive 13 | else 14 | echo "skipping $name" 15 | fi 16 | 17 | done 18 | -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-17: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-17 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-174: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-174 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-189: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-189 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-19: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-19 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-20: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-20 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-21: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-21 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-22: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-22 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-23: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-23 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-24: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-24 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-25: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-25 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/av-rule-3: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/av-rule-3 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/double-free: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/double-free -------------------------------------------------------------------------------- /tests/litmus-tests/bin/heap-overflow: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/heap-overflow -------------------------------------------------------------------------------- /tests/litmus-tests/bin/jpl-rule-14: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/jpl-rule-14 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/jpl-rule-4: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/jpl-rule-4 -------------------------------------------------------------------------------- /tests/litmus-tests/bin/must-check-value: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/must-check-value -------------------------------------------------------------------------------- /tests/litmus-tests/bin/restrictness-check: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/restrictness-check -------------------------------------------------------------------------------- /tests/litmus-tests/bin/untrusted-argument: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/untrusted-argument -------------------------------------------------------------------------------- /tests/litmus-tests/bin/use-after-free: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/use-after-free -------------------------------------------------------------------------------- /tests/litmus-tests/bin/warn-unused: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/tests/litmus-tests/bin/warn-unused -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-17/expected: -------------------------------------------------------------------------------- 1 | (incident-static (forbidden-function __errno_location)) 2 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-174/expected: -------------------------------------------------------------------------------- 1 | (incident-location (1 2 | (1:400500 1:40052e 1:4004fb 1:4004ee 1:400524 1:400404))) 3 | (incident-location (2 4 | (1:400513 1:40052e 1:4004fb 1:4004ee 1:400524 1:400404))) 5 | (incident (null-ptr-deref 2 1)) 6 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-189/expected: -------------------------------------------------------------------------------- 1 | (incident-static (non-structural-cfg bad 0x4005a6)) 2 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-19/expected: -------------------------------------------------------------------------------- 1 | (incident-static (forbidden-function setlocale)) 2 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-20/expected: -------------------------------------------------------------------------------- 1 | (incident-static (forbidden-function longjmp)) 2 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-21/expected: -------------------------------------------------------------------------------- 1 | (incident-static (forbidden-function raise)) 2 | (incident-static (forbidden-function signal)) 3 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-22/expected: -------------------------------------------------------------------------------- 1 | (incident-static (forbidden-function clearerr)) 2 | (incident-static (forbidden-function fclose)) 3 | (incident-static (forbidden-function feof)) 4 | (incident-static (forbidden-function ferror)) 5 | (incident-static (forbidden-function fflush)) 6 | (incident-static (forbidden-function fgetc)) 7 | (incident-static (forbidden-function fgetpos)) 8 | (incident-static (forbidden-function fgets)) 9 | (incident-static (forbidden-function fopen)) 10 | (incident-static (forbidden-function fprintf)) 11 | (incident-static (forbidden-function fputc)) 12 | (incident-static (forbidden-function fread)) 13 | (incident-static (forbidden-function freopen)) 14 | (incident-static (forbidden-function fseek)) 15 | (incident-static (forbidden-function fsetpos)) 16 | (incident-static (forbidden-function ftell)) 17 | (incident-static (forbidden-function fwrite)) 18 | (incident-static (forbidden-function getchar)) 19 | (incident-static (forbidden-function perror)) 20 | (incident-static (forbidden-function putchar)) 21 | (incident-static (forbidden-function puts)) 22 | (incident-static (forbidden-function remove)) 23 | (incident-static (forbidden-function rename)) 24 | (incident-static (forbidden-function rewind)) 25 | (incident-static (forbidden-function setbuf)) 26 | (incident-static (forbidden-function setvbuf)) 27 | (incident-static (forbidden-function tmpfile)) 28 | (incident-static (forbidden-function tmpnam)) 29 | (incident-static (forbidden-function ungetc)) 30 | (incident-static (forbidden-function vfprintf)) 31 | (incident-static (forbidden-function vprintf)) 32 | (incident-static (forbidden-function vsprintf)) 33 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-23/expected: -------------------------------------------------------------------------------- 1 | (incident-static (forbidden-function atof)) 2 | (incident-static (forbidden-function atoi)) 3 | (incident-static (forbidden-function atol)) 4 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-24/expected: -------------------------------------------------------------------------------- 1 | (incident-static (forbidden-function abort)) 2 | (incident-static (forbidden-function exit)) 3 | (incident-static (forbidden-function getenv)) 4 | (incident-static (forbidden-function system)) 5 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-25/expected: -------------------------------------------------------------------------------- 1 | (incident-static (forbidden-function asctime)) 2 | (incident-static (forbidden-function clock)) 3 | (incident-static (forbidden-function ctime)) 4 | (incident-static (forbidden-function difftime)) 5 | (incident-static (forbidden-function gmtime)) 6 | (incident-static (forbidden-function localtime)) 7 | (incident-static (forbidden-function mktime)) 8 | (incident-static (forbidden-function strftime)) 9 | (incident-static (forbidden-function time)) 10 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/av-rule-3/expected: -------------------------------------------------------------------------------- 1 | (incident-static (complex-function bad 0x40067e)) 2 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/double-free/expected: -------------------------------------------------------------------------------- 1 | (incident-location 2 | (1 3 | (1:4005af 1:4005f0 1:4005a1 1:400592 1:40058d 1:400584 1:400573 1:4005e6 4 | 1:400494))) 5 | (incident-location 6 | (2 7 | (1:4005c9 1:4005c0 1:4005af 1:4005f0 1:4005a1 1:400592 1:40058d 1:400584 8 | 1:400573 1:4005e6 1:400494))) 9 | (incident-location 10 | (3 11 | (1:4005d5 1:4005c9 1:4005c0 1:4005af 1:4005f0 1:4005a1 1:400592 1:40058d 12 | 1:400584 1:400573 1:4005e6 1:400494))) 13 | (incident (memcheck-double-release 1 2 3)) 14 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/heap-overflow/expected: -------------------------------------------------------------------------------- 1 | (incident-location (3 (1:40072e 1:40071e 1:400594))) 2 | (incident-location (7 3 | (1:4006b4 1:40075c 1:400693 1:40068c 1:400749 1:40072e 4 | 1:40071e 1:400594))) 5 | (incident (memcheck-out-of-bound 3 3 7)) 6 | (incident-location (8 7 | (1:4006f7 1:400773 1:4006d0 1:4006c2 1:4006b4 1:40075c 8 | 1:400693 1:40068c 1:400749 1:40072e 1:40071e 1:400594))) 9 | (incident (memcheck-out-of-bound 3 3 8)) 10 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/jpl-rule-14/expected: -------------------------------------------------------------------------------- 1 | (incident-location (4 2 | (5:4005a5 5:4005c3 5:400592 5:400584 1:400430 1:400578 3 | 1:4005b9 1:400494))) 4 | (incident (unused-return-value 4)) 5 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/jpl-rule-4/expected: -------------------------------------------------------------------------------- 1 | (incident-static (recursive-function bad 0x400526)) 2 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/must-check-value/expected: -------------------------------------------------------------------------------- 1 | (incident-location (10 2 | (1:400689 1:400710 1:4006fc 1:4006e9 1:400510 1:4006dd 3 | 1:400706 1:400594))) 4 | (incident (value-was-not-checked 10)) 5 | (incident-location (46 6 | (5:40069b 5:400691 5:400540 5:400689 5:400710 5:4006fc 7 | 5:400530 5:4006f5 5:4006e9 1:400510 1:4006dd 1:400706 8 | 1:400594))) 9 | (incident-location (49 10 | (5:4006ac 5:400510 5:40069b 5:400691 5:400540 5:400689 11 | 5:400710 5:4006fc 5:400530 5:4006f5 5:4006e9 1:400510 12 | 1:4006dd 1:400706 1:400594))) 13 | (incident (value-was-not-checked 46)) 14 | (incident (value-was-not-checked 49)) 15 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/restrictness-check/api/c/myapi.h: -------------------------------------------------------------------------------- 1 | 2 | int foo(int * restrict r, int * s); 3 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/restrictness-check/expected: -------------------------------------------------------------------------------- 1 | (incident-location (4 2 | (6:4006c5 6:400752 6:400698 6:4004e0 6:400692 6:400690 3 | 1:4004f0 1:40067d 1:400638 1:40066c 1:400748 1:400554))) 4 | (incident (restrictness-violation 4)) 5 | (incident-location (5 6 | (6:40071a 6:4006ff 6:40075c 6:4006f1 6:4006e9 6:4004f0 7 | 6:4006d6 6:400638 6:4006c5 6:400752 6:400698 6:4004e0 8 | 6:400692 6:400690 1:4004f0 1:40067d 1:400638 1:40066c 9 | 1:400748 1:400554))) 10 | (incident (restrictness-violation 5)) 11 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/untrusted-argument/expected: -------------------------------------------------------------------------------- 1 | (incident-location (5 (1:6d9 1:753 1:73f 1:73d 1:71c 1:710 1:749 1:5e4))) 2 | (incident-location (6 (1:6e9 1:6d9 1:753 1:73f 1:73d 1:71c 1:710 1:749 1:5e4))) 3 | (incident (unchecked-untrusted-argument 6 5)) -------------------------------------------------------------------------------- /tests/litmus-tests/data/use-after-free/expected: -------------------------------------------------------------------------------- 1 | (incident-location 2 | (1 3 | (1:40060a 1:400656 1:4005fc 1:4005e2 1:4005dd 1:4005d4 1:4005c3 1:40064c 4 | 1:4004e4))) 5 | (incident-location 6 | (2 7 | (1:400624 1:40061b 1:40060a 1:400656 1:4005fc 1:4005e2 1:4005dd 1:4005d4 8 | 1:4005c3 1:40064c 1:4004e4))) 9 | (incident-location 10 | (3 11 | (1:40062d 1:400624 1:40061b 1:40060a 1:400656 1:4005fc 1:4005e2 1:4005dd 12 | 1:4005d4 1:4005c3 1:40064c 1:4004e4))) 13 | (incident (memcheck-use-after-release 1 2 3)) 14 | -------------------------------------------------------------------------------- /tests/litmus-tests/data/warn-unused/expected: -------------------------------------------------------------------------------- 1 | (incident-location 2 | (3 3 | (1:40060f 1:4004a0 1:40060f 1:400671 1:400601 1:4005fd 1:4005f8 1:4005f1 4 | 1:4004a0 1:4005e5 1:400667 1:4005d7 1:4005d0 1:4004a0 1:4005c3 1:40065d 5 | 1:4004e4))) 6 | (incident-location 7 | (4 8 | (1:40063f 1:4004a0 1:40063f 1:40067b 1:400619 1:4004a0 1:40060f 1:400671 9 | 1:400601 1:4005fd 1:4005f8 1:4005f1 1:4004a0 1:4005e5 1:400667 1:4005d7 10 | 1:4005d0 1:4004a0 1:4005c3 1:40065d 1:4004e4))) 11 | (incident (warn-unused-result 3)) 12 | (incident (warn-unused-result 4)) 13 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-17.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void bad() { 6 | FILE * fp; 7 | fp = fopen("file-not-exists.txt", "r"); 8 | printf("Errno: %d\n ", errno); 9 | } 10 | 11 | 12 | int main() { 13 | bad(); 14 | return 0; 15 | } 16 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-174.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | void good() { 4 | int *x = NULL; 5 | int b = 0; 6 | if (!x) 7 | b = *x; 8 | } 9 | 10 | void bad() { 11 | int *x = NULL; 12 | int b = 0; 13 | b = *x; 14 | } 15 | 16 | int main() { 17 | good(); 18 | bad(); 19 | return 0; 20 | } 21 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-189.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void bad(int argc, char **argv) { 5 | int optind = 3; 6 | 7 | if (argc <= optind) { 8 | argv[2] = "y"; 9 | } 10 | 11 | while (1) { 12 | int i; 13 | for (i = optind; i < argc; i++) 14 | if (fputs (argv[i], stdout) == EOF) 15 | printf("error!\n"); 16 | } 17 | } 18 | 19 | 20 | int main(int argc, char **argv) { 21 | bad(argc,argv); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-19.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void bad () { 6 | setlocale(LC_MESSAGES, "de_DE.utf8"); 7 | } 8 | 9 | int main() { 10 | bad(); 11 | return 0; 12 | } 13 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-20.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | jmp_buf buf; 7 | 8 | void fun(int n) { 9 | printf("%d\n", n); 10 | longjmp(buf, n + 1); 11 | } 12 | 13 | void bad () { 14 | int i = 0; 15 | if (setjmp(buf) != 5) { 16 | fun(++i); 17 | } 18 | } 19 | 20 | int main() { 21 | bad(); 22 | return 0; 23 | } 24 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-21.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void sighandler(int signum) { 6 | printf("Caught signal %d\n", signum); 7 | exit(0); 8 | } 9 | 10 | void bad (int n) { 11 | if (n > 10) 12 | raise(SIGINT); 13 | } 14 | 15 | int main() { 16 | signal(SIGINT, sighandler); 17 | bad(42); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-22.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | 6 | void with_file() { 7 | char buf[10]; 8 | 9 | FILE *f = fopen("foo.txt", "rw"); 10 | rewind(f); 11 | fprintf(f,"ff %d", 42); 12 | int p = ftell(f); 13 | fseek(f,p, SEEK_END); 14 | fread(buf, 1, 3, f); 15 | fwrite(buf, 1, 3, f); 16 | fputc('f',f); 17 | fputs("foo",f); 18 | fgetc(f); 19 | fgets(buf,2,f); 20 | 21 | fclose(f); 22 | f = freopen("foo.txt", "rw", f); 23 | char buffer[BUFSIZ]; 24 | setbuf (f, buffer); 25 | setvbuf (f, buffer, _IOFBF , 1024); 26 | fpos_t pos; 27 | fgetpos(f, &pos); 28 | fsetpos(f, &pos); 29 | fscanf(f, buf, "%s"); 30 | 31 | feof(f); 32 | ferror(f); 33 | clearerr(f); 34 | fflush(f); 35 | rename("foo.txt", "bar.txt"); 36 | remove("bar.txt"); 37 | fclose(f); 38 | } 39 | 40 | void with_va_list ( const char * format, ... ) { 41 | char buf[10]; 42 | va_list args; 43 | va_start (args, format); 44 | vprintf (format, args); 45 | vsprintf(buf, format, args); 46 | 47 | FILE *f = fopen("bar.txt", "rw"); 48 | vfprintf(f, format, args); 49 | fclose(f); 50 | 51 | va_end (args); 52 | } 53 | 54 | void with_io() { 55 | char buf[10]; 56 | 57 | printf("foo\n"); 58 | sprintf("foo, %s", "aa"); 59 | 60 | putc('b', stdout); 61 | puts("bar"); 62 | putchar('a'); 63 | char a = getc(stdin); 64 | ungetc(a,stdout); 65 | getchar(); 66 | 67 | char c; 68 | sscanf(buf, "%c", &c); 69 | scanf(buf, "%c", &c); 70 | perror("BUG!\n"); 71 | } 72 | 73 | void bad () { 74 | with_file(); 75 | with_va_list("%s, %s", "foo", "bar"); 76 | with_io(); 77 | 78 | char buf[10]; 79 | char *c = tmpnam(buf); 80 | FILE *f = tmpfile(); 81 | } 82 | 83 | int main() { 84 | bad(); 85 | return 0; 86 | } 87 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-23.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void bad () { 5 | int x = atoi("42"); 6 | float y = atof("42.2"); 7 | long z = atol("42"); 8 | } 9 | 10 | int main() { 11 | bad(); 12 | return 0; 13 | } 14 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-24.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void bad (int x) { 5 | if (x > 10) 6 | abort(); 7 | if (x > 5) 8 | exit(1); 9 | 10 | char buf[10]; 11 | 12 | char *a = getenv("AA"); 13 | system("echo"); 14 | } 15 | 16 | int main() { 17 | bad(2); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-25.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void bad () { 6 | time_t timer; 7 | time(&timer); 8 | struct tm y2k = {0}; 9 | y2k.tm_hour = 0; y2k.tm_min = 0; y2k.tm_sec = 0; 10 | y2k.tm_year = 100; y2k.tm_mon = 0; y2k.tm_mday = 1; 11 | int seconds = difftime(timer,mktime(&y2k)); 12 | 13 | struct tm *loc, *gmt; 14 | loc = localtime (&timer); 15 | gmt = gmtime(&timer); 16 | char *ta = ctime(&timer); 17 | char *tb = asctime(loc); 18 | char buf[20]; 19 | 20 | strftime (buf,20,"Now it's %I:%M%p.", loc); 21 | 22 | clock_t t; 23 | t = clock(); 24 | } 25 | 26 | int main() { 27 | bad(); 28 | return 0; 29 | } 30 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/av-rule-3.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | #define GT(x, y, code) \ 6 | if (x > y) { \ 7 | code; \ 8 | } \ 9 | 10 | #define GT_PLUS_5(x, y, code) \ 11 | GT(x, y, GT(x, y + 1, GT(x, y + 2, GT(x, y + 3, GT(x, y + 4, code))))) 12 | 13 | #define GT_PLUS_10(x, y, code) \ 14 | GT_PLUS_5(x, y, GT_PLUS_5(x, y + 5, code)) 15 | 16 | 17 | void good(int x) { 18 | GT_PLUS_10(x, 0, 19 | GT_PLUS_10(x, 10, 20 | GT_PLUS_10(x, 20, 21 | GT_PLUS_10(x, 30, 22 | printf("ok!\n"))))); 23 | } 24 | 25 | void bad(int x) { 26 | GT_PLUS_10(x, 0, 27 | GT_PLUS_10(x, 10, 28 | GT_PLUS_10(x, 20, 29 | GT_PLUS_10(x, 30, 30 | GT_PLUS_10(x, 40, 31 | printf("ok!\n")))))); 32 | } 33 | 34 | 35 | int main() { 36 | good(42); 37 | bad(42); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/double-free.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | static int MyTrue = 1; 4 | 5 | void good() { 6 | int *p = malloc(42); 7 | if (MyTrue) { 8 | free(p); 9 | return; 10 | } 11 | free(p); 12 | } 13 | 14 | void bad() { 15 | int *p = malloc(42); 16 | if (MyTrue) { 17 | free(p); 18 | } 19 | free(p); 20 | } 21 | 22 | int main() { 23 | good(); 24 | bad(); 25 | return 0; 26 | } 27 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/heap-overflow.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | void good(const int *src, int *dst, size_t len) { 6 | memcpy(dst, src, len); 7 | } 8 | 9 | void bad_read(const int *q, size_t len) { 10 | void *p = memchr(q, 1, len); 11 | if (!p) 12 | printf("Not found!\n"); 13 | } 14 | 15 | void bad_write(const int *src, int *dst, size_t len) { 16 | memcpy(dst, src, len); 17 | } 18 | 19 | int main() { 20 | size_t big = 42; 21 | size_t small = 41; 22 | int *src = malloc(big); 23 | int *dst = malloc(small); 24 | good(src, dst, small); 25 | bad_read(dst, big); 26 | bad_write(src, dst, big); 27 | free(src); 28 | free(dst); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/jpl-rule-14.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void good() { 5 | int x = printf("good"); 6 | if (x != 4) { 7 | exit(1); 8 | } 9 | } 10 | 11 | void bad() { 12 | int x = printf("bad!\n"); 13 | } 14 | 15 | int main() { 16 | good(); 17 | bad(); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/jpl-rule-4.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | 5 | int bad(int n) { 6 | if (n < 0) 7 | bad(n + 1); 8 | printf("%d\n", n); 9 | } 10 | 11 | int main() { 12 | bad (42); 13 | return 0; 14 | } 15 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/must-check-value.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | #include 5 | 6 | void bad() { 7 | char s[100]; 8 | printf("%s\n", getcwd(s, 100)); 9 | 10 | chdir(".."); 11 | printf("%s\n", getcwd(s, 100)); 12 | } 13 | 14 | void good() { 15 | int x = chdir(".."); 16 | if (x == -1) 17 | printf("failed to change dir"); 18 | } 19 | 20 | int main() { 21 | good (); 22 | bad(); 23 | return 0; 24 | } 25 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/restrictness-check.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | int foo(int * restrict r, int * q) { 5 | return 42; 6 | } 7 | 8 | void good() { 9 | int a = 4; 10 | int b = 2; 11 | printf("%d\n", foo(&a, &b)); 12 | } 13 | 14 | void bad1() { 15 | int a = 4; 16 | printf("%d\n", foo(&a, &a)); 17 | } 18 | 19 | void bad2() { 20 | int * ptr = malloc(10); 21 | printf("%d\n", foo(ptr, ptr + 2)); 22 | free(ptr); 23 | } 24 | 25 | int main () { 26 | good(); 27 | bad1(); 28 | bad2(); 29 | return 0; 30 | } 31 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/untrusted-argument.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | void bad() { 5 | int x = atoi("42"); 6 | int *ptr = malloc(x); 7 | free(ptr); 8 | } 9 | 10 | void good() { 11 | int x = atoi("-42"); 12 | if (x <= 0) 13 | return; 14 | int *ptr = malloc(x); 15 | free(ptr); 16 | } 17 | 18 | int main() { 19 | good(); 20 | bad(); 21 | return 0; 22 | } 23 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/use-after-free.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | 4 | static int MyTrue = 1; 5 | 6 | void good() { 7 | int *p = malloc(42); 8 | if (MyTrue) { 9 | free(p); 10 | return; 11 | } 12 | printf("%d\n", *p); 13 | } 14 | 15 | void bad() { 16 | int *p = malloc(42); 17 | if (MyTrue) { 18 | free(p); 19 | } 20 | printf("%d\n", *p); 21 | } 22 | 23 | int main() { 24 | good(); 25 | bad(); 26 | return 0; 27 | } 28 | -------------------------------------------------------------------------------- /tests/litmus-tests/src/warn-unused.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | 5 | /* used as an argument of system call */ 6 | void good1 () { 7 | int x = atoi("1"); 8 | putchar(x); 9 | } 10 | 11 | /* has an influence to a control flow */ 12 | void good2 () { 13 | int x = atoi("2"); 14 | if (x > 0) { 15 | return; 16 | } 17 | printf("good!\n"); 18 | } 19 | 20 | void bad1 () { 21 | int x = atoi("-1"); 22 | } 23 | 24 | void even_is_used_as_argument(int arg) { 25 | printf("but not as argument of any system call\n"); 26 | } 27 | 28 | void bad2() { 29 | int x = atoi("-2"); 30 | even_is_used_as_argument(x); 31 | } 32 | 33 | int main() { 34 | good1(); 35 | good2(); 36 | bad1(); 37 | bad2(); 38 | return 0; 39 | } 40 | -------------------------------------------------------------------------------- /tests/run.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | trap 'exit 130' INT 4 | 5 | 6 | XFAILS="jpl-rule-14 warn-unused must-check-value juliet-cwe-252/jpl-rule-14 CVE-2012-4559 CVE-2012-6063 CVE-2018-1000222 CVE-2019-8936" 7 | # Reasons: 8 | # warn-unused must-check-value 9 | # relies on taint-finalize observation, that doesn't 10 | # work anymore in the same way as it was earlier (before 11 | # Primus.Systems) 12 | # 13 | # CVE-2012-4559 CVE-2012-6063 CVE-2018-1000222: 14 | # waiting a PR with batched memset/memcpy 15 | # 16 | # CVE-2019-8936 CVE-2018-1000222 17 | # need to replace these artifacts or wait until we rewrite 18 | # checks with symbolic executor - so far we don't have an exact pass 19 | # that leads us to an incident 20 | 21 | logfile="toolkit.log" 22 | litmuses="litmus-tests" 23 | status=OK 24 | 25 | update_status() { 26 | if [ ! "is$status" = "isFAIL" ]; then 27 | result=`echo $1 | grep -v XFAIL | grep FAIL` 28 | if [ ! "OK$result" = "OK" ]; then 29 | status=FAIL 30 | fi 31 | fi 32 | } 33 | 34 | run_bap() { 35 | name=$1 36 | binary=$2 37 | recipe=$3 38 | api_path=$4 39 | start=`date | cut -d' ' -f4` 40 | echo $name: $start bap $binary --recipe=$recipe $api_path >> $logfile 41 | bap $binary --recipe=$recipe $api_path > /dev/null 2> /dev/null 42 | finish=`date | cut -d' ' -f4` 43 | echo "$finish finished" >> $logfile 44 | } 45 | 46 | check_if_may_fail () { 47 | name=$1 48 | MAYFAIL= 49 | for c in $XFAILS; do 50 | if [ "fail$c" = "fail$name" ]; then 51 | MAYFAIL=true 52 | fi 53 | done 54 | } 55 | 56 | compare() { 57 | name=$1 58 | expected_incidents=$2 59 | exact=$3 60 | 61 | check_if_may_fail $name 62 | expected_fail= 63 | if [ "got$MAYFAIL" != "got" ]; then 64 | expected_fail="--expect-fail" 65 | fi 66 | 67 | cp incidents $(basename $name).incidents 68 | result= 69 | result=`./compare-incidents $name $expected_incidents incidents $exact $expected_fail` 70 | 71 | echo "" >> $logfile 72 | echo $result 73 | 74 | update_status "$result" 75 | } 76 | 77 | 78 | litmuses_run() { 79 | echo " LITMUS TESTS" 80 | 81 | for name in `ls litmus-tests/bin`; do 82 | binary=$litmuses/bin/$name 83 | data=$litmuses/data/$name 84 | expected_incidents=$data/expected 85 | 86 | if [ -d $data/api ]; then 87 | api="--api-path=$data/api" 88 | else 89 | api="" 90 | fi 91 | 92 | run_bap $name $binary $name $api 93 | compare $name $expected_incidents "--exact" 94 | 95 | rm -f incidents 96 | 97 | done 98 | } 99 | 100 | file_not_found() { 101 | bug="ERROR: $1 not found" 102 | echo $bug >> $logfile 103 | echo "" >> $logfile 104 | echo $bug 105 | } 106 | 107 | 108 | artifacts_run() { 109 | echo " ARTIFACTS (patience!)" 110 | dir=artifacts 111 | 112 | for arti in `ls $dir`; do 113 | artifact=$dir/$arti/artifact 114 | if [ ! -f $artifact ]; then 115 | continue 116 | fi 117 | 118 | for check in `ls $dir/$arti | grep -v artifact`; do 119 | expected_incidents=$dir/$arti/$check/expected 120 | run=$dir/$arti/$check/run 121 | api=$dir/$arti/$check/api 122 | 123 | if [ ! -f $run ]; then 124 | file_not_found $run 125 | continue 126 | fi 127 | 128 | api_path= 129 | if [ -d $api ]; then 130 | api_path="--api-path=$api" 131 | fi 132 | 133 | recipe=`cat $run` 134 | 135 | cve=`echo $check | grep CVE` 136 | if [ "no$cve" = "no" ]; then 137 | name=$arti/$check 138 | else 139 | name=$check 140 | fi 141 | 142 | check_if_may_fail $name 143 | if [ "got$MAYFAIL" != "got" ]; then 144 | echo "skipping $name" >> $logfile 145 | continue 146 | fi 147 | 148 | run_bap $name $artifact $recipe $api_path 149 | compare $name $expected_incidents 150 | 151 | rm -f incidents 152 | done 153 | done 154 | } 155 | 156 | rm -rf log 157 | rm -f $logfile 158 | 159 | start=`date | cut -d' ' -f4` 160 | echo "started at $start" >> $logfile 161 | litmuses_run 162 | echo "" 163 | artifacts_run 164 | echo "" 165 | 166 | if [ "is$status" = "isFAIL" ]; then 167 | echo "Some tests FAILED" 168 | exit 1 169 | fi 170 | 171 | echo "OK" 172 | -------------------------------------------------------------------------------- /tests/src/Makefile: -------------------------------------------------------------------------------- 1 | 2 | install: build 3 | dune install --root=$$(pwd) --bindir=$$(realpath ..) 4 | 5 | build: 6 | dune build --root=$$(pwd) 7 | -------------------------------------------------------------------------------- /tests/src/compare_incidents.ml: -------------------------------------------------------------------------------- 1 | [@@@warning "-D"] 2 | open Core_kernel 3 | open Bap.Std 4 | 5 | module Sys = Caml.Sys 6 | 7 | type location_id = string 8 | type incident_name = string [@@deriving bin_io, compare,sexp] 9 | 10 | type event = 11 | | Incident_location of location_id * addr 12 | | Incident of incident_name * location_id list 13 | | Incident_static of incident_name * string 14 | 15 | type info = 16 | | Locations of addr list 17 | | Static_data of string 18 | [@@deriving bin_io, compare,sexp] 19 | 20 | type incident = { 21 | name : string; 22 | info : info; 23 | } 24 | [@@deriving bin_io, compare,sexp] 25 | 26 | module Incident = struct 27 | module Set = Set.Make(struct 28 | type t = incident [@@deriving bin_io, compare,sexp] 29 | end) 30 | end 31 | 32 | 33 | type t = { 34 | hist : addr String.Map.t; 35 | incs : Incident.Set.t; 36 | } 37 | 38 | 39 | module Parse = struct 40 | 41 | let addr_of_string a = 42 | Addr.of_string @@ sprintf "0x%s:64u" a 43 | 44 | let point_of_sexp x = match x with 45 | | Sexp.List _ -> None 46 | | Sexp.Atom x -> 47 | match String.split ~on:':' x with 48 | | [_; addr] -> Some (addr_of_string addr) 49 | | [addr] -> Some (addr_of_string addr) 50 | | _ -> None 51 | 52 | let last_addr xs = 53 | Option.value_map ~default:None ~f:point_of_sexp (List.hd xs) 54 | 55 | let locs_of_sexps xs = 56 | List.filter_map xs ~f:(function 57 | | Sexp.Atom s -> Some s 58 | | _ -> None) 59 | 60 | let of_sexp s = 61 | let open Sexp in 62 | match s with 63 | | List (Atom "incident-location" :: List [Atom id; List points] :: _) -> 64 | Option.map (last_addr points) ~f:(fun p -> Incident_location (id, p)) 65 | | List (Atom "incident" :: List (Atom name :: locs) :: _) -> 66 | Incident (name, locs_of_sexps locs) |> Option.some 67 | | List (Atom "incident-static" :: List (Atom name :: data) :: _) -> 68 | Incident_static (name, Sexp.to_string (List data)) |> Option.some 69 | | _ -> None 70 | 71 | let of_sexp s = 72 | try of_sexp s 73 | with _ -> None 74 | 75 | let sexp ch = 76 | try Some (Sexp.input_sexp ch) 77 | with _ -> None 78 | 79 | let of_in_channel ch = 80 | let rec read () = 81 | match sexp ch with 82 | | None -> None 83 | | Some s -> 84 | match of_sexp s with 85 | | None -> read () 86 | | Some _ as r -> r in 87 | read () 88 | end 89 | 90 | module Log = struct 91 | 92 | let logfile = "toolkit.log" 93 | 94 | let file_not_found check_name file = 95 | let reason = sprintf "%s failed: %s not found" check_name file in 96 | Out_channel.with_file logfile ~append:true ~f:(fun ch -> 97 | Out_channel.output_lines ch [reason]) 98 | 99 | let check_failed check_name real ours = 100 | let tp = Set.inter real ours in 101 | let fp = Set.diff ours real in 102 | let fn = Set.diff real ours in 103 | let fabula = 104 | sprintf "%s failed: True-pos/False-pos/False-neg: %d/%d/%d" 105 | check_name (Set.length tp) (Set.length fp) (Set.length fn) in 106 | Out_channel.with_file logfile ~append:true ~f:(fun ch -> 107 | Out_channel.output_lines ch 108 | [fabula; " The following incidents are missed"]; 109 | let missed = 110 | Set.fold ~init:[] fn ~f:(fun acc inc -> 111 | let inc = sprintf " %s" 112 | (Sexp.to_string (sexp_of_incident inc)) in 113 | inc :: acc) in 114 | Out_channel.output_lines ch missed) 115 | 116 | end 117 | 118 | 119 | 120 | let incident_location s (id,addr) = 121 | {s with hist = Map.set s.hist ~key:id ~data:addr} 122 | 123 | let incident s name locs = 124 | let locs = List.filter_map locs ~f:(Map.find s.hist) in 125 | {s with incs = Set.add s.incs {name; info=Locations locs}} 126 | 127 | let incident_static s name data = 128 | {s with incs = Set.add s.incs {name; info=Static_data data}} 129 | 130 | let event s = function 131 | | Incident_location (id,addr) -> incident_location s (id,addr) 132 | | Incident (name, locs) -> incident s name locs 133 | | Incident_static (name, data) -> incident_static s name data 134 | 135 | let read ch = 136 | let rec loop s = 137 | match Parse.of_in_channel ch with 138 | | None -> s 139 | | Some ev -> event s ev |> loop in 140 | let s = loop { hist = Map.empty (module String); 141 | incs=Incident.Set.empty; } in 142 | s.incs 143 | 144 | let print_status name status = 145 | let margin = 60 in 146 | let dots = String.init (margin - String.length name) ~f:(fun _ -> '.') in 147 | printf "%s %s %s\n" name dots status 148 | 149 | let compare_incidents exact real ours = 150 | if exact then Set.equal real ours 151 | else Set.is_subset real ~of_:ours 152 | 153 | let file_exists check_name f = 154 | let r = Sys.file_exists f in 155 | if not r then Log.file_not_found check_name f; 156 | r 157 | 158 | let main name real_incs ours_incs exact expected_fail = 159 | let of_ch c = In_channel.with_file c ~f:read in 160 | if not (file_exists name real_incs) || not (file_exists name ours_incs) then 161 | print_status name "FAIL" 162 | else 163 | let real = of_ch real_incs in 164 | let ours = of_ch ours_incs in 165 | let passed = compare_incidents exact real ours in 166 | let status = 167 | if passed then "PASS" 168 | else if expected_fail then "XFAIL" 169 | else "FAIL" in 170 | print_status name status; 171 | if not passed then 172 | Log.check_failed name real ours; 173 | if not passed && not expected_fail then 174 | exit 1 175 | 176 | open Cmdliner 177 | 178 | let doc = "Compares incidents in two files. 179 | 180 | invocation: ./compare-incidents check-name real incidents exact expected 181 | 182 | If the exact flag is set then incidents in two files must be 183 | be the same, i.e. all the incidents from one file are present 184 | in another and vice versa. 185 | 186 | Otherwise, all the real incidents must be a subset of the 187 | incidents we are checking, i.e. false positives are permitted, 188 | but no regression is allowed. 189 | 190 | Incidents are compared by the addresses of their locations and 191 | by theirs name. Thus, if an incident has three locations, then 192 | a corresponded incident considered as an equal one if it has 193 | the same number of locations with the same addresses as the first one. 194 | 195 | The status of the comparison is one of the PASS | FAIL | XFAIL. 196 | The latter one is assigned if incidents don't match each other and 197 | 'expected' flag is set." 198 | 199 | let test_name : string Term.t = 200 | let doc = "Name of the test to do" in 201 | Arg.(required & pos 0 (some string) None & 202 | info [] ~doc ~docv:"NAME") 203 | 204 | let real : string Term.t = 205 | let doc = "File with real(proven) incidents" in 206 | Arg.(required & pos 1 (some string) None & 207 | info [] ~doc ~docv:"REAL") 208 | 209 | let ours : string Term.t = 210 | let doc = "File with new incidents" in 211 | Arg.(required & pos 2 (some string) None & 212 | info [] ~doc ~docv:"FILE") 213 | 214 | let exact : bool Term.t = 215 | let doc = 216 | "Compares incidents exactly, i.e. no False positives permitted" in 217 | Arg.(value & flag & info ["exact"] ~doc) 218 | 219 | let expected_fail : bool Term.t = 220 | let doc = 221 | "Indicates, that it's not a bug if a test is failed, it was expected" in 222 | Arg.(value & flag & info ["expect-fail"] ~doc) 223 | 224 | 225 | let prg = 226 | Term.(const main $test_name $real $ours $exact $expected_fail), 227 | Term.info "compare-incidents" ~doc 228 | 229 | let _ : unit Term.result = Term.eval prg 230 | -------------------------------------------------------------------------------- /tests/src/compare_incidents.mli: -------------------------------------------------------------------------------- 1 | (* compares two incident files *) 2 | -------------------------------------------------------------------------------- /tests/src/dune: -------------------------------------------------------------------------------- 1 | (executable 2 | (name compare_incidents) 3 | (public_name compare-incidents) 4 | (preprocess (pps ppx_jane)) 5 | (libraries bap core_kernel cmdliner)) 6 | -------------------------------------------------------------------------------- /tests/src/dune-project: -------------------------------------------------------------------------------- 1 | (lang dune 3.1) 2 | (package 3 | (name bap-toolkit) 4 | (depends bap core_kernel cmdliner)) 5 | -------------------------------------------------------------------------------- /tests/update_dockerfile.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env sh 2 | 3 | gen() { 4 | echo "FROM binaryanalysisplatform/bap:latest as base" 5 | echo 6 | echo "COPY --chown=opam:nogroup src /src" 7 | echo "WORKDIR /src" 8 | echo "RUN eval \"\$(opam env)\" && make build" 9 | echo 10 | echo "FROM binaryanalysisplatform/bap-toolkit:latest as toolkit" 11 | echo 12 | echo "COPY . /tests" 13 | echo "WORKDIR /tests" 14 | echo "COPY --from=base /src/compare-incidents /tests" 15 | 16 | for name in `ls artifacts/`; do 17 | arti=artifacts/$name 18 | echo "COPY --from=binaryanalysisplatform/bap-artifacts:$name /artifact $arti" 19 | 20 | done 21 | 22 | echo "RUN sh run.sh" 23 | } 24 | 25 | gen > Dockerfile 26 | -------------------------------------------------------------------------------- /untrusted-argument/descr: -------------------------------------------------------------------------------- 1 | detects a usage of untrusted data by some certain functions -------------------------------------------------------------------------------- /untrusted-argument/limit-malloc.lisp: -------------------------------------------------------------------------------- 1 | ;; up to 4 Mb each chunk, up to 128 Mbytes total 2 | 3 | (defmethod init () 4 | (set *malloc-max-chunk-size* (* 4 1024 1024)) 5 | (set *malloc-guard-edges* 0) 6 | (set *malloc-max-arena-size* (* 32 *malloc-max-chunk-size*)) 7 | (set *malloc-arena-start* brk) 8 | (set *malloc-zero-sentinel* 0)) 9 | -------------------------------------------------------------------------------- /untrusted-argument/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter depth 32768 "a depth of analysis") 2 | (parameter entry-points all-subroutines "where to search") 3 | 4 | (option primus-lisp-load 5 | posix 6 | taint 7 | limit-malloc 8 | taint-sources 9 | sensitive-sinks) 10 | 11 | (option primus-lisp-add $prefix) 12 | 13 | (option passes 14 | with-no-return 15 | run) 16 | 17 | (option primus-lisp-channel-redirect 18 | :$prefix/stdin 19 | :$prefix/stdout) 20 | 21 | (option report-progress) 22 | (option log-dir log) 23 | 24 | (option run-entry-points ${entry-points}) 25 | 26 | (option primus-promiscuous-mode) 27 | (option primus-greedy-scheduler) 28 | (option primus-print-output incidents) 29 | (option primus-limit-max-length $depth) 30 | 31 | (option primus-print-obs 32 | exception 33 | pc-changed 34 | jumping 35 | call 36 | call-return 37 | machine-switch 38 | machine-fork 39 | lisp-message 40 | incident 41 | incident-location) 42 | -------------------------------------------------------------------------------- /untrusted-argument/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/untrusted-argument/stdin -------------------------------------------------------------------------------- /untrusted-argument/stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/untrusted-argument/stdout -------------------------------------------------------------------------------- /use-after-free/descr: -------------------------------------------------------------------------------- 1 | detects access to a memory that has been freed previously 2 | 3 | This check covers CWE-416 Use After Free entry. 4 | 5 | Motivation 6 | ========== 7 | 8 | Referencing memory after it has been freed can cause a program to crash, 9 | use unexpected values, or execute code. 10 | -------------------------------------------------------------------------------- /use-after-free/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter depth 32768 "a depth of analysis") 2 | (parameter entry-points all-subroutines "where to search") 3 | (parameter optimization 0 "optimization level") 4 | (parameter visits 128 "maximum number of executions of the same block") 5 | 6 | (option primus-lisp-load 7 | posix 8 | use-after-free) 9 | 10 | (option primus-lisp-add $prefix) 11 | (option passes 12 | with-no-return 13 | run) 14 | 15 | (option primus-lisp-channel-redirect 16 | :$prefix/stdin 17 | :$prefix/stdout) 18 | 19 | (option report-progress) 20 | (option log-dir log) 21 | 22 | (option run-entry-points ${entry-points}) 23 | 24 | (option primus-promiscuous-mode) 25 | (option primus-greedy-scheduler) 26 | (option primus-print-output incidents) 27 | (option primus-limit-max-length $depth) 28 | (option primus-limit-max-visited $visits) 29 | 30 | (option primus-print-obs 31 | exception 32 | pc-changed 33 | jumping 34 | call 35 | call-return 36 | machine-switch 37 | machine-fork 38 | lisp-message 39 | incident 40 | incident-location) 41 | 42 | (option optimization-level $optimization) 43 | -------------------------------------------------------------------------------- /use-after-free/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/use-after-free/stdin -------------------------------------------------------------------------------- /use-after-free/stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/use-after-free/stdout -------------------------------------------------------------------------------- /use-after-free/use-after-free.lisp: -------------------------------------------------------------------------------- 1 | (require memcheck) 2 | 3 | (defmethod call (name ptr) 4 | (when (and ptr (= name 'free) 5 | (not (= ptr *malloc-zero-sentinel*))) 6 | (when (and ptr 7 | (not (memcheck-is-tracked 'malloc ptr))) 8 | (memcheck-acquire 'malloc ptr 1)) 9 | (memcheck-release 'malloc ptr))) 10 | 11 | (defmethod loaded (ptr) 12 | (memcheck-access 'malloc ptr)) 13 | 14 | (defmethod stored (ptr) 15 | (memcheck-access 'malloc ptr)) 16 | 17 | (defmethod call-return (name len ptr) 18 | (when (and len ptr (= name 'malloc)) 19 | (memcheck-acquire 'malloc ptr len))) 20 | -------------------------------------------------------------------------------- /warn-unused/.merlin: -------------------------------------------------------------------------------- 1 | PKG core_kernel 2 | PKG bap 3 | PKG bap-primus 4 | PKG bap-c 5 | PKG bap-taint 6 | 7 | S . 8 | 9 | B _build/ -------------------------------------------------------------------------------- /warn-unused/descr: -------------------------------------------------------------------------------- 1 | detects an unused result of a function with warn-unused-result attribute 2 | 3 | Ensures the usage of a value returned by a function 4 | that is tagged wih the GNU warn-unused-result attribute. 5 | 6 | 7 | The Algorithm 8 | ================ 9 | 10 | We use the Primus Taint analysis engine to propagate the taint from the 11 | return argument of a function that has warn-unused attribute. We 12 | sanitize taint (thus indicating that the value was used when one of 13 | the following happens): 14 | 15 | 1) some control flow depends on the tainted value, i.e., 16 | a taint reaches the condition of a jump term; 17 | 2) the taint reaches a function with an external linkage. 18 | 19 | To catch the unused values as soon as possible, we enable the 20 | conservative Primus taint garbage collector that notifies us when a 21 | taint is no longer reachable (and thus has no chance on sanitizing). 22 | 23 | Finally, when analysis finishes, we indicate all functions 24 | that weren't sanitized as unused, even if their taint still alive. 25 | -------------------------------------------------------------------------------- /warn-unused/info: -------------------------------------------------------------------------------- 1 | main: warn_unused_result.ml 2 | depends: bap bap-main bap-primus bap-taint -------------------------------------------------------------------------------- /warn-unused/recipe.scm: -------------------------------------------------------------------------------- 1 | (parameter depth 32768 "a depth of analysis") 2 | (parameter entry-points all-subroutines "where to search") 3 | 4 | (option primus-lisp-load 5 | warn-unused-result 6 | posix) 7 | 8 | (option passes 9 | with-no-return 10 | callsites 11 | run) 12 | 13 | (option run-system bap:warn-unused-result) 14 | (option primus-limit-max-length $depth) 15 | (option primus-lisp-add $prefix) 16 | (option primus-systems-add $prefix) 17 | (option primus-print-output incidents) 18 | (option run-entry-points ${entry-points}) 19 | 20 | (option primus-lisp-channel-redirect 21 | :$prefix/stdin 22 | :$prefix/stderr 23 | :$prefix/stdout) 24 | 25 | (option primus-print-observations 26 | bap:warn-unused-result/introduce 27 | bap:warn-unused-result/sanitize 28 | exception 29 | pc-changed 30 | jumping 31 | call 32 | call-return 33 | machine-switch 34 | machine-fork 35 | lisp-message 36 | incident 37 | incident-location) 38 | 39 | (option report-progress) 40 | (option log-dir log) 41 | -------------------------------------------------------------------------------- /warn-unused/stderr: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/warn-unused/stderr -------------------------------------------------------------------------------- /warn-unused/stdin: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/warn-unused/stdin -------------------------------------------------------------------------------- /warn-unused/stdout: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/warn-unused/stdout -------------------------------------------------------------------------------- /warn-unused/warn-unused-result.asd: -------------------------------------------------------------------------------- 1 | (defsystem bap:warn-unused-result 2 | :description "Checks that values, returned by functions that are 3 | annotated with the warn-unused-result attribute, are properly used." 4 | :depends-on (bap:taint-analyzer) 5 | :components (bap:warn-unused-tracker 6 | bap:conservative-garbage-collector)) 7 | -------------------------------------------------------------------------------- /warn-unused/warn-unused-result.lisp: -------------------------------------------------------------------------------- 1 | ;; when a call is made to a wur function, taint the result 2 | (defmethod bap:warn-unused-result/introduce (taint) 3 | (dict-add 'warn-unused-results/taints 4 | taint 5 | (incident-location))) 6 | 7 | ;; or used in an external function 8 | (defmethod bap:warn-unused-result/sanitize (taint) 9 | (dict-del 'warn-unused-result/taints taint)) 10 | 11 | ;; when taint dies without being sanitized report an incident 12 | (defmethod taint-finalize (taint live) 13 | (let ((unchecked (dict-get 'warn-unused-results/taints taint))) 14 | (when (and unchecked (not live)) 15 | (incident-report 'warn-unused-result unchecked) 16 | (dict-del 'warn-unused-result/taints unchecked)))) 17 | -------------------------------------------------------------------------------- /warn-unused/warn_unused_result.ml: -------------------------------------------------------------------------------- 1 | (** The Algorithm 2 | 3 | When a call to a function that has any of its arguments marked 4 | with the warn-unused-result attribute is made we emit the 5 | warn-unused-result-call signal parameterized with the values that 6 | we have to check. This signal is received by the 7 | warn-unused-result Lisp code that defines the policy. The value is 8 | tainted and tracked in the dictionary of values to be checked. 9 | 10 | Once we have an external call that consumes a tainted value we 11 | dispatch the warn-unused-tainted-external-call signal for each 12 | taint of the warn-unused kind. The Lisp code uses this signal to 13 | sanitize the taint and mark the corresponding value as checked. 14 | 15 | In addition the Lisp code monitors the `jumping` signal and 16 | sanitizes the warn-unused taint associated with its condition. 17 | 18 | Finally, when the taint-finalize signal occurs for a taint that is 19 | not marked as sanitized we report an incident. 20 | 21 | See warn-unused-result.lisp for more information. 22 | **) 23 | 24 | open Core_kernel 25 | open Bap.Std 26 | open Bap_primus.Std 27 | open Bap_main 28 | open Bap_taint.Std 29 | 30 | let check_name = "warn unused result" 31 | 32 | let print_results rs = 33 | let open Format in 34 | let pp_bold ppf = fprintf ppf "\027[1m" in 35 | let pp_norm ppf = fprintf ppf "\027[0m" in 36 | match rs with 37 | | [] -> printf "%s OK\n" check_name 38 | | rs -> 39 | printf "%s FAIL\n\n" check_name; 40 | printf "%t%-10s %-20s\n%t" pp_bold "Address" "Function" pp_norm; 41 | List.iter rs ~f:(fun (addr,name) -> 42 | let addr = sprintf "%a" Addr.pps addr in 43 | printf "%-10s %-20s\n%!" addr name) 44 | 45 | let is_wur sub = 46 | Term.enum arg_t sub |> Seq.exists ~f:(fun arg -> 47 | Dict.mem (Term.attrs arg) Arg.warn_unused) 48 | 49 | let is_ext sub = Term.has_attr sub Sub.stub 50 | 51 | let select_subs is_our prog = 52 | Term.enum sub_t prog |> Seq.fold 53 | ~f:(fun subs sub -> 54 | if is_our sub 55 | then Map.add_exn subs (Term.tid sub) (Sub.name sub) 56 | else subs) 57 | ~init:(Map.empty (module Tid)) 58 | 59 | let callsite_collector ours = object 60 | inherit [string Map.M(Addr).t] Term.visitor 61 | method! enter_jmp t sites = 62 | match Jmp.alt t with 63 | | None -> sites 64 | | Some dst -> match Jmp.resolve dst with 65 | | Second _ -> sites 66 | | First dst -> match Map.find ours dst with 67 | | None -> sites 68 | | Some name -> match Term.get_attr t address with 69 | | None -> sites 70 | | Some addr -> Map.set sites addr name 71 | end 72 | 73 | let collect_sites pred proj = 74 | let prog = Project.program proj in 75 | let collector = callsite_collector (select_subs pred prog) in 76 | collector#run prog (Map.empty (module Addr)) 77 | 78 | let warn_unused_introduce,introduced = 79 | Primus.Observation.provide "warn-unused-result/introduce" 80 | ~package:"bap" 81 | ~inspect:Taint.Object.inspect 82 | ~desc:"Occurs on a return from a function that has \ 83 | the GNU warn_unused_result attribute returns. \ 84 | Parameterized with the returned value." 85 | 86 | let warn_unused_sanitize,sanitized = 87 | Primus.Observation.provide "warn-unused-result/sanitize" 88 | ~package:"bap" 89 | ~inspect:Taint.Object.inspect 90 | ~desc:"Occurs when a value that has a warn-unused taint \ 91 | is passed to an external function." 92 | 93 | type state = { 94 | unchecked : addr Map.M(Taint.Object).t; 95 | callsites : string Map.M(Addr).t; 96 | externals : string Map.M(Addr).t; 97 | 98 | } 99 | 100 | let state = 101 | Primus.Machine.State.declare 102 | ~name:"warn-unused-result" 103 | ~uuid:"1e117d51-3b9d-4c93-b136-e15b77c5ea26" @@ fun proj -> 104 | { 105 | unchecked = Map.empty (module Taint.Object); 106 | callsites = collect_sites is_wur proj; 107 | externals = collect_sites is_ext proj; 108 | } 109 | 110 | module Tracker(Machine : Primus.Machine.S) = struct 111 | open Machine.Syntax 112 | open Machine.Let 113 | module Eval = Primus.Interpreter.Make(Machine) 114 | module Lisp = Primus.Lisp.Make(Machine) 115 | module Kind = Taint.Kind.Make(Machine) 116 | module Object = Taint.Object.Make(Machine) 117 | module Tracker = Taint.Tracker.Make(Machine) 118 | 119 | let wur_kind = Kind.create "bap:warn-unused" 120 | 121 | let introduce v = 122 | wur_kind >>= 123 | Tracker.new_direct v 124 | 125 | let foreach_wur v f = 126 | wur_kind >>= fun k -> 127 | Tracker.lookup v Taint.Rel.direct >>| 128 | Set.to_sequence >>= 129 | Machine.Seq.iter ~f:(fun t -> 130 | Object.kind t >>= fun k' -> 131 | if Taint.Kind.equal k k' then f v t 132 | else Machine.return ()) 133 | 134 | let summarize _ = 135 | Machine.Global.get state >>| fun {unchecked; callsites} -> 136 | Map.fold unchecked 137 | ~f:(fun ~key:_ ~data:site unchecked -> 138 | Map.set unchecked site (Map.find_exn callsites site)) 139 | ~init:(Map.empty (module Addr)) |> 140 | Map.to_alist |> 141 | print_results 142 | 143 | let handle_wur_call (_name,args) = 144 | let* pc = Eval.pc in 145 | let* {callsites} as curr = Machine.Global.get state in 146 | if Map.mem callsites pc then match List.rev args with 147 | | rval :: _ -> 148 | introduce rval >>= fun t -> 149 | Machine.sequence [ 150 | Machine.Global.put state { 151 | curr with 152 | unchecked = Map.add_exn curr.unchecked t pc 153 | }; 154 | Machine.Observation.make introduced t 155 | ] 156 | | _ -> Machine.return () 157 | else Machine.return () 158 | 159 | let sanitize v t = Machine.sequence [ 160 | wur_kind >>= Tracker.sanitize v Taint.Rel.direct; 161 | Machine.Observation.make sanitized t; 162 | Machine.Global.update state ~f:(fun curr -> { 163 | curr with 164 | unchecked = Map.remove curr.unchecked t 165 | }) 166 | ] 167 | 168 | let handle_external (_name,args) = 169 | let* pc = Eval.pc in 170 | let* {externals} = Machine.Global.get state in 171 | if Map.mem externals pc 172 | then Machine.List.iter args ~f:(fun arg -> 173 | foreach_wur arg sanitize) 174 | else Machine.return () 175 | 176 | let handle_jump (cnd,_) = foreach_wur cnd sanitize 177 | 178 | let reflect_signals = 179 | let params = Primus.Lisp.Type.Spec.(one Taint.Object.t) in 180 | let reflect obs = 181 | Lisp.signal ~params obs @@ fun v -> 182 | Object.to_value v >>| fun v -> [v] in 183 | Machine.sequence [ 184 | reflect warn_unused_introduce; 185 | reflect warn_unused_sanitize; 186 | ] 187 | 188 | let init () = 189 | let* {callsites} = Machine.Global.get state in 190 | if Map.is_empty callsites 191 | then !!(print_results []) 192 | else Machine.sequence [ 193 | Primus.System.stop >>> summarize; 194 | Primus.Linker.Trace.return >>> handle_wur_call; 195 | Primus.Linker.Trace.call >>> handle_external; 196 | Primus.Interpreter.jumping >>> handle_jump; 197 | reflect_signals; 198 | ] 199 | end 200 | 201 | let enabled = Extension.Configuration.flag "enable" 202 | ~doc:"Adds the analysis component to the bap:legacy-main system." 203 | 204 | let () = 205 | let open Extension.Syntax in 206 | Extension.declare 207 | @@ fun ctxt -> 208 | Primus.Components.register_generic "warn-unused-tracker" 209 | ~package:"bap" (module Tracker); 210 | if ctxt-->enabled 211 | then Primus.Machine.add_component (module Tracker) 212 | [@warning "-D"]; 213 | Ok () 214 | -------------------------------------------------------------------------------- /warn-unused/warn_unused_result.mli: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/BinaryAnalysisPlatform/bap-toolkit/c892076f73b198f5c9557085ceb89c074718d291/warn-unused/warn_unused_result.mli -------------------------------------------------------------------------------- /with-no-return/.merlin: -------------------------------------------------------------------------------- 1 | PKG core_kernel 2 | PKG bap 3 | 4 | S . 5 | B _build -------------------------------------------------------------------------------- /with-no-return/info: -------------------------------------------------------------------------------- 1 | depends: bap bap-main graphlib -------------------------------------------------------------------------------- /with-no-return/with_no_return.ml: -------------------------------------------------------------------------------- 1 | 2 | (** 3 | This pass removes 'return' edge from all the calls to the non-return 4 | functions. 5 | 6 | Algorithm 7 | 8 | We start from the initial set of non-return functions, such ones 9 | that either have GNU noreturn attribute OR have an edge between 10 | start and exit nodes in the Tid graph. For instance, the latter can 11 | happen when a loop without exit exists in a graph of a subroutine. 12 | 13 | Then, for each subroutine in the program, we remove such edges in the 14 | Tid graph of the subroutine that correspond to calls to 15 | non-return functions. 16 | 17 | By doing so, we can introduce unreachable blocks. And to be sure 18 | that they are trully unreachable, we need to prove that they can't 19 | be reached by indirect calls. We add a synthetic node, and connect 20 | each block with indirect call with this node and also connect this 21 | node with the exit. 22 | 23 | Now, the decision if the function is non-return one depends on 24 | the reachability of the exit node from the start. If it can't 25 | be reached then such subroutine is a non-return and we need to add 26 | it in the set of nonreturn subroutines and apply algorithm 27 | again to the all subroutines. *) 28 | 29 | 30 | open Core_kernel 31 | open Bap.Std 32 | open Graphlib.Std 33 | 34 | include Self () 35 | 36 | module G = Graphs.Tid 37 | 38 | type call_edge = { 39 | src : tid; 40 | label : tid; 41 | } 42 | 43 | type subroutine = { 44 | tid : tid; 45 | graph : G.t; 46 | indirect : tid; 47 | callees : call_edge list Tid.Map.t; 48 | } 49 | 50 | let is_resolved j = 51 | List.filter_map ~f:ident [Jmp.dst j; Jmp.alt j] |> 52 | List.exists ~f:(fun d -> Either.is_first (Jmp.resolve d)) 53 | 54 | let is_indirect j = not (is_resolved j) 55 | 56 | let indirects_of_blk b = 57 | Term.to_sequence jmp_t b |> Seq.filter ~f:is_indirect 58 | 59 | let connect_indirects g node blk = 60 | Seq.fold (indirects_of_blk blk) ~init:g 61 | ~f:(fun g j -> 62 | let e = G.Edge.create (Term.tid blk) node (Term.tid j) in 63 | G.Edge.insert e g) 64 | 65 | let calls_of_blk calls b = 66 | Term.to_sequence jmp_t b |> 67 | Seq.fold ~init:calls ~f:(fun acc j -> 68 | match Jmp.alt j with 69 | | None -> acc 70 | | Some callee -> match Jmp.resolve callee with 71 | | First callee -> 72 | Map.add_multi acc callee { src = Term.tid b; label = Term.tid j; } 73 | | _ -> acc) 74 | 75 | let callees_of_sub sub = 76 | Term.to_sequence blk_t sub |> 77 | Seq.fold ~init:(Map.empty (module Tid)) ~f:calls_of_blk 78 | 79 | let of_sub sub = 80 | let blks = Term.to_sequence blk_t sub in 81 | if Seq.is_empty blks then None 82 | else 83 | let indirect = Tid.create () in 84 | let graph = Sub.to_graph sub in 85 | let graph = G.Edge.(insert (create indirect G.exit indirect) graph) in 86 | let graph = 87 | Seq.fold blks ~init:graph 88 | ~f:(fun g b -> connect_indirects g indirect b) in 89 | let callees = callees_of_sub sub in 90 | Some {tid = Term.tid sub; graph; indirect; callees} 91 | 92 | let prune_edge_to_nonreturn g {src; label} = 93 | G.Node.outputs src g |> 94 | Seq.fold ~init:g ~f:(fun g e -> 95 | if Tid.equal (G.Edge.label e) label 96 | then G.Edge.remove e g 97 | else g) 98 | 99 | let update s no_ret = 100 | let is_unreachable b g = G.Node.degree ~dir:`Out b g = 0 in 101 | match Map.find s.callees no_ret with 102 | | None -> s 103 | | Some edges -> { 104 | s with 105 | graph = 106 | List.fold edges ~init:s.graph 107 | ~f:(fun g edge -> 108 | let dsts = 109 | G.Node.outputs edge.src g |> Seq.map ~f:G.Edge.dst in 110 | let g = prune_edge_to_nonreturn g edge in 111 | Seq.fold dsts ~init:g 112 | ~f:(fun g blk -> 113 | if is_unreachable blk g then 114 | G.Edge.(insert (create blk s.indirect s.indirect) g) 115 | else g)) 116 | } 117 | 118 | let update s no_rets = Set.fold no_rets ~init:s ~f:update 119 | 120 | let apply no_returns prog = 121 | (object 122 | inherit Term.mapper 123 | 124 | method! map_jmp j = 125 | match Jmp.kind j with 126 | | Goto _ | Ret _ | Int _ -> j 127 | | Call c -> 128 | match Call.target c with 129 | | Indirect _ -> j 130 | | Direct tid -> 131 | if Set.mem no_returns tid then 132 | Jmp.with_kind j (Call (Call.with_noreturn c)) 133 | else j 134 | end)#run prog 135 | 136 | let is_known_noreturn s g = 137 | Term.has_attr s Sub.noreturn || 138 | G.Node.has_edge G.start G.exit g 139 | 140 | let of_prog prog = 141 | Term.to_sequence sub_t prog |> 142 | Seq.fold ~init:([],Set.empty (module Tid)) 143 | ~f:(fun (subs,no_rets) s -> match of_sub s with 144 | | None -> subs, no_rets 145 | | Some s' -> 146 | let no_rets = 147 | if is_known_noreturn s s'.graph then 148 | Set.add no_rets s'.tid 149 | else no_rets in 150 | s' :: subs, no_rets) 151 | 152 | let is_no_return sub = 153 | not (Graphlib.is_reachable (module G) sub.graph G.start G.exit) 154 | 155 | let run prog = 156 | let update_prog subs no_rets = 157 | List.fold subs ~init:([],no_rets) ~f:(fun (subs, no_rets) s -> 158 | let s = update s no_rets in 159 | let no_rets = 160 | if is_no_return s then 161 | Set.add no_rets s.tid 162 | else no_rets in 163 | s :: subs, no_rets) in 164 | let rec loop subs no_rets = 165 | let subs,no_rets' = update_prog subs no_rets in 166 | if Set.is_empty (Set.diff no_rets' no_rets) then no_rets 167 | else loop subs no_rets' in 168 | let subs,no_rets = of_prog prog in 169 | let no_rets = loop subs no_rets in 170 | apply no_rets prog 171 | 172 | let main p = Project.with_program p (run (Project.program p)) 173 | 174 | let () = 175 | Config.when_ready (fun _ -> Project.register_pass ~deps:["api"] main) 176 | --------------------------------------------------------------------------------