Skip to content
Projects
Groups
Snippets
Help
This project
Loading...
Sign in / Register
Toggle navigation
C
cwe_checker
Overview
Overview
Details
Activity
Cycle Analytics
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Charts
Issues
0
Issues
0
List
Board
Labels
Milestones
Merge Requests
0
Merge Requests
0
CI / CD
CI / CD
Pipelines
Jobs
Schedules
Charts
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Charts
Create a new issue
Jobs
Commits
Issue Boards
Open sidebar
fact-depend
cwe_checker
Commits
41b84a41
Commit
41b84a41
authored
Feb 22, 2019
by
Enkelmann
Committed by
Thomas Barabosch
Feb 22, 2019
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Cwe476 (#11)
* improved CWE476-check with dataflow analysis
parent
44cb572a
Hide whitespace changes
Inline
Side-by-side
Showing
31 changed files
with
465 additions
and
196 deletions
+465
-196
CHANGES.md
CHANGES.md
+7
-6
cwe_190.ml
src/checkers/cwe_190.ml
+2
-2
cwe_190.mli
src/checkers/cwe_190.mli
+2
-2
cwe_215.ml
src/checkers/cwe_215.ml
+8
-9
cwe_215.mli
src/checkers/cwe_215.mli
+3
-3
cwe_243.ml
src/checkers/cwe_243.ml
+6
-7
cwe_243.mli
src/checkers/cwe_243.mli
+2
-2
cwe_248.ml
src/checkers/cwe_248.ml
+1
-1
cwe_248.mli
src/checkers/cwe_248.mli
+1
-1
cwe_332.ml
src/checkers/cwe_332.ml
+3
-4
cwe_332.mli
src/checkers/cwe_332.mli
+2
-2
cwe_367.ml
src/checkers/cwe_367.ml
+3
-3
cwe_367.mli
src/checkers/cwe_367.mli
+2
-2
cwe_426.ml
src/checkers/cwe_426.ml
+2
-2
cwe_426.mli
src/checkers/cwe_426.mli
+5
-5
cwe_457.ml
src/checkers/cwe_457.ml
+3
-3
cwe_457.mli
src/checkers/cwe_457.mli
+1
-1
cwe_467.ml
src/checkers/cwe_467.ml
+5
-5
cwe_467.mli
src/checkers/cwe_467.mli
+2
-2
cwe_476.ml
src/checkers/cwe_476.ml
+283
-44
cwe_476.mli
src/checkers/cwe_476.mli
+18
-5
cwe_676.ml
src/checkers/cwe_676.ml
+1
-2
cwe_676.mli
src/checkers/cwe_676.mli
+1
-1
cwe_782.ml
src/checkers/cwe_782.ml
+2
-2
cwe_782.mli
src/checkers/cwe_782.mli
+1
-1
config.json
src/config.json
+4
-0
cwe_checker.ml
src/cwe_checker.ml
+30
-26
json_utils.ml
src/utils/json_utils.ml
+7
-0
json_utils.mli
src/utils/json_utils.mli
+1
-0
cwe_476.c
test/artificial_samples/cwe_476.c
+5
-4
makefile
test/artificial_samples/makefile
+52
-49
No files found.
CHANGES.md
View file @
41b84a41
0.2-dev (2019-XX-XX)
=====
-
Refactoring: Unification of cwe_checker function interface
-
Refactoring: Created utils module for JSON functionality
-
Added check for CWE 248: Uncaught Exception (PR #5)
-
Added automated test suite (run with make test) (PR #7)
-
Improved cross compiling for acceptance test cases by using dockcross (PR #8)
-
Added BAP recipe for standard cwe_checker run (PR #9)
-
Refactoring: Unification of cwe_checker function interface
-
Refactoring: Created utils module for JSON functionality
-
Added check for CWE 248: Uncaught Exception (PR #5)
-
Added automated test suite (run with make test) (PR #7)
-
Improved cross compiling for acceptance test cases by using dockcross (PR #8)
-
Added BAP recipe for standard cwe_checker run (PR #9)
-
Improved check for CWE-476 (NULL Pointer Dereference) using data flow analysis (PR #11)
0.
1 (2018-10-08)
=====
...
...
src/checkers/cwe_190.ml
View file @
41b84a41
...
...
@@ -27,10 +27,10 @@ let check_multiplication_before_symbol proj prog sub blk jmp tid_map symbols =
(
Address_translation
.
translate_tid_to_assembler_address_string
(
Term
.
tid
blk
)
tid_map
)
(
Symbol_utils
.
get_symbol_name_from_jmp
jmp
symbols
))
let
check_cwe
prog
proj
tid_map
symbol_names
=
let
check_cwe
prog
proj
tid_map
symbol_names
_
=
match
symbol_names
with
|
hd
::
[]
->
let
symbols
=
Symbol_utils
.
build_symbols
hd
prog
in
let
symbols
=
Symbol_utils
.
build_symbols
hd
prog
in
let
calls
=
call_finder
#
run
prog
[]
in
let
relevant_calls
=
filter_calls_to_symbols
calls
symbols
in
check_calls
relevant_calls
prog
proj
tid_map
symbols
check_multiplication_before_symbol
...
...
src/checkers/cwe_190.mli
View file @
41b84a41
...
...
@@ -3,6 +3,6 @@ CWE-190 (Integer Overflow or Wraparound)
https://cwe.mitre.org/data/definitions/190.html
*)
val
name
:
string
val
version
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/checkers/cwe_215.ml
View file @
41b84a41
...
...
@@ -3,17 +3,17 @@ open Bap.Std
open
Unix
(* TODO: IVG via gitter:
I see, so you need the CU information, and yes BAP doesn't provide this.
The right way to do this thing (a little bit complicated, but it
I see, so you need the CU information, and yes BAP doesn't provide this.
The right way to do this thing (a little bit complicated, but it
will preserve the abstractions), would be the following:
- Define the abstract interface for the CU providers (you can use Source module
or just define it manually with the interface you like)
- Write plugins that will provide implementations
(i.e., using readelf, objdump, IDA, LLVM, or whatever). The implementation shall
- Write plugins that will provide implementations
(i.e., using readelf, objdump, IDA, LLVM, or whatever). The implementation shall
subscribe to Project.Info.file information stream and generate CU information every time a new file is open.
Of course, for the prototype your approach will work,
Of course, for the prototype your approach will work,
but in general case it is better to use the approach described above. *)
let
name
=
"CWE215"
...
...
@@ -29,8 +29,8 @@ let read_lines in_chan =
In_channel
.
close
in_chan
;
List
.
rev
!
lines
(* TODO: check if program contains strings like "DEBUG"*)
let
check_cwe
_
project
_
_
=
(* TODO: check if program contains strings like "DEBUG"*)
let
check_cwe
_
project
_
_
_
=
match
Project
.
get
project
filename
with
|
Some
fname
->
begin
let
cmd
=
Format
.
sprintf
"readelf --debug-dump=decodedline %s | grep CU"
fname
in
...
...
@@ -38,8 +38,7 @@ let check_cwe _ project _ _ =
let
in_chan
=
Unix
.
open_process_in
cmd
in
read_lines
in_chan
|>
List
.
iter
~
f
:
(
fun
l
->
Log_utils
.
warn
"[%s] {%s} (Information Exposure Through Debug Information) %s"
name
version
l
)
with
Unix
.
Unix_error
(
e
,
fm
,
argm
)
->
Unix
.
Unix_error
(
e
,
fm
,
argm
)
->
Log_utils
.
error
"[%s] {%s} %s %s %s"
name
version
(
Unix
.
error_message
e
)
fm
argm
end
|
_
->
failwith
"[CWE215] symbol_names not as expected"
src/checkers/cwe_215.mli
View file @
41b84a41
(** This module checks if a binary contains sensitive debugging information that could be leveraged to
(** This module checks if a binary contains sensitive debugging information that could be leveraged to
get a better understanding of it in less time. This is basically CWE-215 (https://cwe.mitre.org/data/definitions/215.html *)
val
name
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/checkers/cwe_243.ml
View file @
41b84a41
open
Core_kernel
.
Std
open
Bap
.
Std
open
Symbol_utils
open
Symbol_utils
include
Self
()
...
...
@@ -30,10 +30,10 @@ let get_call_dests_of_sub sub =
end
|
_
->
[]
let
rec
check
dests
symbols
=
let
rec
check
dests
symbols
=
match
dests
with
|
[]
->
(
List
.
length
symbols
)
=
0
|
hd
::
tl
->
|
hd
::
tl
->
begin
match
symbols
with
|
[]
->
true
...
...
@@ -45,7 +45,7 @@ let rec check dests symbols =
end
let
check_route
sub
symbols
=
let
call_dests
=
get_call_dests_of_sub
sub
in
let
call_dests
=
get_call_dests_of_sub
sub
in
let
res
=
check
call_dests
symbols
in
if
res
then
res
else
res
...
...
@@ -62,7 +62,7 @@ let check_path prog tid_map sub path =
else
false
(** Checks a subfunction for CWE-243. Only functions that actually call "chroot" are considered.
(** Checks a subfunction for CWE-243. Only functions that actually call "chroot" are considered.
It checks each of the configured VALID pathes found in config.json, e.g.
"chroot_pathes": [["chroot", "chdir"], ["chdir", "chroot", "setresuid"], ["chdir", "chroot", "seteuid"],
["chdir", "chroot", "setreuid"], ["chdir", "chroot", "setuid"]].
...
...
@@ -81,10 +81,9 @@ let check_subfunction prog tid_map sub pathes =
(
Term
.
name
sub
)
end
let
check_cwe
prog
proj
tid_map
pathes
=
let
check_cwe
prog
proj
tid_map
pathes
_
=
let
chroot_symbol
=
find_symbol
prog
"chroot"
in
match
chroot_symbol
with
|
Some
_
->
Seq
.
iter
(
Term
.
enum
sub_t
prog
)
~
f
:
(
fun
sub
->
check_subfunction
prog
tid_map
sub
pathes
)
|
_
->
()
src/checkers/cwe_243.mli
View file @
41b84a41
(** This module implements a check for CWE-243 (Creation of chroot Jail Without Changing Working Directory).
According to http://www.unixwiz.net/techtips/chroot-practices.html, there are several ways to achieve the
According to http://www.unixwiz.net/techtips/chroot-practices.html, there are several ways to achieve the
safe creation of a chroot jail, e.g. chdir -> chroot -> setuid. They are configurable in config.json.
See https://cwe.mitre.org/data/definitions/243.html for detailed description. *)
val
name
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/checkers/cwe_248.ml
View file @
41b84a41
...
...
@@ -59,7 +59,7 @@ let rec find_uncaught_exceptions subfunction already_checked_functions program ~
(* Search for uncatched exceptions for each entry point into the binary.
TODO: Exceptions, that are catched when starting from one entry point, but not from another, are masked this
way. We should check whether this produces a lot of false negatives. *)
let
check_cwe
program
project
tid_map
symbol_pairs
=
let
check_cwe
program
project
tid_map
symbol_pairs
_
=
let
entry_points
=
Symbol_utils
.
get_program_entry_points
program
in
let
_
=
Seq
.
fold
entry_points
~
init
:
[]
~
f
:
(
fun
already_checked_functions
sub
->
find_uncaught_exceptions
~
tid_map
:
tid_map
sub
already_checked_functions
program
)
in
()
src/checkers/cwe_248.mli
View file @
41b84a41
...
...
@@ -8,4 +8,4 @@ can actually catch the thrown exceptions, thus we generate some false negatives.
val
name
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/checkers/cwe_332.ml
View file @
41b84a41
open
Bap
.
Std
open
Core_kernel
.
Std
open
Graph_utils
open
Graph_utils
open
Symbol_utils
let
name
=
"CWE332"
let
version
=
"0.1"
let
version
=
"0.1"
let
check_cwe
program
proj
tid_map
symbol_pairs
=
let
check_cwe
program
proj
tid_map
symbol_pairs
_
=
match
Option
.
both
(
find_symbol
program
"srand"
)
(
find_symbol
program
"rand"
)
with
|
None
->
begin
match
(
find_symbol
program
"rand"
)
with
...
...
@@ -15,4 +15,3 @@ let check_cwe program proj tid_map symbol_pairs =
|
Some
_
->
Log_utils
.
warn
"[%s] {%s} (Insufficient Entropy in PRNG) program uses rand without calling srand before"
name
version
end
|
Some
(
srand_tid
,
rand_tid
)
->
()
src/checkers/cwe_332.mli
View file @
41b84a41
(** This module implements a check for CWE332 (Insufficient Entropy in PRNG).
This can happen, for instance, if the PRNG is not seeded. A classical example
would be calling rand without srand. This could lead to predictable random
numbers and could, for example, weaken crypto functionality.
numbers and could, for example, weaken crypto functionality.
See https://cwe.mitre.org/data/definitions/332.html for detailed description. *)
val
name
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
'
a
->
'
b
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
'
a
->
'
b
->
string
list
list
->
'
c
->
unit
src/checkers/cwe_367.ml
View file @
41b84a41
...
...
@@ -18,14 +18,14 @@ let get_calls_to_symbol symbol_name callsites program =
let
get_blk_tid_of_tid
sub
tid
=
let
blk
=
Seq
.
find
(
Term
.
enum
blk_t
sub
)
~
f
:
(
fun
b
->
fun
b
->
match
Term
.
last
jmp_t
b
with
|
Some
last_term
->
tid
=
(
Term
.
tid
last_term
)
|
None
->
false
)
in
match
blk
with
|
Some
b
->
Term
.
tid
b
|
_
->
assert
(
false
)
let
is_reachable
sub
source
sink
=
let
cfg
=
Sub
.
to_graph
sub
in
let
source_tid
=
Term
.
tid
source
in
...
...
@@ -57,6 +57,6 @@ let handle_sub sub program tid_map symbols source sink =
else
()
let
check_cwe
program
proj
tid_map
symbol_pairs
=
let
check_cwe
program
proj
tid_map
symbol_pairs
_
=
let
symbols
=
Symbol_utils
.
build_symbols
[
"access"
;
"open"
;]
in
Seq
.
iter
(
Term
.
enum
sub_t
program
)
~
f
:
(
fun
s
->
handle_sub
s
program
tid_map
symbols
"access"
"open"
)
src/checkers/cwe_367.mli
View file @
41b84a41
...
...
@@ -3,6 +3,6 @@ CWE-367 (Time-of-check Time-of-use (TOCTOU) Race Condition)
https://en.wikipedia.org/wiki/Time_of_check_to_time_of_use
*)
val
name
:
string
val
version
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/checkers/cwe_426.ml
View file @
41b84a41
...
...
@@ -20,8 +20,8 @@ let handle_sub sub program tid_map symbols =
()
end
else
()
let
check_cwe
program
proj
tid_map
symbols
=
let
check_cwe
program
proj
tid_map
symbols
_
=
match
symbols
with
|
hd
::
[]
->
Seq
.
iter
(
Term
.
enum
sub_t
program
)
~
f
:
(
fun
s
->
handle_sub
s
program
tid_map
hd
)
...
...
src/checkers/cwe_426.mli
View file @
41b84a41
(** This module checks for CWE-426 (Untrusted Search Path) (https://cwe.mitre.org/data/definitions/426.html). Basically, the program searches
for critical resources on an untrusted search path that can be adjusted by an adversary. For example, see Nebula Level 1
(https://exploit-exercises.com/nebula/level01/).
(https://exploit-exercises.com/nebula/level01/).
According to "man system" the following problems can arise:
"Do not use system() from a program with set-user-ID or set-group-ID privileges, because strange values for some environment variables might
be used to subvert system integrity. Use the exec(3) family of functions instead, but not execlp(3) or execvp(3). system() will not, in
fact, work properly from programs with set-user-ID or set-group-ID privileges on systems on which /bin/sh is bash version 2, since bash 2
"Do not use system() from a program with set-user-ID or set-group-ID privileges, because strange values for some environment variables might
be used to subvert system integrity. Use the exec(3) family of functions instead, but not execlp(3) or execvp(3). system() will not, in
fact, work properly from programs with set-user-ID or set-group-ID privileges on systems on which /bin/sh is bash version 2, since bash 2
drops privileges on startup. (Debian uses a modified bash which does not do this when invoked as sh.)"
*)
val
name
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/checkers/cwe_457.ml
View file @
41b84a41
...
...
@@ -38,7 +38,7 @@ let get_min_fp_offset arch =
match
arch
with
|
`x86
|
`x86_64
->
0x10000
|
_
->
0x0
(*FIXME: this is architecture dependent and ugly*)
let
get_fp_of_arch
arch
=
match
arch
with
...
...
@@ -91,6 +91,6 @@ let check_subfunction prog proj tid_map sub =
end
)
end
end
)
let
check_cwe
prog
proj
tid_map
symbol_names
=
let
check_cwe
prog
proj
tid_map
symbol_names
_
=
Seq
.
iter
(
Term
.
enum
sub_t
prog
)
~
f
:
(
fun
sub
->
check_subfunction
prog
proj
tid_map
sub
)
src/checkers/cwe_457.mli
View file @
41b84a41
...
...
@@ -4,4 +4,4 @@ See https://cwe.mitre.org/data/definitions/457.html for detailed description. *)
val
name
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/checkers/cwe_467.ml
View file @
41b84a41
open
Core_kernel
.
Std
open
Bap
.
Std
open
Symbol_utils
open
Symbol_utils
let
name
=
"CWE467"
let
version
=
"0.1"
let
get_pointer_size
arch
=
Size
.
in_bytes
@@
Arch
.
addr_size
arch
Size
.
in_bytes
@@
Arch
.
addr_size
arch
let
check_input_is_pointer_size
proj
prog
sub
blk
jmp
tid_map
symbols
=
Seq
.
iter
(
Term
.
enum
def_t
blk
)
~
f
:
(
fun
d
->
match
Exp
.
eval
@@
Def
.
rhs
d
with
...
...
@@ -23,11 +23,11 @@ let check_input_is_pointer_size proj prog sub blk jmp tid_map symbols =
end
|
_
->
()
)
let
check_cwe
prog
proj
tid_map
symbol_names
=
let
check_cwe
prog
proj
tid_map
symbol_names
_
=
match
symbol_names
with
|
hd
::
[]
->
let
symbols
=
Symbol_utils
.
build_symbols
hd
prog
in
let
symbols
=
Symbol_utils
.
build_symbols
hd
prog
in
let
calls
=
call_finder
#
run
prog
[]
in
let
relevant_calls
=
filter_calls_to_symbols
calls
symbols
in
check_calls
relevant_calls
prog
proj
tid_map
symbols
check_input_is_pointer_size
...
...
src/checkers/cwe_467.mli
View file @
41b84a41
...
...
@@ -2,11 +2,11 @@
In a nutshell, it before a function call to symbols like malloc and memmove, which
take a size parameter and a pointer to data as input, if not accidentally the size
of the pointer instead of the data is passed. This can have severe consequences.
The check is quite basic: it checks if before the call an immediate value that
The check is quite basic: it checks if before the call an immediate value that
equals the size of a pointer (e.g. 4 bytes on x86) is referenced (e.g. pushed
onto the stack).The symbols are configurable in config.json.
See https://cwe.mitre.org/data/definitions/467.html for detailed description. *)
val
name
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/checkers/cwe_476.ml
View file @
41b84a41
open
Core_kernel
.
Std
open
Bap
.
Std
open
Symbol_utils
open
Core_kernel
.
Std
let
name
=
"CWE476"
let
version
=
"0.1"
let
find_blk_tid_in_sub
blk_tid
sub
=
Seq
.
find
(
Term
.
enum
blk_t
sub
)
~
f
:
(
fun
b
->
(
Term
.
tid
b
)
=
blk_tid
)
let
get_jmps
blk
=
Seq
.
filter
(
Blk
.
elts
blk
)
~
f
:
(
fun
elt
->
match
elt
with
|
`Phi
phi
->
false
|
`Def
def
->
false
|
`Jmp
jmp
->
true
)
|>
Seq
.
map
~
f
:
(
fun
j
->
match
j
with
|
`Jmp
jmp
->
jmp
|
_
->
assert
(
false
))
let
jmp_cond_checks_zf
jmp
=
let
e
=
Jmp
.
cond
jmp
in
(
Exp
.
to_string
e
)
=
"~ZF"
||
(
Exp
.
to_string
e
)
=
"ZF"
(* Check if next block contains when zf = 0 goto, if not then there is a chance that this yields a null pointer deref *)
let
check_null_pointer
proj
prog
sub
blk
jmp
tid_map
symbols
=
Seq
.
iter
(
Graphs
.
Tid
.
Node
.
succs
(
Term
.
tid
blk
)
(
Sub
.
to_graph
sub
))
~
f
:
(
fun
next_blk
->
match
find_blk_tid_in_sub
next_blk
sub
with
|
Some
b
->
begin
(* ToDo: Check if there is a definition of ZF = 0 *)
let
jmps
=
get_jmps
b
in
match
Seq
.
find
jmps
~
f
:
jmp_cond_checks_zf
with
|
Some
_
->
()
|
None
->
Log_utils
.
warn
"[%s] {%s} (NULL Pointer Dereference) There is no check if the return value is NULL at %s (%s)."
name
version
(
Address_translation
.
translate_tid_to_assembler_address_string
(
Term
.
tid
blk
)
tid_map
)
(
Symbol_utils
.
get_symbol_name_from_jmp
jmp
symbols
)
end
|
_
->
assert
(
false
))
let
check_cwe
prog
proj
tid_map
symbol_names
=
match
symbol_names
with
|
hd
::
[]
->
let
symbols
=
Symbol_utils
.
build_symbols
hd
prog
in
let
calls
=
call_finder
#
run
prog
[]
in
let
relevant_calls
=
filter_calls_to_symbols
calls
symbols
in
check_calls
relevant_calls
prog
proj
tid_map
symbols
check_null_pointer
|
_
->
failwith
"[CWE476] symbol_names not as expected"
let
version
=
"0.2"
(* Access type denotes whether a variable var gets accessed or the memory stored at
address var gets accessed *)
type
access_type
=
|
Access
of
Bil
.
var
|
MemAccess
of
Bil
.
var
|
NoAccess
(* The union of two accesses is the higher access with MemAcces > Access > NoAccess *)
let
union_access
access1
access2
:
access_type
=
match
(
access1
,
access2
)
with
|
(
MemAccess
(
_
)
,
_
)
->
access1
|
(
_
,
MemAccess
(
_
))
|
(
_
,
Access
(
_
))
->
access2
|
_
->
access1
(* union of three accesses for convenience *)
let
union_access_triple
access1
access2
access3
=
union_access
access1
access2
|>
union_access
access3
(* the state contains a list of pairs of register names containing an unchecked
return value and the term identifiers of the block where the unchecked
return value was generated. *)
module
State
=
struct
type
t
=
(
Var
.
t
*
Tid
.
t
)
list
(** adds var as a tainted register (with the taint source given by tid) *)
let
add
state
var
tid
=
let
state
=
List
.
Assoc
.
remove
state
~
equal
:
Var
.(
=
)
var
in
List
.
Assoc
.
add
state
~
equal
:
Var
.(
=
)
var
tid
(** returns Some(tid) if var is a tainted register, None otherwise *)
let
find
state
var
=
List
.
Assoc
.
find
state
~
equal
:
Var
.(
=
)
var
(** returns the tid associated with a tainted register *)
let
find_exn
state
var
=
Option
.
value_exn
(
find
state
var
)
(** only remove the register var from the list of tainted registers *)
let
remove_var
state
var
=
List
.
Assoc
.
remove
state
~
equal
:
Var
.(
=
)
var
(** filters out all registers from the state with the same tid *)
let
remove_tid
state
var
=
let
tid
=
find_exn
state
var
in
List
.
filter
state
~
f
:
(
fun
(
_
,
state_elem_tid
)
->
not
(
state_elem_tid
=
tid
))
(** two states are equal if they contain the same set of tainted registers*)
let
equal
state1
state2
=
(
List
.
length
state1
)
=
(
List
.
length
state2
)
&&
not
(
List
.
exists
state1
~
f
:
(
fun
(
var
,
tid
)
->
Option
.
is_none
(
find
state2
var
)
))
(** The union of two states is the union of the tainted registers*)
let
union
state1
state2
=
List
.
fold
state2
~
init
:
state1
~
f
:
(
fun
state
(
var
,
tid
)
->
if
Option
.
is_some
(
find
state
var
)
then
state
else
(
var
,
tid
)
::
state
)
(** remove virtual registers from the state (useful at the end of a block) *)
let
remove_virtual_registers
state
=
List
.
filter
state
~
f
:
(
fun
(
var
,
tid
)
->
Var
.
is_physical
var
)
end
(* check whether an expression contains an unchecked value. *)
let
rec
contains_unchecked
exp
state
:
access_type
=
match
exp
with
|
Bil
.
Load
(
mem
,
addr
,
_
,
_
)
->
begin
let
acc
=
contains_unchecked
addr
state
in
match
acc
with
|
MemAccess
(
_
)
->
acc
|
Access
(
var
)
->
MemAccess
(
var
)
|
NoAccess
->
NoAccess
end
|
Bil
.
Store
(
mem
,
addr
,
val_expression
,
_
,_
)
->
begin
let
acc
=
union_access
(
contains_unchecked
addr
state
)
(
contains_unchecked
val_expression
state
)
in
match
acc
with
|
MemAccess
(
_
)
->
acc
|
Access
(
var
)
->
MemAccess
(
var
)
|
NoAccess
->
NoAccess
end
|
Bil
.
BinOp
(
_
,
exp1
,
exp2
)
->
union_access
(
contains_unchecked
exp1
state
)
(
contains_unchecked
exp2
state
)
|
Bil
.
UnOp
(
_
,
exp
)
->
contains_unchecked
exp
state
|
Bil
.
Var
(
var
)
->
begin
match
State
.
find
state
var
with
|
Some
(
_
)
->
Access
(
var
)
|
None
->
NoAccess
end
|
Bil
.
Int
(
_
)
->
NoAccess
|
Bil
.
Cast
(
_
,
_
,
exp
)
->
contains_unchecked
exp
state
|
Bil
.
Let
(
var
,
exp1
,
exp2
)
->
union_access_triple
(
contains_unchecked
exp1
state
)
(
contains_unchecked
exp2
state
)
(
contains_unchecked
(
Bil
.
var
var
)
state
)
|
Bil
.
Unknown
(
_
)
->
NoAccess
|
Bil
.
Ite
(
if_
,
then_
,
else_
)
->
union_access_triple
(
contains_unchecked
if_
state
)
(
contains_unchecked
then_
state
)
(
contains_unchecked
else_
state
)
|
Bil
.
Extract
(
_
,_,
exp
)
->
contains_unchecked
exp
state
|
Bil
.
Concat
(
exp1
,
exp2
)
->
union_access
(
contains_unchecked
exp1
state
)
(
contains_unchecked
exp2
state
)
(* If an formerly unchecked return value was checked then remove all registers pointing
to the source of this return value from state. *)
let
checks_value
exp
state
:
State
.
t
=
match
exp
with
|
Bil
.
Ite
(
if_
,
then_
,
else_
)
->
begin
match
contains_unchecked
if_
state
with
|
Access
(
var
)
->
(* We filter out all registers with the same generating tid, since we have checked
the return value of this source *)
State
.
remove_tid
state
var
|
MemAccess
(
_
)
(* This is a memory access before checking the return value, so do nothing here. *)
|
NoAccess
->
state
end
|
_
->
state
let
append_to_hits
(
cwe_hits
:
Tid
.
t
list
ref
)
(
tid
:
Tid
.
t
)
=
match
List
.
find
cwe_hits
.
contents
~
f
:
(
fun
elem
->
elem
=
tid
)
with
|
Some
(
_
)
->
()
|
None
->
(
cwe_hits
:=
(
tid
::
cwe_hits
.
contents
))
(** flags any access (not just memory access) from an unchecked source as a cwe_hit. *)
let
flag_any_access
exp
state
~
cwe_hits
=
match
contains_unchecked
exp
state
with
|
MemAccess
(
var
)
|
Access
(
var
)
->
let
tid
=
State
.
find_exn
state
var
in
append_to_hits
cwe_hits
tid
;
State
.
remove_tid
state
var
|
NoAccess
->
state
(** flag all unchecked registers as cwe_hits, return empty state *)
let
flag_all_unchecked_registers
state
~
cwe_hits
=
let
()
=
List
.
iter
state
~
f
:
(
fun
(
var
,
tid
)
->
append_to_hits
cwe_hits
tid
)
in
[]
(** Updates the state depending on the def. If memory is accessed using an unchecked return value,
then the access is added to the list of cwe_hits. *)
let
update_state_def
def
state
~
cwe_hits
=
let
(
lhs
,
rhs
)
=
(
Def
.
lhs
def
,
Def
.
rhs
def
)
in
let
state
=
checks_value
rhs
state
in
match
contains_unchecked
rhs
state
with
|
MemAccess
(
var
)
->
begin
(* we found a case of unchecked return value *)
let
tid
=
State
.
find_exn
state
var
in
append_to_hits
cwe_hits
tid
;
State
.
remove_tid
state
var
end
|
Access
(
var
)
->
(* taint the lhs as an unchecked return value *)
let
tid
=
State
.
find_exn
state
var
in
State
.
add
state
lhs
tid
|
NoAccess
->
(* no access to an unchecked return value in rhs. Since lhs is overwritten, it cannot be an unchecked return value anymore. *)
State
.
remove_var
state
lhs
(** Taint the return registers of a function as unchecked return values. *)
let
taint_return_registers
func_tid
state
~
program
~
block
=
let
func
=
Term
.
find_exn
sub_t
program
func_tid
in
let
arguments
=
Term
.
enum
arg_t
func
in
(* Every return register is tainted as unchecked return value. *)
Seq
.
fold
arguments
~
init
:
state
~
f
:
(
fun
state
arg
->
match
Bap
.
Std
.
Arg
.
intent
arg
with
|
None
|
Some
(
In
)
->
state
|
Some
(
Out
)
|
Some
(
Both
)
->
let
variable
=
match
Bap
.
Std
.
Arg
.
rhs
arg
with
|
Bil
.
Var
(
var
)
->
var
|
_
->
failwith
"[CWE476] Return register wasn't a register."
in
State
.
add
state
variable
(
Term
.
tid
block
)
)
(** Updates the state depending on the jump. On a jump to a function from the function list
taint all return registers as unchecked return values. *)
let
update_state_jmp
jmp
state
~
cwe_hits
~
function_names
~
program
~
block
~
strict_call_policy
=
(* first check the guard condition for unchecked access. Any normal access clears the access from being unchecked *)
let
condition_exp
=
Jmp
.
cond
jmp
in
let
state
=
begin
match
contains_unchecked
condition_exp
state
with
|
Access
(
var
)
->
State
.
remove_tid
state
var
|
MemAccess
(
var
)
->
(* a memory access using an unchecked value is still an error *)
let
tid
=
State
.
find_exn
state
var
in
let
()
=
append_to_hits
cwe_hits
tid
in
State
.
remove_tid
state
var
|
NoAccess
->
state
end
in
match
Jmp
.
kind
jmp
with
|
Goto
(
Indirect
(
exp
))
->
flag_any_access
exp
state
cwe_hits
|
Goto
(
Direct
(
_
))
->
state
|
Ret
(
_
)
->
if
strict_call_policy
then
flag_all_unchecked_registers
state
cwe_hits
else
state
|
Int
(
_
,
_
)
->
flag_all_unchecked_registers
state
cwe_hits
|
Call
(
call
)
->
let
state
=
match
Call
.
return
call
with
|
Some
(
Indirect
(
exp
))
->
flag_any_access
exp
state
cwe_hits
|
_
->
state
in
let
state
=
match
Call
.
target
call
with
|
Indirect
(
exp
)
->
flag_any_access
exp
state
cwe_hits
|
_
->
state
in
let
state
=
match
strict_call_policy
with
|
true
->
(* all unchecked registers get flagged as hits *)
flag_all_unchecked_registers
state
cwe_hits
|
false
->
(* we assume that the callee will check all remaining unchecked values *)
[]
in
match
Call
.
target
call
with
|
Indirect
(
_
)
->
state
(* already handled above *)
|
Direct
(
tid
)
->
if
List
.
exists
function_names
~
f
:
(
fun
elem
->
String
.(
=
)
elem
(
Tid
.
name
tid
))
then
taint_return_registers
tid
state
program
block
else
state
(** updates a block analysis.
The strict call policy decides the behaviour on call and return instructions:
strict: all unchecked values get flagged as cwe-hits
non-strict: the state gets cleared, it is assumed that the target of the call/return
instruction checks all remaining unchecked values. *)
let
update_block_analysis
block
register_state
~
cwe_hits
~
function_names
~
program
~
strict_call_policy
=
let
elements
=
Blk
.
elts
block
in
let
register_state
=
Seq
.
fold
elements
~
init
:
register_state
~
f
:
(
fun
state
element
->
match
element
with
|
`Def
def
->
update_state_def
def
state
~
cwe_hits
|
`Phi
phi
->
state
(* We ignore phi terms for this analysis. *)
|
`Jmp
jmp
->
update_state_jmp
jmp
state
~
cwe_hits
~
function_names
~
program
~
block
~
strict_call_policy
)
in
State
.
remove_virtual_registers
register_state
(* virtual registers should not be accessed outside of the block where they are defined. *)
let
print_hit
tid
~
sub
~
function_names
~
tid_map
=
let
block
=
Option
.
value_exn
(
Term
.
find
blk_t
sub
tid
)
in
let
jmps
=
Term
.
enum
jmp_t
block
in
let
_
=
Seq
.
find_exn
jmps
~
f
:
(
fun
jmp
->
match
Jmp
.
kind
jmp
with
|
Call
(
call
)
->
begin
match
Call
.
target
call
with
|
Direct
(
call_tid
)
->
Option
.
is_some
(
List
.
find
function_names
~
f
:
(
fun
name
->
if
name
=
(
Tid
.
name
call_tid
)
then
begin
Log_utils
.
warn
"[%s] {%s} (NULL Pointer Dereference) There is no check if the return value is NULL at %s (%s)."
name
version
(
Address_translation
.
translate_tid_to_assembler_address_string
tid
tid_map
)
name
;
true
end
else
false
))
|
_
->
false
end
|
_
->
false
)
in
()
let
check_cwe
prog
proj
tid_map
symbol_names
parameters
=
let
symbols
=
match
symbol_names
with
|
hd
::
_
->
hd
|
_
->
failwith
"[CWE476] symbol_names not as expected"
in
let
(
strict_call_policy_string
,
max_steps_string
)
=
match
parameters
with
|
par1
::
par2
::
_
->
(
par1
,
par2
)
|
_
->
failwith
"[CWE476] parameters not as expected"
in
let
strict_call_policy
=
match
String
.
split
strict_call_policy_string
~
on
:
'
=
'
with
|
"strict_call_policy"
::
policy
::
[]
->
bool_of_string
policy
|
_
->
failwith
"[CWE476] parameters not as expected"
in
let
max_steps
=
match
String
.
split
max_steps_string
~
on
:
'
=
'
with
|
"max_steps"
::
num
::
[]
->
int_of_string
num
|
_
->
failwith
"[CWE476] parameters not as expected"
in
let
function_names
=
List
.
map
symbols
~
f
:
(
fun
symb
->
"@"
^
symb
)
in
let
subfunctions
=
Term
.
enum
sub_t
prog
in
Seq
.
iter
subfunctions
~
f
:
(
fun
subfn
->
let
cfg
=
Sub
.
to_cfg
subfn
in
let
cwe_hits
=
ref
[]
in
let
empty
=
Map
.
empty
Graphs
.
Ir
.
Node
.
comparator
in
let
init
=
Graphlib
.
Std
.
Solution
.
create
empty
[]
in
let
equal
=
State
.
equal
in
let
merge
=
State
.
union
in
let
f
=
(
fun
node
state
->
let
block
=
Graphs
.
Ir
.
Node
.
label
node
in
update_block_analysis
block
state
~
cwe_hits
~
function_names
~
program
:
prog
~
strict_call_policy
)
in
let
_
=
Graphlib
.
Std
.
Graphlib
.
fixpoint
(
module
Graphs
.
Ir
)
cfg
~
steps
:
max_steps
~
rev
:
false
~
init
:
init
~
equal
:
equal
~
merge
:
merge
~
f
:
f
in
List
.
iter
(
!
cwe_hits
)
~
f
:
(
fun
hit
->
print_hit
hit
~
sub
:
subfn
~
function_names
~
tid_map
)
)
src/checkers/cwe_476.mli
View file @
41b84a41
(** This module implements a check for CWE-476 (NULL Pointer Dereference).
It checks if the result of a function that may return a NULL value is checked immediately
for NULL. The symbols are configurable in config.json.
See https://cwe.mitre.org/data/definitions/476.html for detailed description. *)
val
name
:
string
It checks if the result of a function that may return a NULL value is checked
for NULL before any memory gets accessed using the return values. The symbols
are configurable in config.json. See https://cwe.mitre.org/data/definitions/476.html
for detailed description.
Parameters:
- strict_call_policy={true, false}: Determines behaviour on call and return instructions.
If false, we assume that the callee, resp. the caller on a return instruction,
checks all unchecked values still contained in the registers. If true, every
unchecked value on a call or return instruction gets reported.
- max_steps=<num>: Max number of steps for the dataflow fixpoint algorithm.
Notes: The check relies on Bap-generated stubs to identify return registers of the
checked functions. Therefore it only works for functions for which Bap generates
these stubs. *)
val
name
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/checkers/cwe_676.ml
View file @
41b84a41
...
...
@@ -35,7 +35,7 @@ let resolve_symbols prog symbols =
Seq
.
filter
~
f
:
(
fun
s
->
List
.
exists
~
f
:
(
fun
x
->
x
=
Sub
.
name
s
)
symbols
)
let
check_cwe
prog
proj
tid_map
symbol_names
=
let
check_cwe
prog
proj
tid_map
symbol_names
_
=
match
symbol_names
with
|
hd
::
[]
->
let
subfunctions
=
Term
.
enum
sub_t
prog
in
...
...
@@ -43,4 +43,3 @@ let check_cwe prog proj tid_map symbol_names =
get_calls_to_symbols
cg
subfunctions
(
resolve_symbols
prog
hd
)
|>
print_calls
~
tid_map
:
tid_map
|
_
->
failwith
"[CWE676] symbol_names not as expected"
src/checkers/cwe_676.mli
View file @
41b84a41
...
...
@@ -5,4 +5,4 @@ See https://cwe.mitre.org/data/definitions/676.html for detailed description. *)
val
name
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/checkers/cwe_782.ml
View file @
41b84a41
...
...
@@ -14,6 +14,6 @@ let handle_sub sub program tid_map symbols =
(
Address_translation
.
translate_tid_to_assembler_address_string
(
Term
.
tid
sub
)
tid_map
)
else
()
let
check_cwe
program
proj
tid_map
symbols
=
let
check_cwe
program
proj
tid_map
symbols
_
=
Seq
.
iter
(
Term
.
enum
sub_t
program
)
~
f
:
(
fun
s
->
handle_sub
s
program
tid_map
symbols
)
src/checkers/cwe_782.mli
View file @
41b84a41
...
...
@@ -4,4 +4,4 @@ https://cwe.mitre.org/data/definitions/782.html *)
val
name
:
string
val
version
:
string
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
val
check_cwe
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
src/config.json
View file @
41b84a41
...
...
@@ -95,6 +95,10 @@
"CWE476"
:
{
"_comment"
:
"any function that possibly returns a NULL value."
,
"_comment1"
:
"included functions of the following libs: stdlib.h, locale.h, stdio.h, cstring.h, wchar.h"
,
"parameters"
:
[
"strict_call_policy=true"
,
"max_steps=100"
],
"symbols"
:
[
"malloc"
,
"calloc"
,
...
...
src/cwe_checker.ml
View file @
41b84a41
...
...
@@ -7,50 +7,54 @@ open Yojson.Basic.Util
include
Self
()
type
cwe_module
=
{
cwe_func
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
unit
;
cwe_func
:
Bap
.
Std
.
program
Bap
.
Std
.
term
->
Bap
.
Std
.
project
->
Bap
.
Std
.
word
Bap
.
Std
.
Tid
.
Map
.
t
->
string
list
list
->
string
list
->
unit
;
name
:
string
;
version
:
string
;
requires_pairs
:
bool
;
has_parameters
:
bool
;
}
let
known_modules
=
[{
cwe_func
=
Cwe_190
.
check_cwe
;
name
=
Cwe_190
.
name
;
version
=
Cwe_190
.
version
;
requires_pairs
=
false
};
{
cwe_func
=
Cwe_215
.
check_cwe
;
name
=
Cwe_215
.
name
;
version
=
Cwe_215
.
version
;
requires_pairs
=
false
};
{
cwe_func
=
Cwe_243
.
check_cwe
;
name
=
Cwe_243
.
name
;
version
=
Cwe_243
.
version
;
requires_pairs
=
true
};
{
cwe_func
=
Cwe_248
.
check_cwe
;
name
=
Cwe_248
.
name
;
version
=
Cwe_248
.
version
;
requires_pairs
=
false
};
{
cwe_func
=
Cwe_332
.
check_cwe
;
name
=
Cwe_332
.
name
;
version
=
Cwe_332
.
version
;
requires_pairs
=
true
};
{
cwe_func
=
Cwe_367
.
check_cwe
;
name
=
Cwe_367
.
name
;
version
=
Cwe_367
.
version
;
requires_pairs
=
true
};
{
cwe_func
=
Cwe_426
.
check_cwe
;
name
=
Cwe_426
.
name
;
version
=
Cwe_426
.
version
;
requires_pairs
=
false
};
{
cwe_func
=
Cwe_457
.
check_cwe
;
name
=
Cwe_457
.
name
;
version
=
Cwe_457
.
version
;
requires_pairs
=
false
};
{
cwe_func
=
Cwe_467
.
check_cwe
;
name
=
Cwe_467
.
name
;
version
=
Cwe_467
.
version
;
requires_pairs
=
false
};
{
cwe_func
=
Cwe_476
.
check_cwe
;
name
=
Cwe_476
.
name
;
version
=
Cwe_476
.
version
;
requires_pairs
=
false
};
{
cwe_func
=
Cwe_676
.
check_cwe
;
name
=
Cwe_676
.
name
;
version
=
Cwe_676
.
version
;
requires_pairs
=
false
};
{
cwe_func
=
Cwe_782
.
check_cwe
;
name
=
Cwe_782
.
name
;
version
=
Cwe_782
.
version
;
requires_pairs
=
false
}]
let
known_modules
=
[{
cwe_func
=
Cwe_190
.
check_cwe
;
name
=
Cwe_190
.
name
;
version
=
Cwe_190
.
version
;
requires_pairs
=
false
;
has_parameters
=
false
};
{
cwe_func
=
Cwe_215
.
check_cwe
;
name
=
Cwe_215
.
name
;
version
=
Cwe_215
.
version
;
requires_pairs
=
false
;
has_parameters
=
false
};
{
cwe_func
=
Cwe_243
.
check_cwe
;
name
=
Cwe_243
.
name
;
version
=
Cwe_243
.
version
;
requires_pairs
=
true
;
has_parameters
=
false
};
{
cwe_func
=
Cwe_248
.
check_cwe
;
name
=
Cwe_248
.
name
;
version
=
Cwe_248
.
version
;
requires_pairs
=
false
;
has_parameters
=
false
};
{
cwe_func
=
Cwe_332
.
check_cwe
;
name
=
Cwe_332
.
name
;
version
=
Cwe_332
.
version
;
requires_pairs
=
true
;
has_parameters
=
false
};
{
cwe_func
=
Cwe_367
.
check_cwe
;
name
=
Cwe_367
.
name
;
version
=
Cwe_367
.
version
;
requires_pairs
=
true
;
has_parameters
=
false
};
{
cwe_func
=
Cwe_426
.
check_cwe
;
name
=
Cwe_426
.
name
;
version
=
Cwe_426
.
version
;
requires_pairs
=
false
;
has_parameters
=
false
};
{
cwe_func
=
Cwe_457
.
check_cwe
;
name
=
Cwe_457
.
name
;
version
=
Cwe_457
.
version
;
requires_pairs
=
false
;
has_parameters
=
false
};
{
cwe_func
=
Cwe_467
.
check_cwe
;
name
=
Cwe_467
.
name
;
version
=
Cwe_467
.
version
;
requires_pairs
=
false
;
has_parameters
=
false
};
{
cwe_func
=
Cwe_476
.
check_cwe
;
name
=
Cwe_476
.
name
;
version
=
Cwe_476
.
version
;
requires_pairs
=
false
;
has_parameters
=
true
};
{
cwe_func
=
Cwe_676
.
check_cwe
;
name
=
Cwe_676
.
name
;
version
=
Cwe_676
.
version
;
requires_pairs
=
false
;
has_parameters
=
false
};
{
cwe_func
=
Cwe_782
.
check_cwe
;
name
=
Cwe_782
.
name
;
version
=
Cwe_782
.
version
;
requires_pairs
=
false
;
has_parameters
=
false
}]
let
build_version_sexp
()
=
let
build_version_sexp
()
=
List
.
map
known_modules
~
f
:
(
fun
cwe
->
Format
.
sprintf
"(
\"
%s
\"
\"
%s
\"
)"
cwe
.
name
cwe
.
version
)
|>
String
.
concat
~
sep
:
" "
let
print_module_versions
()
=
Log_utils
.
info
"[cwe_checker] module_versions: (%s)"
(
build_version_sexp
()
)
let
execute_cwe_module
cwe
json
program
project
tid_address_map
=
let
parameters
=
match
cwe
.
has_parameters
with
|
false
->
[]
|
true
->
Json_utils
.
get_parameter_list_from_json
json
cwe
.
name
in
if
cwe
.
requires_pairs
=
true
then
begin
let
symbol_pairs
=
Json_utils
.
get_symbol_lists_from_json
json
cwe
.
name
in
cwe
.
cwe_func
program
project
tid_address_map
symbol_pairs
let
symbol_pairs
=
Json_utils
.
get_symbol_lists_from_json
json
cwe
.
name
in
cwe
.
cwe_func
program
project
tid_address_map
symbol_pairs
parameters
end
else
begin
let
symbols
=
Json_utils
.
get_symbols_from_json
json
cwe
.
name
in
cwe
.
cwe_func
program
project
tid_address_map
[
symbols
]
let
symbols
=
Json_utils
.
get_symbols_from_json
json
cwe
.
name
in
cwe
.
cwe_func
program
project
tid_address_map
[
symbols
]
parameters
end
let
partial_run
project
config
modules
=
let
program
=
Project
.
program
project
in
let
program
=
Project
.
program
project
in
let
tid_address_map
=
Address_translation
.
generate_tid_map
program
in
let
json
=
Yojson
.
Basic
.
from_file
config
in
let
json
=
Yojson
.
Basic
.
from_file
config
in
Log_utils
.
info
"[cwe_checker] Just running the following analyses: %s."
modules
;
List
.
iter
(
String
.
split
modules
~
on
:
'
,
'
)
~
f
:
(
fun
cwe
->
try
begin
...
...
@@ -59,15 +63,15 @@ let partial_run project config modules =
execute_cwe_module
cwe_mod
json
program
project
tid_address_map
end
with
Not_found
->
failwith
"[CWE_CHECKER] Unknown CWE module"
)
let
full_run
project
config
=
let
full_run
project
config
=
let
program
=
Project
.
program
project
in
let
tid_address_map
=
Address_translation
.
generate_tid_map
program
in
let
json
=
Yojson
.
Basic
.
from_file
config
in
let
json
=
Yojson
.
Basic
.
from_file
config
in
begin
List
.
iter
known_modules
~
f
:
(
fun
cwe
->
execute_cwe_module
cwe
json
program
project
tid_address_map
)
end
let
main
config
module_versions
partial_update
project
=
Log_utils
.
set_log_level
Log_utils
.
DEBUG
;
Log_utils
.
set_output
stdout
;
...
...
@@ -89,7 +93,7 @@ let main config module_versions partial_update project =
partial_run
project
config
partial_update
end
end
module
Cmdline
=
struct
open
Config
let
config
=
param
string
"config"
~
doc
:
"Path to configuration file."
...
...
src/utils/json_utils.ml
View file @
41b84a41
...
...
@@ -23,3 +23,10 @@ let get_symbol_lists_from_json json cwe =
|>
filter_member
"pairs"
|>
flatten
|>
List
.
map
~
f
:
(
fun
l
->
List
.
map
(
to_list
l
)
~
f
:
to_string
)
let
get_parameter_list_from_json
json
cwe
=
[
json
]
|>
filter_member
cwe
|>
filter_member
"parameters"
|>
flatten
|>
List
.
map
~
f
:
to_string
src/utils/json_utils.mli
View file @
41b84a41
...
...
@@ -2,3 +2,4 @@
val
get_symbol_lists_from_json
:
Yojson
.
Basic
.
json
->
string
->
string
list
list
val
get_symbols_from_json
:
Yojson
.
Basic
.
json
->
string
->
string
list
val
get_parameter_list_from_json
:
Yojson
.
Basic
.
json
->
string
->
string
list
test/artificial_samples/cwe_476.c
View file @
41b84a41
#include <stdlib.h>
void
func1
(){
void
*
data
=
malloc
(
20
);
void
*
data
=
malloc
(
20
000
);
if
(
data
==
NULL
){
exit
(
42
);
}
...
...
@@ -9,13 +9,14 @@ void func1(){
}
void
func2
(){
void
*
data
=
malloc
(
20
);
int
*
data
=
malloc
(
200000
);
printf
(
"%i"
,
data
[
0
]);
free
(
data
);
}
}
void
main
()
{
func1
();
func2
();
}
test/artificial_samples/makefile
View file @
41b84a41
...
...
@@ -10,114 +10,117 @@ CPP_ARM=arm-linux-gnueabi-g++-5
CPP_MIPS
=
mips-linux-gnu-g++-5
CPP_PPC
=
powerpc-linux-gnu-g++-5
CFLAGS_X64
=
-O0
-g
-fno-stack-protector
-std
=
c11
CFLAGS_X86
=
-O0
-g
-m32
-fno-stack-protector
-std
=
c11
CFLAGS_ARM
=
-O0
-g
-fno-stack-protector
-std
=
c11
CFLAGS_MIPS
=
-O0
-g
-fno-stack-protector
-std
=
c11
CFLAGS_PPC
=
-O0
-g
-fno-stack-protector
-std
=
c11
CPPFLAGS_X64
=
-O0
-g
-fno-stack-protector
CPPFLAGS_X86
=
-O0
-g
-m32
-fno-stack-protector
CPPFLAGS_ARM
=
-O0
-g
-fno-stack-protector
CPPFLAGS_MIPS
=
-O0
-g
-fno-stack-protector
CPPFLAGS_PPC
=
-O0
-g
-fno-stack-protector
CFLAGS_X64
=
-g
-fno-stack-protector
-std
=
c11
CFLAGS_X86
=
-g
-m32
-fno-stack-protector
-std
=
c11
CFLAGS_ARM
=
-g
-fno-stack-protector
-std
=
c11
CFLAGS_MIPS
=
-g
-fno-stack-protector
-std
=
c11
CFLAGS_PPC
=
-g
-fno-stack-protector
-std
=
c11
CPPFLAGS_X64
=
-g
-fno-stack-protector
CPPFLAGS_X86
=
-g
-m32
-fno-stack-protector
CPPFLAGS_ARM
=
-g
-fno-stack-protector
CPPFLAGS_MIPS
=
-g
-fno-stack-protector
CPPFLAGS_PPC
=
-g
-fno-stack-protector
OPTIMIZE
=
-O3
NO_OPTIMIZE
=
-O0
define
compile_x64
@echo "Compiling x64 target
:
" $(1)
$(CC_x64)
$(CFLAGS_X64)
-o
build/
$
(
1
)
_x64.out
$
(
1
)
.c
execstack
-s
build/
$
(
1
)
_x64.out
$(CC_x64)
$(CFLAGS_X64)
$
(
2
)
-o
build/
$
(
1
)
_x64.out
$
(
1
)
.c
execstack
-s
build/
$
(
1
)
_x64.out
endef
define
compile_x64_cpp
@echo "Compiling x64 target
:
" $(1)
$(CPP_x64)
$(CPPFLAGS_X64)
-o
build/
$
(
1
)
_x64.out
$
(
1
)
.cpp
$(CPP_x64)
$(CPPFLAGS_X64)
$
(
2
)
-o
build/
$
(
1
)
_x64.out
$
(
1
)
.cpp
execstack
-s
build/
$
(
1
)
_x64.out
endef
define
compile_x86
@echo "Compiling x86 target
:
" $(1)
$(CC_X86)
$(CFLAGS_X86)
-o
build/
$
(
1
)
_x86.out
$
(
1
)
.c
$(CC_X86)
$(CFLAGS_X86)
$
(
2
)
-o
build/
$
(
1
)
_x86.out
$
(
1
)
.c
execstack
-s
build/
$
(
1
)
_x86.out
endef
define
compile_x86_cpp
@echo "Compiling x86 target
:
" $(1)
$(CPP_X86)
$(CPPFLAGS_X86)
-o
build/
$
(
1
)
_x86.out
$
(
1
)
.cpp
$(CPP_X86)
$(CPPFLAGS_X86)
$
(
2
)
-o
build/
$
(
1
)
_x86.out
$
(
1
)
.cpp
execstack
-s
build/
$
(
1
)
_x86.out
endef
define
compile_mips
@echo "Compiling mips target
:
" $(1)
$(CC_MIPS)
$(CFLAGS_MIPS)
-o
build/
$
(
1
)
_mips.out
$
(
1
)
.c
$(CC_MIPS)
$(CFLAGS_MIPS)
$
(
2
)
-o
build/
$
(
1
)
_mips.out
$
(
1
)
.c
execstack
-s
build/
$
(
1
)
_mips.out
endef
define
compile_mips_cpp
@echo "Compiling mips target
:
" $(1)
$(CPP_MIPS)
$(CPPFLAGS_MIPS)
-o
build/
$
(
1
)
_mips.out
$
(
1
)
.cpp
$(CPP_MIPS)
$(CPPFLAGS_MIPS)
$
(
2
)
-o
build/
$
(
1
)
_mips.out
$
(
1
)
.cpp
execstack
-s
build/
$
(
1
)
_mips.out
endef
define
compile_arm
@echo "Compiling arm target
:
" $(1)
$(CC_ARM)
$(CFLAGS_ARM)
-o
build/
$
(
1
)
_arm.out
$
(
1
)
.c
$(CC_ARM)
$(CFLAGS_ARM)
$
(
2
)
-o
build/
$
(
1
)
_arm.out
$
(
1
)
.c
execstack
-s
build/
$
(
1
)
_arm.out
endef
define
compile_arm_cpp
@echo "Compiling arm target
:
" $(1)
$(CPP_ARM)
$(CPPFLAGS_ARM)
-o
build/
$
(
1
)
_arm.out
$
(
1
)
.cpp
$(CPP_ARM)
$(CPPFLAGS_ARM)
$
(
2
)
-o
build/
$
(
1
)
_arm.out
$
(
1
)
.cpp
execstack
-s
build/
$
(
1
)
_arm.out
endef
define
compile_ppc
@echo "Compiling ppc target
:
" $(1)
$(CC_PPC)
$(CFLAGS_PPC)
-o
build/
$
(
1
)
_ppc.out
$
(
1
)
.c
$(CC_PPC)
$(CFLAGS_PPC)
$
(
2
)
-o
build/
$
(
1
)
_ppc.out
$
(
1
)
.c
execstack
-s
build/
$
(
1
)
_ppc.out
endef
define
compile_ppc_cpp
@echo "Compiling ppc target
:
" $(1)
$(CPP_PPC)
$(CPPFLAGS_PPC)
-o
build/
$
(
1
)
_ppc.out
$
(
1
)
.cpp
$(CPP_PPC)
$(CPPFLAGS_PPC)
$
(
2
)
-o
build/
$
(
1
)
_ppc.out
$
(
1
)
.cpp
execstack
-s
build/
$
(
1
)
_ppc.out
endef
define
compile_all
$(shell
mkdir
-p
"build"
)
$(call
compile_x64,$(1))
$(call
compile_x86,$(1))
$(call
compile_arm,$(1))
$(call
compile_mips,$(1))
$(call
compile_ppc,$(1))
$(call
compile_x64,$(1)
,$(2)
)
$(call
compile_x86,$(1)
,$(2)
)
$(call
compile_arm,$(1)
,$(2)
)
$(call
compile_mips,$(1)
,$(2)
)
$(call
compile_ppc,$(1)
,$(2)
)
endef
define
compile_all_cpp
$(shell
mkdir
-p
"build"
)
$(call
compile_x64_cpp,$(1))
$(call
compile_x86_cpp,$(1))
$(call
compile_arm_cpp,$(1))
$(call
compile_mips_cpp,$(1))
$(call
compile_ppc_cpp,$(1))
$(call
compile_x64_cpp,$(1)
,$(2)
)
$(call
compile_x86_cpp,$(1)
,$(2)
)
$(call
compile_arm_cpp,$(1)
,$(2)
)
$(call
compile_mips_cpp,$(1)
,$(2)
)
$(call
compile_ppc_cpp,$(1)
,$(2)
)
endef
all
:
$
(
call compile_all,c_constructs
)
$
(
call compile_all,cwe_190
)
$
(
call compile_all,cwe_243
)
$
(
call compile_all,cwe_243_clean
)
$
(
call compile_all_cpp,cwe_248
)
$
(
call compile_all,cwe_332
)
$
(
call compile_all,cwe_367
)
$
(
call compile_all,cwe_415
)
$
(
call compile_all,cwe_426
)
$
(
call compile_all,cwe_457
)
$
(
call compile_all,cwe_467
)
$
(
call compile_all,cwe_476
)
$
(
call compile_all,cwe_478
)
$
(
call compile_all,cwe_676
)
$
(
call compile_x64,cwe_782
)
$
(
call compile_all,arrays
)
$
(
call compile_all,memory_access
)
$
(
call compile_all,c_constructs
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_190
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_243
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_243_clean
,
$(NO_OPTIMIZE)
)
$
(
call compile_all_cpp,cwe_248
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_332
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_367
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_415
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_426
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_457
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_467
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_476
,
$(OPTIMIZE)
)
$
(
call compile_all,cwe_478
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,cwe_676
,
$(NO_OPTIMIZE)
)
$
(
call compile_x64,cwe_782
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,arrays
,
$(NO_OPTIMIZE)
)
$
(
call compile_all,memory_access
,
$(NO_OPTIMIZE)
)
clean
:
rm
-rf
build
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment