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
9eafce76
Unverified
Commit
9eafce76
authored
Jun 07, 2021
by
Enkelmann
Committed by
GitHub
Jun 07, 2021
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Expression propagation (#185)
parent
6810c1f8
Expand all
Show whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
359 additions
and
116 deletions
+359
-116
tests.rs
...ecker_lib/src/analysis/pointer_inference/context/tests.rs
+7
-76
trait_impls.rs
...lib/src/analysis/pointer_inference/context/trait_impls.rs
+3
-38
expression.rs
...checker_lib/src/intermediate_representation/expression.rs
+0
-0
tests.rs
...r_lib/src/intermediate_representation/expression/tests.rs
+122
-0
term.rs
src/cwe_checker_lib/src/intermediate_representation/term.rs
+223
-0
cwe_78.c
test/artificial_samples/cwe_78.c
+2
-2
lib.rs
test/src/lib.rs
+2
-0
No files found.
src/cwe_checker_lib/src/analysis/pointer_inference/context/tests.rs
View file @
9eafce76
...
@@ -395,97 +395,28 @@ fn specialize_conditional() {
...
@@ -395,97 +395,28 @@ fn specialize_conditional() {
let
mut
state
=
State
::
new
(
&
register
(
"RSP"
),
Tid
::
new
(
"func"
));
let
mut
state
=
State
::
new
(
&
register
(
"RSP"
),
Tid
::
new
(
"func"
));
state
.set_register
(
&
register
(
"RAX"
),
IntervalDomain
::
mock
(
-
10
,
20
)
.into
());
state
.set_register
(
&
register
(
"RAX"
),
IntervalDomain
::
mock
(
-
10
,
20
)
.into
());
let
condition
=
Expression
::
Var
(
Variable
::
mock
(
"FLAG"
,
1
));
let
condition
=
Expression
::
BinOp
{
// A complicated way of computing the result of `RAX <= 0`
// and assigning the result to the `FLAG` register.
let
defs
=
vec!
[
Def
::
assign
(
"def1"
,
register
(
"RAX"
),
Expression
::
Var
(
register
(
"RAX"
))),
Def
::
assign
(
"def_that_should_be_ignored"
,
Variable
::
mock
(
"FLAG"
,
1
),
Expression
::
Const
(
Bitvector
::
from_u8
(
42
)),
),
Def
::
assign
(
"def2"
,
Variable
::
mock
(
"FLAG_SLESS"
,
1
),
Expression
::
BinOp
{
lhs
:
Box
::
new
(
Expression
::
Var
(
register
(
"RAX"
))),
lhs
:
Box
::
new
(
Expression
::
Var
(
register
(
"RAX"
))),
op
:
BinOpType
::
IntSLess
,
op
:
BinOpType
::
IntSLessEqual
,
rhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
from_u64
(
0
))),
rhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
zero
(
ByteSize
::
new
(
8
)
.into
()))),
},
),
Def
::
assign
(
"def3"
,
Variable
::
mock
(
"FLAG_EQUAL"
,
1
),
Expression
::
BinOp
{
lhs
:
Box
::
new
(
Expression
::
Var
(
register
(
"RAX"
))),
op
:
BinOpType
::
IntEqual
,
rhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
from_u64
(
0
))),
},
),
Def
::
assign
(
"def4"
,
Variable
::
mock
(
"FLAG_NOTEQUAL"
,
1
),
Expression
::
BinOp
{
lhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"FLAG_SLESS"
,
1
))),
op
:
BinOpType
::
IntNotEqual
,
rhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
from_u8
(
0
))),
},
),
Def
::
assign
(
"def5"
,
Variable
::
mock
(
"FLAG"
,
1
),
Expression
::
BinOp
{
lhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"FLAG_EQUAL"
,
1
))),
op
:
BinOpType
::
BoolOr
,
rhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"FLAG_NOTEQUAL"
,
1
))),
},
),
];
let
block
=
Term
{
tid
:
Tid
::
new
(
"block"
),
term
:
Blk
{
defs
,
jmps
:
Vec
::
new
(),
indirect_jmp_targets
:
Vec
::
new
(),
},
};
};
let
block
=
Blk
::
mock
();
let
result
=
context
let
result
=
context
.specialize_conditional
(
&
state
,
&
condition
,
&
block
,
false
)
.specialize_conditional
(
&
state
,
&
condition
,
&
block
,
false
)
.unwrap
();
.unwrap
();
assert_eq!
(
assert_eq!
(
result
.get_register
(
&
Variable
::
mock
(
"FLAG"
,
1
)),
Bitvector
::
from_u8
(
0
)
.into
()
);
assert_eq!
(
result
.get_register
(
&
Variable
::
mock
(
"FLAG_NOTEQUAL"
,
1
)),
Bitvector
::
from_u8
(
0
)
.into
()
);
assert_eq!
(
result
.get_register
(
&
Variable
::
mock
(
"FLAG_EQUAL"
,
1
)),
Bitvector
::
from_u8
(
0
)
.into
()
);
assert_eq!
(
result
.get_register
(
&
Variable
::
mock
(
"FLAG_SLESS"
,
1
)),
Bitvector
::
from_u8
(
0
)
.into
()
);
// The result is technically false, since RAX == 0 should be excluded.
// This impreciseness is due to the way that the result is calculated.
assert_eq!
(
result
.get_register
(
&
register
(
"RAX"
)),
result
.get_register
(
&
register
(
"RAX"
)),
IntervalDomain
::
mock
(
0
,
20
)
.into
()
IntervalDomain
::
mock
(
1
,
20
)
.into
()
);
);
state
.set_register
(
&
register
(
"RAX"
),
IntervalDomain
::
mock
(
0
,
20
)
.into
());
state
.set_register
(
&
register
(
"RAX"
),
IntervalDomain
::
mock
(
0
,
20
)
.into
());
let
result
=
context
let
result
=
context
.specialize_conditional
(
&
state
,
&
condition
,
&
block
,
fals
e
)
.specialize_conditional
(
&
state
,
&
condition
,
&
block
,
tru
e
)
.unwrap
();
.unwrap
();
assert_eq!
(
assert_eq!
(
result
.get_register
(
&
register
(
"RAX"
)),
result
.get_register
(
&
register
(
"RAX"
)),
IntervalDomain
::
mock_with_bounds
(
Some
(
0
),
1
,
2
0
,
None
)
.into
()
IntervalDomain
::
mock_with_bounds
(
None
,
0
,
0
,
None
)
.into
()
);
);
state
.set_register
(
&
register
(
"RAX"
),
IntervalDomain
::
mock
(
-
20
,
0
)
.into
());
state
.set_register
(
&
register
(
"RAX"
),
IntervalDomain
::
mock
(
-
20
,
0
)
.into
());
...
...
src/cwe_checker_lib/src/analysis/pointer_inference/context/trait_impls.rs
View file @
9eafce76
use
super
::
*
;
use
super
::
*
;
use
std
::
collections
::
HashSet
;
impl
<
'a
>
crate
::
analysis
::
forward_interprocedural_fixpoint
::
Context
<
'a
>
for
Context
<
'a
>
{
impl
<
'a
>
crate
::
analysis
::
forward_interprocedural_fixpoint
::
Context
<
'a
>
for
Context
<
'a
>
{
type
Value
=
State
;
type
Value
=
State
;
...
@@ -346,12 +345,12 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
...
@@ -346,12 +345,12 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
/// Update the state with the knowledge that some conditional evaluated to true or false.
/// Update the state with the knowledge that some conditional evaluated to true or false.
fn
specialize_conditional
(
fn
specialize_conditional
(
&
self
,
&
self
,
valu
e
:
&
State
,
stat
e
:
&
State
,
condition
:
&
Expression
,
condition
:
&
Expression
,
block_before_condition
:
&
Term
<
Blk
>
,
_
block_before_condition
:
&
Term
<
Blk
>
,
is_true
:
bool
,
is_true
:
bool
,
)
->
Option
<
State
>
{
)
->
Option
<
State
>
{
let
mut
specialized_state
=
valu
e
.clone
();
let
mut
specialized_state
=
stat
e
.clone
();
if
specialized_state
if
specialized_state
.specialize_by_expression_result
(
condition
,
Bitvector
::
from_u8
(
is_true
as
u8
)
.into
())
.specialize_by_expression_result
(
condition
,
Bitvector
::
from_u8
(
is_true
as
u8
)
.into
())
.is_err
()
.is_err
()
...
@@ -359,40 +358,6 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
...
@@ -359,40 +358,6 @@ impl<'a> crate::analysis::forward_interprocedural_fixpoint::Context<'a> for Cont
// State is unsatisfiable
// State is unsatisfiable
return
None
;
return
None
;
}
}
let
mut
modified_vars
:
HashSet
<
Variable
>
=
HashSet
::
new
();
for
def
in
block_before_condition
.term.defs
.iter
()
.rev
()
{
match
&
def
.term
{
Def
::
Store
{
..
}
=>
(),
Def
::
Load
{
var
,
..
}
=>
{
modified_vars
.insert
(
var
.clone
());
}
Def
::
Assign
{
var
,
value
:
input_expr
,
}
=>
{
if
!
modified_vars
.contains
(
var
)
{
// Register is not modified again between the `Def` and the end of the block.
modified_vars
.insert
(
var
.clone
());
if
input_expr
.input_vars
()
.into_iter
()
.find
(|
input_var
|
modified_vars
.contains
(
input_var
))
.is_none
()
{
// Values of input registers did not change between the `Def` and the end of the block.
let
expr_result
=
specialized_state
.get_register
(
var
);
if
specialized_state
.specialize_by_expression_result
(
input_expr
,
expr_result
.clone
())
.is_err
()
{
// State is unsatisfiable
return
None
;
}
}
}
}
}
}
Some
(
specialized_state
)
Some
(
specialized_state
)
}
}
}
}
src/cwe_checker_lib/src/intermediate_representation/expression.rs
View file @
9eafce76
This diff is collapsed.
Click to expand it.
src/cwe_checker_lib/src/intermediate_representation/expression/tests.rs
View file @
9eafce76
...
@@ -15,6 +15,7 @@ struct Setup<'a> {
...
@@ -15,6 +15,7 @@ struct Setup<'a> {
int_sub_subpiece_expr
:
Expression
,
int_sub_subpiece_expr
:
Expression
,
eax_variable
:
Expression
,
eax_variable
:
Expression
,
rax_variable
:
Expression
,
rax_variable
:
Expression
,
rcx_variable
:
Expression
,
}
}
impl
<
'a
>
Setup
<
'a
>
{
impl
<
'a
>
Setup
<
'a
>
{
...
@@ -99,6 +100,11 @@ impl<'a> Setup<'a> {
...
@@ -99,6 +100,11 @@ impl<'a> Setup<'a> {
size
:
ByteSize
::
new
(
8
),
size
:
ByteSize
::
new
(
8
),
is_temp
:
false
,
is_temp
:
false
,
}),
}),
rcx_variable
:
Expression
::
Var
(
Variable
{
name
:
String
::
from
(
"RCX"
),
size
:
ByteSize
::
new
(
8
),
is_temp
:
false
,
}),
}
}
}
}
}
}
...
@@ -123,6 +129,122 @@ fn trivial_expression_substitution() {
...
@@ -123,6 +129,122 @@ fn trivial_expression_substitution() {
};
};
expr
.substitute_trivial_operations
();
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
setup
.rax_variable
);
assert_eq!
(
expr
,
setup
.rax_variable
);
let
sub_expr
=
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
op
:
BinOpType
::
IntSub
,
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
};
let
mut
expr
=
Expression
::
BinOp
{
op
:
BinOpType
::
IntEqual
,
lhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
zero
(
ByteSize
::
new
(
1
)
.into
()))),
rhs
:
Box
::
new
(
sub_expr
.clone
()),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
op
:
BinOpType
::
IntEqual
,
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
}
);
let
mut
expr
=
Expression
::
BinOp
{
op
:
BinOpType
::
IntNotEqual
,
lhs
:
Box
::
new
(
sub_expr
.clone
()),
rhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
zero
(
ByteSize
::
new
(
1
)
.into
()))),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
op
:
BinOpType
::
IntNotEqual
,
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
}
);
let
mut
expr
=
Expression
::
BinOp
{
lhs
:
Box
::
new
(
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
op
:
BinOpType
::
IntLess
,
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
}),
op
:
BinOpType
::
BoolOr
,
rhs
:
Box
::
new
(
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
op
:
BinOpType
::
IntEqual
,
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
}),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
op
:
BinOpType
::
IntLessEqual
,
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
}
);
let
mut
expr
=
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
0
),
size
:
ByteSize
::
new
(
4
),
arg
:
Box
::
new
(
Expression
::
Cast
{
op
:
CastOpType
::
IntSExt
,
size
:
ByteSize
::
new
(
8
),
arg
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"EAX"
,
4
))),
}),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
Var
(
Variable
::
mock
(
"EAX"
,
4
)));
let
mut
expr
=
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
4
),
size
:
ByteSize
::
new
(
4
),
arg
:
Box
::
new
(
Expression
::
BinOp
{
op
:
BinOpType
::
Piece
,
lhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"EAX"
,
4
))),
rhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"EBX"
,
4
))),
}),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
Var
(
Variable
::
mock
(
"EAX"
,
4
)));
let
mut
expr
=
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
0
),
size
:
ByteSize
::
new
(
4
),
arg
:
Box
::
new
(
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
2
),
size
:
ByteSize
::
new
(
6
),
arg
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"RAX"
,
8
))),
}),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
2
),
size
:
ByteSize
::
new
(
4
),
arg
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"RAX"
,
8
))),
}
);
let
mut
expr
=
Expression
::
UnOp
{
op
:
UnOpType
::
BoolNegate
,
arg
:
Box
::
new
(
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
op
:
BinOpType
::
IntLess
,
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
}),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
op
:
BinOpType
::
IntLessEqual
,
rhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
}
);
}
}
#[test]
#[test]
...
...
src/cwe_checker_lib/src/intermediate_representation/term.rs
View file @
9eafce76
This diff is collapsed.
Click to expand it.
test/artificial_samples/cwe_78.c
View file @
9eafce76
#include <string.h>
#include <string.h>
#include <stdlib.h>
#include <stdlib.h>
int
constant_system
()
{
void
constant_system
()
{
system
(
"ls"
);
system
(
"ls"
);
}
}
int
main
(
int
argc
,
char
**
argv
)
{
int
main
(
int
argc
,
char
**
argv
)
{
char
*
dest
=
"usr/bin/cat "
;
char
dest
[
30
]
=
"usr/bin/cat "
;
strcat
(
dest
,
argv
[
1
]);
strcat
(
dest
,
argv
[
1
]);
system
(
dest
);
system
(
dest
);
constant_system
();
constant_system
();
...
...
test/src/lib.rs
View file @
9eafce76
...
@@ -185,6 +185,8 @@ mod tests {
...
@@ -185,6 +185,8 @@ mod tests {
mark_architecture_skipped
(
&
mut
tests
,
"ppc64le"
);
// Ghidra generates mangled function names here for some reason.
mark_architecture_skipped
(
&
mut
tests
,
"ppc64le"
);
// Ghidra generates mangled function names here for some reason.
mark_skipped
(
&
mut
tests
,
"x86"
,
"clang"
);
// Return value detection insufficient for x86
mark_skipped
(
&
mut
tests
,
"x86"
,
"clang"
);
// Return value detection insufficient for x86
mark_skipped
(
&
mut
tests
,
"arm"
,
"clang"
);
// Loss of stack pointer position
mark_skipped
(
&
mut
tests
,
"aarch64"
,
"clang"
);
// Loss of stack pointer position
mark_compiler_skipped
(
&
mut
tests
,
"mingw32-gcc"
);
// Pointer Inference returns insufficient results for PE
mark_compiler_skipped
(
&
mut
tests
,
"mingw32-gcc"
);
// Pointer Inference returns insufficient results for PE
...
...
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