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

Symbolic model for strcpy #1681

Merged
merged 62 commits into from
Jun 9, 2020
Merged
Changes from 1 commit
Commits
Show all changes
62 commits
Select commit Hold shift + click to select a range
88fc5b6
Working copy for strcpy - without symbolic input
sschriner Apr 24, 2020
3977b0a
Corrected null term error
sschriner Apr 24, 2020
590e0e8
Needs to be tested but general algorithm idea for handling symbolic i…
sschriner Apr 24, 2020
b62ae4a
Updated according to feedback
sschriner Apr 24, 2020
063f2cd
Beginning of strcpy tests
sschriner Apr 24, 2020
4ae8527
Revising strcpy algorithm - realised it was flawed
sschriner Apr 27, 2020
f94244a
This should be a more correct way of handling symbolic bytes. Needs t…
sschriner Apr 27, 2020
5db5296
Get rid of redundant code
sschriner Apr 27, 2020
425232a
Fixed another typo
sschriner Apr 27, 2020
ac2c56a
Update manticore/native/models.py
sschriner Apr 27, 2020
8ac2185
Clarified and updated comments
sschriner Apr 27, 2020
9f836fa
Fixed some errors in model while working on tests
sschriner Apr 28, 2020
509a964
Progress on tests
sschriner Apr 28, 2020
0b1729f
Found typo in models
sschriner Apr 28, 2020
c05a4e6
Removed unnecassary whitespace
sschriner Apr 28, 2020
1b5f11a
Added some helper functions for tests and to clean things up
sschriner Apr 28, 2020
f53a89b
Added comments for helper functions
sschriner Apr 28, 2020
4c034d4
WIP: current state of strcpy tests
sschriner Apr 29, 2020
bb13eaf
Updated type hints from Expression to BitVec
sschriner Apr 29, 2020
9f0cb0f
Fixed linter complaints
sschriner Apr 29, 2020
f727753
Updated strcpy return type to make linter happy
sschriner Apr 29, 2020
a64bcaf
Added some helper properties to expression BitVecITE
sschriner Apr 29, 2020
38c0ed1
Overwrote equal op in ArraySelect
sschriner Apr 29, 2020
828dbe6
Fixed formatting in expression
sschriner Apr 29, 2020
82c61eb
Almost done just needs some cleaning
sschriner Apr 30, 2020
2c51906
Attempt at overriding __eq__ again
sschriner Apr 30, 2020
62a547c
Cleaned up tests some still have unresolved __eq__ issues
sschriner Apr 30, 2020
767b360
Removed stuff from expression and updated test_models.py
sschriner May 1, 2020
c1c9f20
Removed stuff from expression and updated test_models.py
sschriner May 1, 2020
9afad4f
Basicly done probably needs some more comments for clarity
sschriner May 1, 2020
7601831
Cleaned up the tests a little
sschriner May 7, 2020
f2dd84b
Corrected linter error and added more comments to strcpy model functions
sschriner May 7, 2020
a353e84
Merge branch 'master' of github.com:trailofbits/manticore into c_str_…
sschriner May 7, 2020
f8be8eb
Remove duplicated word in comment
sschriner May 8, 2020
35cc9fc
Update manticore/native/models.py
sschriner May 14, 2020
1ce0424
Update manticore/native/models.py
sschriner May 14, 2020
edb721d
Update tests/native/test_models.py
sschriner May 14, 2020
f2f58b2
Merge branch 'master' of github.com:trailofbits/manticore into c_str_…
sschriner May 14, 2020
4296893
Updates according to feedback
sschriner May 14, 2020
5028cda
Updates according to feedback
sschriner May 14, 2020
794f943
Swapped can_be_true and must be true
sschriner May 14, 2020
dceb351
Updates for feedback
sschriner May 19, 2020
9b0aad5
Forgot to lint
sschriner May 19, 2020
dde7d0f
Fixed some typos
sschriner May 20, 2020
1a6d1ce
Largely simplified ITE being built
sschriner May 20, 2020
adec0f8
Forgot to lint
sschriner May 20, 2020
657ab4f
This is messy but seems to be concretizing to the correct states
sschriner May 26, 2020
dd9447b
Very very messy state of the code before attempting to concretize on …
sschriner May 29, 2020
e65c185
Cleaned up model with forking on every possible NULL
sschriner Jun 3, 2020
ee93ffb
Removed trailing whitespace for CodeClimate
sschriner Jun 3, 2020
1dad5c3
Added state.context for offset value back
sschriner Jun 3, 2020
72516ab
New symbolic test with regex for expected output
sschriner Jun 5, 2020
e20b21c
New symbolic test with regex for expected output
sschriner Jun 5, 2020
f9204e5
Updated for mypy
sschriner Jun 5, 2020
600b44f
Merge branch 'master' of github.com:trailofbits/manticore into c_str_…
sschriner Jun 8, 2020
38cb66d
Updated comments in tests
sschriner Jun 8, 2020
dbd627a
Updated cant_be_null to cannot_be_null
sschriner Jun 9, 2020
a6f4dab
Corrected docstring location for _test_strcpy
sschriner Jun 9, 2020
eab68d7
Add break for efficiency
sschriner Jun 9, 2020
ecb35be
Added compiler information and source file
sschriner Jun 9, 2020
3491d52
Updated regex to use raw strings
sschriner Jun 9, 2020
3cd7b46
Merge branch 'master' of github.com:trailofbits/manticore into c_str_…
sschriner Jun 9, 2020
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
Prev Previous commit
Next Next commit
New symbolic test with regex for expected output
sschriner committed Jun 5, 2020

