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
405c415b
Unverified
Commit
405c415b
authored
3 years ago
by
Enkelmann
Committed by
GitHub
3 years ago
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
Improve widening hint generation (#338)
parent
060884e9
Hide whitespace changes
Inline
Side-by-side
Showing
7 changed files
with
205 additions
and
14 deletions
+205
-14
conditional_specialization.rs
...ib/src/abstract_domain/data/conditional_specialization.rs
+8
-0
interval.rs
src/cwe_checker_lib/src/abstract_domain/interval.rs
+7
-0
mod.rs
src/cwe_checker_lib/src/abstract_domain/mod.rs
+5
-0
tests.rs
...checker_lib/src/analysis/pointer_inference/state/tests.rs
+46
-0
value_specialization.rs
.../analysis/pointer_inference/state/value_specialization.rs
+43
-13
tests.rs
...r_lib/src/intermediate_representation/expression/tests.rs
+24
-1
trivial_operation_substitution.rs
...presentation/expression/trivial_operation_substitution.rs
+72
-0
No files found.
src/cwe_checker_lib/src/abstract_domain/data/conditional_specialization.rs
View file @
405c415b
...
@@ -105,6 +105,14 @@ impl<T: SpecializeByConditional + RegisterDomain> SpecializeByConditional for Da
...
@@ -105,6 +105,14 @@ impl<T: SpecializeByConditional + RegisterDomain> SpecializeByConditional for Da
Ok
(
result
)
Ok
(
result
)
}
}
}
}
fn
without_widening_hints
(
mut
self
)
->
Self
{
for
offset
in
self
.relative_values
.values_mut
()
{
*
offset
=
offset
.clone
()
.without_widening_hints
();
}
self
.absolute_value
=
self
.absolute_value
.map
(|
val
|
val
.without_widening_hints
());
self
}
}
}
#[cfg(test)]
#[cfg(test)]
...
...
This diff is collapsed.
Click to expand it.
src/cwe_checker_lib/src/abstract_domain/interval.rs
View file @
405c415b
...
@@ -503,6 +503,13 @@ impl SpecializeByConditional for IntervalDomain {
...
@@ -503,6 +503,13 @@ impl SpecializeByConditional for IntervalDomain {
Ok
(
intersected_domain
)
Ok
(
intersected_domain
)
}
}
fn
without_widening_hints
(
mut
self
)
->
Self
{
self
.widening_lower_bound
=
None
;
self
.widening_upper_bound
=
None
;
self
.widening_delay
=
0
;
self
}
}
}
impl
AbstractDomain
for
IntervalDomain
{
impl
AbstractDomain
for
IntervalDomain
{
...
...
This diff is collapsed.
Click to expand it.
src/cwe_checker_lib/src/abstract_domain/mod.rs
View file @
405c415b
...
@@ -166,4 +166,9 @@ pub trait SpecializeByConditional: Sized {
...
@@ -166,4 +166,9 @@ pub trait SpecializeByConditional: Sized {
/// Return the intersection of two values or an error if the intersection is empty.
/// Return the intersection of two values or an error if the intersection is empty.
fn
intersect
(
self
,
other
:
&
Self
)
->
Result
<
Self
,
Error
>
;
fn
intersect
(
self
,
other
:
&
Self
)
->
Result
<
Self
,
Error
>
;
/// Remove all widening hints from `self`.
/// Necessary for cases where several sources have widening hints,
/// but only one source should contribute widening hints to the result.
fn
without_widening_hints
(
self
)
->
Self
;
}
}
This diff is collapsed.
Click to expand it.
src/cwe_checker_lib/src/analysis/pointer_inference/state/tests.rs
View file @
405c415b
...
@@ -864,6 +864,52 @@ fn specialize_pointer_comparison() {
...
@@ -864,6 +864,52 @@ fn specialize_pointer_comparison() {
assert_eq!
(
state
.get_register
(
&
register
(
"RAX"
)),
specialized_pointer
);
assert_eq!
(
state
.get_register
(
&
register
(
"RAX"
)),
specialized_pointer
);
}
}
/// Test that value specialization does not introduce unintended widening hints.
/// This is a regression test for cases where pointer comparisons introduced two-sided bounds
/// (resulting in two-sided widenings) instead of one-sided bounds.
#[test]
fn
test_widening_hints_after_pointer_specialization
()
{
let
mut
state
=
State
::
new
(
&
register
(
"RSP"
),
Tid
::
new
(
"func_tid"
));
state
.set_register
(
&
register
(
"RAX"
),
Data
::
from_target
(
new_id
(
"func_tid"
,
"RSP"
),
Bitvector
::
from_i64
(
10
)
.into
()),
);
state
.set_register
(
&
register
(
"RBX"
),
Data
::
from_target
(
new_id
(
"func_tid"
,
"RSP"
),
Bitvector
::
from_i64
(
10
)
.into
()),
);
let
expression
=
Expression
::
BinOp
{
op
:
BinOpType
::
IntSub
,
lhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"RAX"
,
8
))),
rhs
:
Box
::
new
(
Expression
::
Var
(
Variable
::
mock
(
"RBX"
,
8
))),
};
let
neq_expression
=
Expression
::
BinOp
{
op
:
BinOpType
::
IntNotEqual
,
lhs
:
Box
::
new
(
Expression
::
Const
(
Bitvector
::
from_i64
(
5
))),
rhs
:
Box
::
new
(
expression
),
};
state
.specialize_by_expression_result
(
&
neq_expression
,
Bitvector
::
from_i8
(
1
)
.into
())
.unwrap
();
state
.specialize_by_expression_result
(
&
neq_expression
,
Bitvector
::
from_i8
(
1
)
.into
())
.unwrap
();
let
offset_with_upper_bound
:
IntervalDomain
=
Bitvector
::
from_i64
(
10
)
.into
();
let
offset_with_upper_bound
=
offset_with_upper_bound
.add_signed_less_equal_bound
(
&
Bitvector
::
from_i64
(
14
))
.unwrap
();
let
expected_val
=
Data
::
from_target
(
new_id
(
"func_tid"
,
"RSP"
),
offset_with_upper_bound
);
assert_eq!
(
state
.get_register
(
&
Variable
::
mock
(
"RAX"
,
8
)),
expected_val
);
let
offset_with_lower_bound
:
IntervalDomain
=
Bitvector
::
from_i64
(
10
)
.into
();
let
offset_with_lower_bound
=
offset_with_lower_bound
.add_signed_greater_equal_bound
(
&
Bitvector
::
from_i64
(
6
))
.unwrap
();
let
expected_val
=
Data
::
from_target
(
new_id
(
"func_tid"
,
"RSP"
),
offset_with_lower_bound
);
assert_eq!
(
state
.get_register
(
&
Variable
::
mock
(
"RBX"
,
8
)),
expected_val
);
}
#[test]
#[test]
fn
test_check_def_for_null_dereferences
()
{
fn
test_check_def_for_null_dereferences
()
{
let
mut
state
=
State
::
new
(
&
register
(
"RSP"
),
Tid
::
new
(
"func_tid"
));
let
mut
state
=
State
::
new
(
&
register
(
"RSP"
),
Tid
::
new
(
"func_tid"
));
...
...
This diff is collapsed.
Click to expand it.
src/cwe_checker_lib/src/analysis/pointer_inference/state/value_specialization.rs
View file @
405c415b
...
@@ -92,19 +92,20 @@ impl State {
...
@@ -92,19 +92,20 @@ impl State {
)
->
Result
<
(),
Error
>
{
)
->
Result
<
(),
Error
>
{
match
op
{
match
op
{
BinOpType
::
IntAdd
=>
{
BinOpType
::
IntAdd
=>
{
let
intermediate_result
=
result
.clone
()
-
self
.eval
(
lhs
);
let
intermediate_result
=
result
.clone
()
-
self
.eval
(
lhs
)
.without_widening_hints
()
;
self
.specialize_by_expression_result
(
rhs
,
intermediate_result
)
?
;
self
.specialize_by_expression_result
(
rhs
,
intermediate_result
)
?
;
let
intermediate_result
=
result
-
self
.eval
(
rhs
);
let
intermediate_result
=
result
-
self
.eval
(
rhs
)
.without_widening_hints
()
;
self
.specialize_by_expression_result
(
lhs
,
intermediate_result
)
?
;
self
.specialize_by_expression_result
(
lhs
,
intermediate_result
)
?
;
return
Ok
(());
return
Ok
(());
}
}
BinOpType
::
IntSub
=>
{
BinOpType
::
IntSub
=>
{
let
intermediate_result
:
Data
=
self
.eval
(
lhs
)
-
result
.clone
();
let
intermediate_result
:
Data
=
self
.eval
(
lhs
)
.without_widening_hints
()
-
result
.clone
();
self
.specialize_by_expression_result
(
rhs
,
intermediate_result
)
?
;
self
.specialize_by_expression_result
(
rhs
,
intermediate_result
)
?
;
let
intermediate_result
=
result
+
self
.eval
(
rhs
);
let
intermediate_result
=
result
+
self
.eval
(
rhs
)
.without_widening_hints
()
;
self
.specialize_by_expression_result
(
lhs
,
intermediate_result
)
?
;
self
.specialize_by_expression_result
(
lhs
,
intermediate_result
)
?
;
return
Ok
(());
return
Ok
(());
...
@@ -185,11 +186,17 @@ impl State {
...
@@ -185,11 +186,17 @@ impl State {
(
BinOpType
::
IntEqual
,
false
)
|
(
BinOpType
::
IntNotEqual
,
true
)
=>
{
(
BinOpType
::
IntEqual
,
false
)
|
(
BinOpType
::
IntNotEqual
,
true
)
=>
{
// lhs != rhs
// lhs != rhs
if
let
Ok
(
bitvec
)
=
self
.eval
(
lhs
)
.try_to_bitvec
()
{
if
let
Ok
(
bitvec
)
=
self
.eval
(
lhs
)
.try_to_bitvec
()
{
let
new_result
=
self
.eval
(
rhs
)
.add_not_equal_bound
(
&
bitvec
)
?
;
let
new_result
=
self
.eval
(
rhs
)
.without_widening_hints
()
.add_not_equal_bound
(
&
bitvec
)
?
;
self
.specialize_by_expression_result
(
rhs
,
new_result
)
?
;
self
.specialize_by_expression_result
(
rhs
,
new_result
)
?
;
}
}
if
let
Ok
(
bitvec
)
=
self
.eval
(
rhs
)
.try_to_bitvec
()
{
if
let
Ok
(
bitvec
)
=
self
.eval
(
rhs
)
.try_to_bitvec
()
{
let
new_result
=
self
.eval
(
lhs
)
.add_not_equal_bound
(
&
bitvec
)
?
;
let
new_result
=
self
.eval
(
lhs
)
.without_widening_hints
()
.add_not_equal_bound
(
&
bitvec
)
?
;
self
.specialize_by_expression_result
(
lhs
,
new_result
)
?
;
self
.specialize_by_expression_result
(
lhs
,
new_result
)
?
;
}
}
// Also specialize cases of pointer comparisons
// Also specialize cases of pointer comparisons
...
@@ -251,7 +258,10 @@ impl State {
...
@@ -251,7 +258,10 @@ impl State {
lhs
:
&
Expression
,
lhs
:
&
Expression
,
rhs
:
&
Expression
,
rhs
:
&
Expression
,
)
->
Result
<
(),
Error
>
{
)
->
Result
<
(),
Error
>
{
let
(
lhs_pointer
,
rhs_pointer
)
=
(
self
.eval
(
lhs
),
self
.eval
(
rhs
));
let
(
lhs_pointer
,
rhs_pointer
)
=
(
self
.eval
(
lhs
)
.without_widening_hints
(),
self
.eval
(
rhs
)
.without_widening_hints
(),
);
match
(
match
(
lhs_pointer
.get_if_unique_target
(),
lhs_pointer
.get_if_unique_target
(),
rhs_pointer
.get_if_unique_target
(),
rhs_pointer
.get_if_unique_target
(),
...
@@ -308,11 +318,17 @@ impl State {
...
@@ -308,11 +318,17 @@ impl State {
return
Err
(
anyhow!
(
"Unsatisfiable bound"
));
return
Err
(
anyhow!
(
"Unsatisfiable bound"
));
}
}
lhs_bound
+=
&
Bitvector
::
one
(
lhs_bound
.width
());
lhs_bound
+=
&
Bitvector
::
one
(
lhs_bound
.width
());
let
new_result
=
self
.eval
(
rhs
)
.add_signed_greater_equal_bound
(
&
lhs_bound
)
?
;
let
new_result
=
self
.eval
(
rhs
)
.without_widening_hints
()
.add_signed_greater_equal_bound
(
&
lhs_bound
)
?
;
self
.specialize_by_expression_result
(
rhs
,
new_result
)
?
;
self
.specialize_by_expression_result
(
rhs
,
new_result
)
?
;
}
}
IntSLessEqual
=>
{
IntSLessEqual
=>
{
let
new_result
=
self
.eval
(
rhs
)
.add_signed_greater_equal_bound
(
&
lhs_bound
)
?
;
let
new_result
=
self
.eval
(
rhs
)
.without_widening_hints
()
.add_signed_greater_equal_bound
(
&
lhs_bound
)
?
;
self
.specialize_by_expression_result
(
rhs
,
new_result
)
?
;
self
.specialize_by_expression_result
(
rhs
,
new_result
)
?
;
}
}
IntLess
=>
{
IntLess
=>
{
...
@@ -322,12 +338,14 @@ impl State {
...
@@ -322,12 +338,14 @@ impl State {
lhs_bound
+=
&
Bitvector
::
one
(
lhs_bound
.width
());
lhs_bound
+=
&
Bitvector
::
one
(
lhs_bound
.width
());
let
new_result
=
self
let
new_result
=
self
.eval
(
rhs
)
.eval
(
rhs
)
.without_widening_hints
()
.add_unsigned_greater_equal_bound
(
&
lhs_bound
)
?
;
.add_unsigned_greater_equal_bound
(
&
lhs_bound
)
?
;
self
.specialize_by_expression_result
(
rhs
,
new_result
)
?
;
self
.specialize_by_expression_result
(
rhs
,
new_result
)
?
;
}
}
IntLessEqual
=>
{
IntLessEqual
=>
{
let
new_result
=
self
let
new_result
=
self
.eval
(
rhs
)
.eval
(
rhs
)
.without_widening_hints
()
.add_unsigned_greater_equal_bound
(
&
lhs_bound
)
?
;
.add_unsigned_greater_equal_bound
(
&
lhs_bound
)
?
;
self
.specialize_by_expression_result
(
rhs
,
new_result
)
?
;
self
.specialize_by_expression_result
(
rhs
,
new_result
)
?
;
}
}
...
@@ -341,11 +359,17 @@ impl State {
...
@@ -341,11 +359,17 @@ impl State {
return
Err
(
anyhow!
(
"Unsatisfiable bound"
));
return
Err
(
anyhow!
(
"Unsatisfiable bound"
));
}
}
rhs_bound
-
=
&
Bitvector
::
one
(
rhs_bound
.width
());
rhs_bound
-
=
&
Bitvector
::
one
(
rhs_bound
.width
());
let
new_result
=
self
.eval
(
lhs
)
.add_signed_less_equal_bound
(
&
rhs_bound
)
?
;
let
new_result
=
self
.eval
(
lhs
)
.without_widening_hints
()
.add_signed_less_equal_bound
(
&
rhs_bound
)
?
;
self
.specialize_by_expression_result
(
lhs
,
new_result
)
?
;
self
.specialize_by_expression_result
(
lhs
,
new_result
)
?
;
}
}
IntSLessEqual
=>
{
IntSLessEqual
=>
{
let
new_result
=
self
.eval
(
lhs
)
.add_signed_less_equal_bound
(
&
rhs_bound
)
?
;
let
new_result
=
self
.eval
(
lhs
)
.without_widening_hints
()
.add_signed_less_equal_bound
(
&
rhs_bound
)
?
;
self
.specialize_by_expression_result
(
lhs
,
new_result
)
?
;
self
.specialize_by_expression_result
(
lhs
,
new_result
)
?
;
}
}
IntLess
=>
{
IntLess
=>
{
...
@@ -353,11 +377,17 @@ impl State {
...
@@ -353,11 +377,17 @@ impl State {
return
Err
(
anyhow!
(
"Unsatisfiable bound"
));
return
Err
(
anyhow!
(
"Unsatisfiable bound"
));
}
}
rhs_bound
-
=
&
Bitvector
::
one
(
rhs_bound
.width
());
rhs_bound
-
=
&
Bitvector
::
one
(
rhs_bound
.width
());
let
new_result
=
self
.eval
(
lhs
)
.add_unsigned_less_equal_bound
(
&
rhs_bound
)
?
;
let
new_result
=
self
.eval
(
lhs
)
.without_widening_hints
()
.add_unsigned_less_equal_bound
(
&
rhs_bound
)
?
;
self
.specialize_by_expression_result
(
lhs
,
new_result
)
?
;
self
.specialize_by_expression_result
(
lhs
,
new_result
)
?
;
}
}
IntLessEqual
=>
{
IntLessEqual
=>
{
let
new_result
=
self
.eval
(
lhs
)
.add_unsigned_less_equal_bound
(
&
rhs_bound
)
?
;
let
new_result
=
self
.eval
(
lhs
)
.without_widening_hints
()
.add_unsigned_less_equal_bound
(
&
rhs_bound
)
?
;
self
.specialize_by_expression_result
(
lhs
,
new_result
)
?
;
self
.specialize_by_expression_result
(
lhs
,
new_result
)
?
;
}
}
_
=>
panic!
(),
_
=>
panic!
(),
...
...
This diff is collapsed.
Click to expand it.
src/cwe_checker_lib/src/intermediate_representation/expression/tests.rs
View file @
405c415b
...
@@ -163,7 +163,7 @@ fn trivial_expression_substitution() {
...
@@ -163,7 +163,7 @@ fn trivial_expression_substitution() {
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
}
}
);
);
// Test `x < y || x == y` substitutes to `x <= y`
let
mut
expr
=
Expression
::
BinOp
{
let
mut
expr
=
Expression
::
BinOp
{
lhs
:
Box
::
new
(
Expression
::
BinOp
{
lhs
:
Box
::
new
(
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
...
@@ -186,6 +186,29 @@ fn trivial_expression_substitution() {
...
@@ -186,6 +186,29 @@ fn trivial_expression_substitution() {
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
}
}
);
);
// Test `x <= y && x != y` transforms to `x < y`
let
mut
expr
=
Expression
::
BinOp
{
lhs
:
Box
::
new
(
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
op
:
BinOpType
::
IntSLessEqual
,
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
}),
op
:
BinOpType
::
BoolAnd
,
rhs
:
Box
::
new
(
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
op
:
BinOpType
::
IntNotEqual
,
rhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
}),
};
expr
.substitute_trivial_operations
();
assert_eq!
(
expr
,
Expression
::
BinOp
{
lhs
:
Box
::
new
(
setup
.rax_variable
.clone
()),
op
:
BinOpType
::
IntSLess
,
rhs
:
Box
::
new
(
setup
.rcx_variable
.clone
()),
}
);
let
mut
expr
=
Expression
::
Subpiece
{
let
mut
expr
=
Expression
::
Subpiece
{
low_byte
:
ByteSize
::
new
(
0
),
low_byte
:
ByteSize
::
new
(
0
),
...
...
This diff is collapsed.
Click to expand it.
src/cwe_checker_lib/src/intermediate_representation/expression/trivial_operation_substitution.rs
View file @
405c415b
...
@@ -145,6 +145,78 @@ impl Expression {
...
@@ -145,6 +145,78 @@ impl Expression {
rhs
:
less_right
.clone
(),
rhs
:
less_right
.clone
(),
};
};
}
}
(
Expression
::
BinOp
{
lhs
:
lessequal_left
,
op
:
IntLessEqual
,
rhs
:
lessequal_right
,
},
BoolAnd
,
Expression
::
BinOp
{
lhs
:
notequal_left
,
op
:
IntNotEqual
,
rhs
:
notequal_right
,
},
)
|
(
Expression
::
BinOp
{
lhs
:
notequal_left
,
op
:
IntNotEqual
,
rhs
:
notequal_right
,
},
BoolAnd
,
Expression
::
BinOp
{
lhs
:
lessequal_left
,
op
:
IntLessEqual
,
rhs
:
lessequal_right
,
},
)
if
(
lessequal_left
==
notequal_left
&&
lessequal_right
==
notequal_right
)
||
(
lessequal_left
==
notequal_right
&&
lessequal_right
==
notequal_left
)
=>
{
// `x <= y and x != y` is equivalent to `x < y `
*
self
=
Expression
::
BinOp
{
lhs
:
lessequal_left
.clone
(),
op
:
IntLess
,
rhs
:
lessequal_right
.clone
(),
};
}
(
Expression
::
BinOp
{
lhs
:
lessequal_left
,
op
:
IntSLessEqual
,
rhs
:
lessequal_right
,
},
BoolAnd
,
Expression
::
BinOp
{
lhs
:
notequal_left
,
op
:
IntNotEqual
,
rhs
:
notequal_right
,
},
)
|
(
Expression
::
BinOp
{
lhs
:
notequal_left
,
op
:
IntNotEqual
,
rhs
:
notequal_right
,
},
BoolAnd
,
Expression
::
BinOp
{
lhs
:
lessequal_left
,
op
:
IntSLessEqual
,
rhs
:
lessequal_right
,
},
)
if
(
lessequal_left
==
notequal_left
&&
lessequal_right
==
notequal_right
)
||
(
lessequal_left
==
notequal_right
&&
lessequal_right
==
notequal_left
)
=>
{
// `x <= y and x != y` is equivalent to `x < y `
*
self
=
Expression
::
BinOp
{
lhs
:
lessequal_left
.clone
(),
op
:
IntSLess
,
rhs
:
lessequal_right
.clone
(),
};
}
_
=>
(),
_
=>
(),
}
}
}
}
...
...
This diff is collapsed.
Click to expand it.
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