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

Fix symbolic syscall arg concretization #1697

Merged
merged 22 commits into from
May 18, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
22 commits
Select commit Hold shift + click to select a range
7d3134c
Rewind cpu when ConcretizeArgument is raised in system call
ekilmer May 6, 2020
ba732d0
Remove unused ConcretizeSyscallArgument
ekilmer May 6, 2020
a6638e6
Add test for symbolic system call argument
ekilmer May 6, 2020
077b6a0
Roll back PC during handling of ConcretizeArgument
ekilmer May 7, 2020
d5a16ac
Statically link test executable
ekilmer May 9, 2020
22a519f
Use simple checkpoint and rollback for PC
ekilmer May 9, 2020
4f2ab10
Rework checkpoint and rollback in exception-handling
ekilmer May 9, 2020
242c76d
Create rollback function in State
ekilmer May 9, 2020
cbbcb34
Define only one local variable for exception data
ekilmer May 9, 2020
aeaac35
Remove unused import
ekilmer May 9, 2020
f9706ac
Less verbosity in test
ekilmer May 9, 2020
f933e58
Rollback in parent state instead of children states
ekilmer May 11, 2020
6e3a7be
Always rollback state on Concretize*
ekilmer May 11, 2020
ba684db
Merge branch 'master' into ek/fix-concretize-syscall-args
ekilmer May 11, 2020
0baebc2
Merge branch 'master' into ek/fix-concretize-syscall-args
ekilmer May 13, 2020
05c75d4
Use typing.NamedTuple
ekilmer May 14, 2020
ef24014
Use local checkpoint variable
ekilmer May 14, 2020
dd998e6
Add type hint to test
ekilmer May 14, 2020
d18492a
Use more specific language in test comment
ekilmer May 14, 2020
bc1edd5
Remove outdated function name in comment
ekilmer May 14, 2020
ae557fc
Fix missed refactor
ekilmer May 14, 2020
c1ede66
Remove unneeded testing changes after refactor
ekilmer May 18, 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
4 changes: 3 additions & 1 deletion manticore/native/cpu/abstractcpu.py
Original file line number Diff line number Diff line change
Expand Up @@ -89,7 +89,9 @@ class ConcretizeRegister(CpuException):
Raised when a symbolic register needs to be concretized.
"""

def __init__(self, cpu, reg_name, message=None, policy="MINMAX"):
def __init__(
self, cpu: "Cpu", reg_name: str, message: Optional[str] = None, policy: str = "MINMAX",
):
self.message = message if message else f"Concretizing {reg_name}"

self.cpu = cpu
Expand Down
12 changes: 10 additions & 2 deletions manticore/native/memory.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
BitVecConstant,
expression,
issymbolic,
Expression,
)
from ..native.mappings import mmap, munmap
from ..utils.helpers import interval_intersection
Expand All @@ -19,7 +20,7 @@
import functools
import logging

from typing import Dict, Generator, Iterable, List, MutableMapping, Optional, Set
from typing import Dict, Generator, Iterable, List, MutableMapping, Optional, Set, Union

logger = logging.getLogger(__name__)

Expand Down Expand Up @@ -58,7 +59,14 @@ class ConcretizeMemory(MemoryException):
Raised when a symbolic memory cell needs to be concretized.
"""

def __init__(self, mem, address, size, message=None, policy="MINMAX"):
def __init__(
self,
mem: "Memory",
address: Union[int, Expression],
size: int,
message: Optional[str] = None,
policy: str = "MINMAX",
):
if message is None:
self.message = f"Concretizing memory address {address} size {size}"
else:
Expand Down
40 changes: 32 additions & 8 deletions manticore/native/state.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,15 @@
from collections import namedtuple
from typing import Any, NamedTuple

from ..core.state import StateBase, Concretize, TerminateState
from ..native.memory import ConcretizeMemory, MemoryException


class CheckpointData(NamedTuple):
pc: Any
last_pc: Any


class State(StateBase):
@property
def cpu(self):
Expand All @@ -17,6 +25,14 @@ def mem(self):
"""
return self._platform.current.memory

def _rollback(self, checkpoint_data: CheckpointData) -> None:
"""
Rollback state to previous values in checkpoint_data
"""
# Keep in this form to make sure we don't miss restoring any newly added
# data. Make sure the order is correct
self.cpu.PC, self.cpu._last_pc = checkpoint_data

def execute(self):
"""
Perform a single step on the current state
Expand All @@ -25,28 +41,36 @@ def execute(self):
ConcretizeRegister,
) # must be here, otherwise we get circular imports