Unverified

No user is associated with the committer email.
commit e20b21c09a50099e1f8f66aec8034cc1fc74f9b8
152 changes: 71 additions & 81 deletions tests/native/test_models.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import unittest
import os
import random
import tempfile
from glob import glob
import re

from manticore.core.smtlib import (
ConstraintSet,
@@ -12,16 +15,15 @@
)
from manticore.native.state import State
from manticore.platforms import linux

from manticore.native import Manticore
from manticore.native.models import (
variadic,
isvariadic,
strcmp,
strlen,
strcpy,
is_definitely_NULL,
can_be_NULL,
cant_be_NULL
cant_be_NULL,
)


@@ -228,15 +230,7 @@ def test_symbolic_mixed(self):


class StrcpyTest(ModelTest):
def _check_BitVecITE(self, dst, dst_val):
# Iterate and check the nested ITE tree for a symbolic byte
self.assertTrue(issymbolic(dst))
while type(dst.true_value) is BitVecITE: # check each if/else in dst
self.assertEqual(dst.false_value, dst_val) # dst = false_val
dst = dst.true_value
return dst

def _assert_start(self, s, d):
def _assert_concrete(self, s, d):
# Checks all characters are copied until the 1st that could be NULL
cpu = self.state.cpu
src = cpu.read_int(s, 8)
@@ -248,49 +242,11 @@ def _assert_start(self, s, d):
offset += 1
src = cpu.read_int(s + offset, 8)
dst = cpu.read_int(d + offset, 8)
return offset

def _assert_end(self, s, d, offset, org_dest_val):
cpu = self.state.cpu
src = cpu.read_int(s + offset, 8)
dst = cpu.read_int(d + offset, 8)

# src string was entirely symbolic
if not issymbolic(dst):
print(offset, src, dst)
self.assertTrue(is_definitely_NULL(src, self.state.constraints))
self.assertEqual(0, dst)

# Check each symbolic byte in the dst
else:
# Loop till src must be NULL or assumed dst space allowed is gone
while not is_definitely_NULL(src, self.state.constraints) and offset < len(
org_dest_val
):
# Check ITE tree in symbolic dst
dst = self._check_BitVecITE(dst, org_dest_val[offset])

# Check that true value is src
if type(dst.true_value) is ArraySelect:
self.assertEqual(type(src), ArraySelect)
self.assertEqual(src.index, dst.true_value.index)
self.assertTrue(src.array is dst.true_value.array)
else:
self.assertTrue(Operators.ITE(dst.true_value == src, True, False))

# Check the false value is dst or offset
if issymbolic(src) and can_be_NULL(src, self.state.constraints):
self.assertEqual(dst.false_value, 0)
else:
self.assertEqual(dst.false_value, org_dest_val[offset]) # dst = false_val

offset += 1
src = cpu.read_int(s + offset, 8)
dst = cpu.read_int(d + offset, 8)

# Check last sym dst byte
dst = self._check_BitVecITE(dst, org_dest_val[offset])
self.assertEqual(dst.true_value, 0)
# Assert final NULL byte
self.assertTrue(is_definitely_NULL(src, self.state.constraints))
self.assertEqual(0, dst)
return offset

"""
This method creates memory for a given src and dst string pointers,
@@ -319,9 +275,7 @@ def _test_strcpy(self, string, dst_len=None):
# addresses should match
self.assertEqual(ret, d)
# assert everything is copied up to the 1st possible 0 is copied
offset = self._assert_start(s, d)
# check all symbolic values created until a value that must be 0 is found
#self._assert_end(s, d, offset, dst_vals)
offset = self._assert_concrete(s, d)

# Delete stack space created
self._pop_string_space(dst_len + len(string))
@@ -336,27 +290,63 @@ def test_concrete_empty(self):
self._test_strcpy("\0")
self._test_strcpy("\0", dst_len=10)

"""
def test_symbolic_mixed(self):
src = self.state.symbolicate_buffer("++\0")
self._test_strcpy(src, dst_len=4)

