Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Unsound symbolication - A general approach to handle symbolic imprecisions #1526

Merged
merged 45 commits into from
Oct 31, 2019
Merged
Show file tree
Hide file tree
Changes from 15 commits
Commits
Show all changes
45 commits
Select commit Hold shift + click to select a range
4046047
Unsound symbolication and asorted fixes
feliam Sep 16, 2019
b667b98
Add test for ULE
feliam Sep 16, 2019
9665aa1
More operators tests
feliam Sep 16, 2019
d021257
remove TT
feliam Sep 16, 2019
87df083
remove TT
feliam Sep 16, 2019
ee2dea1
remove TT
feliam Sep 16, 2019
fd55973
Add test for simple sha3 concretization
feliam Sep 16, 2019
c8653b4
Add test for simple sha3 concretization
feliam Sep 16, 2019
482ed11
Add coverage to integration tests
feliam Sep 17, 2019
e2ecac1
Add coverage to integration tests
feliam Sep 17, 2019
c8f3f25
Added timeout to sha3 matching
feliam Sep 23, 2019
7422bc0
2 files reformatted
feliam Sep 23, 2019
401e06c
Review fixes
feliam Sep 24, 2019
31aa8eb
black
feliam Sep 24, 2019
a958d71
Fix KeepOnlyIfStorageChanges test
feliam Sep 24, 2019
d0099cd
remove dead code
feliam Sep 24, 2019
0b0c193
cleanups
feliam Sep 26, 2019
f7d94f3
remove unused code
feliam Sep 27, 2019
4098ee5
Blacken
Oct 1, 2019
270102c
Better concretize and calldataload
feliam Oct 1, 2019
406692d
Merge branch 'dev-unsound-symb' of github.com:trailofbits/manticore i…
feliam Oct 1, 2019
0471086
black
feliam Oct 1, 2019
1de2fbd
blkn
feliam Oct 1, 2019
31f79c4
mulmod fix
feliam Oct 2, 2019
b11bd92
Blacken
Oct 2, 2019
fa47381
Merge branch 'dev-unsound-symb' of github.com:trailofbits/manticore i…
feliam Oct 3, 2019
5ec8afc
fix calldata rel tests
feliam Oct 3, 2019
632221c
blk
feliam Oct 3, 2019
7b32c59
Merge branch 'master' into dev-unsound-symb
feliam Oct 3, 2019
f482842
Better doc- review
feliam Oct 10, 2019
870fa05
Better doc. Cleanups. sha3timeout changed
feliam Oct 11, 2019
b66dff1
Merge branch 'dev-unsound-symb' of github.com:trailofbits/manticore i…
feliam Oct 11, 2019
c3ff249
Merge branch 'master' into dev-unsound-symb
feliam Oct 12, 2019
d3a5e8a
sha3 - 42mins
feliam Oct 15, 2019
ac14ec3
Merge branch 'dev-unsound-symb' of github.com:trailofbits/manticore i…
feliam Oct 15, 2019
7893d93
blkn
feliam Oct 15, 2019
2d2a3ee
Fix spelling issues, duplicate code, and add type hints
Oct 23, 2019
4370551
Merge branch 'master' into dev-unsound-symb
Oct 23, 2019
df15457
Rm commented code
Oct 23, 2019
07edfd5
review
feliam Oct 30, 2019
47105d5
blkn
feliam Oct 30, 2019
f3db81d
Remove hardcoded conf
feliam Oct 30, 2019
b88ed27
Fix expression bool test
feliam Oct 30, 2019
4c79130
Fix sha3concrete test
feliam Oct 30, 2019
d52ccbd
Merge branch 'master' into dev-unsound-symb
feliam Oct 30, 2019
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion examples/evm/minimal.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
from manticore.ethereum import ManticoreEVM
from manticore import ManticoreEVM

################ Script #######################

Expand Down
2 changes: 2 additions & 0 deletions examples/script/concolic.py
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,8 @@ def flip(constraint):
assert len(equal.operands) == 2
# assume they are the equal -> ite form that we produce on standard branches
ite, forcepc = equal.operands
if not (isinstance(ite, BitVecITE) and isinstance(forcepc, BitVecConstant)):
ehennenfent marked this conversation as resolved.
Show resolved Hide resolved
return constraint
assert isinstance(ite, BitVecITE) and isinstance(forcepc, BitVecConstant)
assert len(ite.operands) == 3
cond, iifpc, eelsepc = ite.operands
Expand Down
43 changes: 36 additions & 7 deletions manticore/core/manticore.py
Original file line number Diff line number Diff line change
Expand Up @@ -549,6 +549,31 @@ def _kill_state(self, state_id, delete=False):
# wake up everyone waiting for a change in the state lists
self._lock.notify_all()