checkpoint_data = CheckpointData(pc=self.cpu.PC, last_pc=self.cpu._last_pc)
try:
result = self._platform.execute()

# Instead of State importing SymbolicRegisterException and SymbolicMemoryException
# from cpu/memory shouldn't we import Concretize from linux, cpu, memory ??
# We are forcing State to have abstractcpu
except ConcretizeRegister as e:
except ConcretizeRegister as exc:
# Need to define local variable to use in closure
e = exc
expression = self.cpu.read_register(e.reg_name)

ekilmer marked this conversation as resolved.
Show resolved Hide resolved
def setstate(state, value):
state.cpu.write_register(setstate.e.reg_name, value)
def setstate(state: State, value):
state.cpu.write_register(e.reg_name, value)

setstate.e = e
self._rollback(checkpoint_data)
raise Concretize(str(e), expression=expression, setstate=setstate, policy=e.policy)
except ConcretizeMemory as e:
except ConcretizeMemory as exc:
# Need to define local variable to use in closure
e = exc
expression = self.cpu.read_int(e.address, e.size)

def setstate(state, value):
state.cpu.write_int(setstate.e.address, value, setstate.e.size)
def setstate(state: State, value):
state.cpu.write_int(e.address, value, e.size)
ekilmer marked this conversation as resolved.
Show resolved Hide resolved

setstate.e = e
self._rollback(checkpoint_data)
raise Concretize(str(e), expression=expression, setstate=setstate, policy=e.policy)
except Concretize as e:
self._rollback(checkpoint_data)
raise e
except MemoryException as e:
raise TerminateState(str(e), testcase=True)

Expand Down
8 changes: 0 additions & 8 deletions manticore/platforms/platform.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,14 +43,6 @@ def __init__(self, idx, name):
super().__init__(msg)


class ConcretizeSyscallArgument(OSException):
ekilmer marked this conversation as resolved.
Show resolved Hide resolved
def __init__(self, reg_num, message="Concretizing syscall argument", policy="SAMPLED"):
self.reg_num = reg_num
self.message = message
self.policy = policy
super().__init__(message)


class Platform(Eventful):
"""
Base class for all platforms e.g. operating systems or virtual machines.
Expand Down
Binary file added tests/native/binaries/symbolic_read_count
Binary file not shown.
26 changes: 26 additions & 0 deletions tests/native/binaries/symbolic_read_count.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// Compiled on Ubuntu 18.04 Manticore Docker image with
// gcc -static symbolic_read_count.c -o symbolic_read_count

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char **argv) {
// Need at least one argument
if (argc != 2) {
return -1;
}

// Just get the char ordinal value
unsigned int count = argv[1][0];
if (count > 9) {
return 0;
}

// Yes... this is very unsafe
char *buf[10];
int sz = read(0, buf, count);
if (sz > 0) {
printf("WIN: Read more than zero data\n");
}
return sz;
}
24 changes: 24 additions & 0 deletions tests/native/test_syscalls.py
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,36 @@
import os
import errno
import re
from glob import glob

from manticore.native import Manticore

from manticore.platforms import linux, linux_syscall_stubs
from manticore.platforms.linux import SymbolicSocket
from manticore.platforms.platform import SyscallNotImplemented, logger as platform_logger


def test_symbolic_syscall_arg() -> None:
BIN_PATH = os.path.join(os.path.dirname(__file__), "binaries", "symbolic_read_count")
tmp_dir = tempfile.TemporaryDirectory(prefix="mcore_test_")
m = Manticore(BIN_PATH, argv=["+"], workspace_url=str(tmp_dir.name))

m.run()
m.finalize()

found_win_msg = False
win_msg = "WIN: Read more than zero data"
outs_glob = f"{str(m.workspace)}/test_*.stdout"
# Search all output messages
for output_p in glob(outs_glob):
with open(output_p) as f:
if win_msg in f.read():
found_win_msg = True
break

assert found_win_msg, f'Did not find win message in {outs_glob}: "{win_msg}"'


class LinuxTest(unittest.TestCase):
_multiprocess_can_split_ = True
BIN_PATH = os.path.join(os.path.dirname(__file__), "binaries", "basic_linux_amd64")
Expand Down