src = self.state.symbolicate_buffer("xy++\0")
self._test_strcpy(src, dst_len=6)

src = self.state.symbolicate_buffer("iv+++")
self.state.constraints.add(src[-1] == 0)
self._test_strcpy(src, dst_len=6)

src = self.state.symbolicate_buffer("+++jl\0")
self._test_strcpy(src, dst_len=6)

src = self.state.symbolicate_buffer("+++df+++")
self.state.constraints.add(src[-1] == 0)
self._test_strcpy(src, dst_len=12)

def test_only_symbolic(self):
src = self.state.symbolicate_buffer("++++++++++++")
self.state.constraints.add(src[-1] == 0)
self._test_strcpy(src, dst_len=15)
"""
def test_symbolic(self):
BIN_PATH = os.path.join(os.path.dirname(__file__), "binaries", "sym_strcpy_test")
print("\nBinary Path:")
print(BIN_PATH)
tmp_dir = tempfile.TemporaryDirectory(prefix="mcore_test_sym_")
m = Manticore(BIN_PATH, stdin_size=10, workspace_url=str(tmp_dir.name))

addr_of_strcpy = 0x400418

@m.hook(addr_of_strcpy)
def strlen_model(state):
state.invoke_model(strcpy)

m.run()
m.finalize()

# Approximate regexes for expected testcase output
# Example Match above each regex
# Manticore varies the hex output slightly per run
expected = [
# STDIN: b'\x00AAAAAAAAA'
"STDIN: b\\'\\\x00A.{8,32}\\'",
# STDIN: b'\xffA\x00\xff\xff\xff\xff\xff\xff\xff'
"STDIN: b\\'(\\\\x((?!(00))[0-9a-f]{2}))A\\\\x00(\\\\x([0-9a-f]{2})){7}\\'",
# STDIN: b'\xffA\xff\x00\xff\xff\xff\xff\xff\xff'
"STDIN: b\\'(\\\\x((?!(00))[0-9a-f]{2}))A(\\\\x((?!(00))[0-9a-f]{2}))\\\\x00(\\\\x([0-9a-f]{2})){6}\\'",
# STDIN: b'\xffA\xff\xff\x00\xff\xff\xff\xff\xff'
"STDIN: b\\'(\\\\x((?!(00))[0-9a-f]{2}))A(\\\\x((?!(00))[0-9a-f]{2})){2}\\\\x00(\\\\x([0-9a-f]{2})){5}\\'",
# STDIN: b'\x00\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe\xbe'
"STDIN: b\\'\\\\x00(\\\\x([0-9a-f]{2})){9}\\'",
# STDIN: b'\xff\x00\xff\xff\xff\xff\xff\xff\xff\xff'
"STDIN: b\\'(\\\\x((?!(00))([0-9a-f]{2}))){1}\\\\x00(\\\\x([0-9a-f]{2})){8}\\'",
# STDIN: b'\xff\xff\x00\xff\xff\xff\xff\xff\xff\xff'
"STDIN: b\\'(\\\\x((?!(00))([0-9a-f]{2}))){2}\\\\x00(\\\\x([0-9a-f]{2})){7}\\'",
# STDIN: b'\xff\xff\xff\x00\xff\xff\xff\xff\xff\xff'
"STDIN: b\\'(\\\\x((?!(00))([0-9a-f]{2}))){3}\\\\x00(\\\\x([0-9a-f]{2})){6}\\'",
# STDIN: b'\xff\xff\xff\xff\x00\xff\xff\xff\xff\xff'
"STDIN: b\\'(\\\\x((?!(00))([0-9a-f]{2}))){4}\\\\x00(\\\\x([0-9a-f]{2})){5}\\'",
# STDIN: b'\xff\xff\xff\xff\xff\xff\xff\xff\xff\xff'
"STDIN: b\\'(\\\\x((?!(00))([0-9a-f]{2}))){10}\\'",
]

inputs = f"{str(m.workspace)}/test_*.input"

# Make a list of the generated input states
stdins = []
for inpt in glob(inputs):
with open(inpt) as f:
stdins.append(f.read())

# Check the number of input states matches the number of regexes
self.assertEqual(len(stdins), len(expected))

# Assert that every regex has a matching input
for e in expected:
match = False
for s in stdins:
if re.fullmatch(e, s) == None:
match = True
self.assertTrue(match)