@sync
def kill_state(self, state, delete=False):
""" Kill a state.
A state is moved from any list to the kill list or fully
removed from secondary storage

:param state_id: a estate id
:type state_id: int
:param delete: if true remove the state from the secondary storage
:type delete: bool
"""
state_id = state.id
if state_id in self._busy_states:
self._busy_states.remove(state_id)
if state_id in self._terminated_states:
self._terminated_states.remove(state_id)
if state_id in self._ready_states:
self._ready_states.remove(state_id)

if delete:
self._remove(state_id)
else:
# add the state_id to the terminated list
self._killed_states.append(state_id)

@property
@sync
def ready_states(self):
Expand All @@ -561,7 +586,8 @@ def ready_states(self):

This means it is not possible to change the state used by Manticore with `states = list(m.ready_states)`.
"""
for state_id in self._ready_states:
_ready_states = self._ready_states
for state_id in _ready_states:
state = self._load(state_id)
yield state
# Re-save the state in case the user changed its data
Expand Down Expand Up @@ -610,9 +636,9 @@ def _all_states(self):
""" Only allowed at not running.
(At running we can have states at busy)
"""
return (
tuple(self._ready_states) + tuple(self._terminated_states) + tuple(self._killed_states)
)
return tuple(self._ready_states) + tuple(
self._terminated_states
) # + tuple(self._killed_states)

@property
@sync
Expand All @@ -634,6 +660,11 @@ def count_states(self):
""" Total states count """
return len(self._all_states)

@sync
def count_all_states(self):
ehennenfent marked this conversation as resolved.
Show resolved Hide resolved
""" Total states count """
return len(self._all_states)

@sync
def count_ready_states(self):
""" Ready states count """
Expand Down Expand Up @@ -866,11 +897,9 @@ def kill_timeout(self, timeout=None):
timer.cancel()

@at_not_running
def run(self, timeout=None):
def run(self):
"""
Runs analysis.

:param timeout: Analysis timeout, in seconds
"""
# Delete state cache
# The cached version of a state may get out of sync if a worker in a
Expand Down
27 changes: 13 additions & 14 deletions manticore/core/smtlib/constraints.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
BitVec,
BoolConstant,
ArrayProxy,
BoolEq,
BoolEqual,
Variable,
Constant,
)
Expand Down Expand Up @@ -141,15 +141,16 @@ def __get_related(self, related_to=None):
return related_variables, related_constraints

def to_string(self, related_to=None, replace_constants=True):
ehennenfent marked this conversation as resolved.
Show resolved Hide resolved
replace_constants = False
related_variables, related_constraints = self.__get_related(related_to)

if replace_constants:
constant_bindings = {}
for expression in self.constraints:
for expression in related_constraints:
if (
isinstance(expression, BoolEq)
isinstance(expression, BoolEqual)
and isinstance(expression.operands[0], Variable)
and isinstance(expression.operands[1], Constant)
and isinstance(expression.operands[1], (Variable, Constant))
):
constant_bindings[expression.operands[0]] = expression.operands[1]

Expand All @@ -163,21 +164,19 @@ def to_string(self, related_to=None, replace_constants=True):
continue
tmp.add(var.declaration)
result += var.declaration + "\n"

translator = TranslatorSmtlib(use_bindings=True)
for constraint in related_constraints:
if replace_constants:
if (
isinstance(constraint, BoolEq)
and isinstance(constraint.operands[0], Variable)
and isinstance(constraint.operands[1], Constant)
):
var = constraint.operands[0]
expression = constraint.operands[1]
expression = simplify(replace(expression, constant_bindings))
constraint = var == expression
constraint = simplify(replace(constraint, constant_bindings))
# if no variables then it is a constant
if isinstance(constraint, Constant) and constraint.value == True:
continue

translator.visit(constraint)
if replace_constants:
for k, v in constant_bindings.items():
translator.visit(k == v)

for name, exp, smtlib in translator.bindings:
if isinstance(exp, BitVec):
result += f"(declare-fun {name} () (_ BitVec {exp.size}))"
Expand Down
43 changes: 24 additions & 19 deletions manticore/core/smtlib/expression.py
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,7 @@ def __invert__(self):
return BoolNot(self)

def __eq__(self, other):
return BoolEq(self, self.cast(other))
return BoolEqual(self, self.cast(other))

def __hash__(self):
return object.__hash__(self)
Expand Down Expand Up @@ -236,7 +236,7 @@ def __init__(self, value, **kwargs):
super().__init__(value, **kwargs)


class BoolEq(BoolOperation):
class BoolEqual(BoolOperation):
def __init__(self, a, b, **kwargs):
super().__init__(a, b, **kwargs)

Expand Down Expand Up @@ -403,13 +403,13 @@ def __le__(self, other):
return LessOrEqual(self, self.cast(other))

def __eq__(self, other):
return Equal(self, self.cast(other))
return BoolEqual(self, self.cast(other))

def __hash__(self):
return object.__hash__(self)

def __ne__(self, other):
return BoolNot(Equal(self, self.cast(other)))
return BoolNot(BoolEqual(self, self.cast(other)))

def __gt__(self, other):
return GreaterThan(self, self.cast(other))
Expand Down Expand Up @@ -591,9 +591,10 @@ def __init__(self, a, b, *args, **kwargs):
super().__init__(a, b, *args, **kwargs)


class Equal(BoolOperation):
class BoolEqual(BoolOperation):
ehennenfent marked this conversation as resolved.
Show resolved Hide resolved
def __init__(self, a, b, *args, **kwargs):
assert a.size == b.size
if isinstance(a, BitVec) or isinstance(b, BitVec):
assert a.size == b.size
super().__init__(a, b, *args, **kwargs)


Expand Down Expand Up @@ -1001,16 +1002,7 @@ def taint(self):
return self._array.taint

def select(self, index):
index = self.cast_index(index)
if self.index_max is not None:
from .visitors import simplify

index = simplify(
BitVecITE(self.index_bits, index < 0, self.index_max + index + 1, index)
)
if isinstance(index, Constant) and index.value in self._concrete_cache:
return self._concrete_cache[index.value]
return self._array.select(index)
return self.get(index)

def store(self, index, value):
if not isinstance(index, Expression):
Expand Down Expand Up @@ -1040,6 +1032,9 @@ def __getitem__(self, index):
for k, v in self._concrete_cache.items():
if k >= start and k < start + size:
array_proxy_slice._concrete_cache[k - start] = v

for i in self.written:
ehennenfent marked this conversation as resolved.
Show resolved Hide resolved
array_proxy_slice.written.add(i - start)
return array_proxy_slice
else:
if self.index_max is not None:
Expand Down Expand Up @@ -1084,9 +1079,9 @@ def written(self):
# take out Proxy sleve
array = self._array
offset = 0
if isinstance(array, ArraySlice):
while isinstance(array, ArraySlice):
# if it is a proxy over a slice take out the slice too
offset = array._slice_offset
offset += array._slice_offset
ehennenfent marked this conversation as resolved.
Show resolved Hide resolved
array = array._array
while not isinstance(array, ArrayVariable):
# The index written to underlaying Array are displaced when sliced
Expand All @@ -1113,7 +1108,17 @@ def get(self, index, default=None):
if default is None:
default = self._default
index = self.cast_index(index)
value = self.select(index)

if self.index_max is not None:
from .visitors import simplify

index = simplify(
BitVecITE(self.index_bits, index < 0, self.index_max + index + 1, index)
)
if isinstance(index, Constant) and index.value in self._concrete_cache:
return self._concrete_cache[index.value]

value = self._array.select(index)
if default is None:
return value

Expand Down
16 changes: 3 additions & 13 deletions manticore/core/smtlib/operators.py
Original file line number Diff line number Diff line change
Expand Up @@ -71,13 +71,6 @@ def OR(a, b, *others):
return result


def XOR(a, b):
result = a ^ b
if isinstance(result, (BitVec, int)):
result = ITE(result != 0, True, False)
return result


def UGT(a, b):
if isinstance(a, BitVec):
return a.ugt(b)
Expand Down Expand Up @@ -208,6 +201,9 @@ def ITEBV(size, cond, true_value, false_value):
assert isinstance(false_value, (BitVec, int))
assert isinstance(size, int)

if isinstance(cond, BoolConstant) and not cond.taint:
cond = cond.value

if isinstance(cond, bool):
if cond:
return true_value
Expand Down Expand Up @@ -263,12 +259,6 @@ def UREM(a, b):
return a % b


def simplify(value):
feliam marked this conversation as resolved.
Show resolved Hide resolved
if issymbolic(value):
return value.simplify()
return value


def SAR(size, a, b):
assert isinstance(size, int)
if isinstance(b, BitVec) and b.size != size:
Expand Down
Loading