Catch and refactor MemoryExceptions (#370)

* initial

* Clean, only store address in message if not symbolic

If it's symbolic,it renders like

    Generating testcase No. 2 - Invalid symbolic memory access (mode:r) <<manticore.core.smtlib.expression.BitVecAnd object at 0x7fd6dcd14410>>

which is not useful output to the user.

* Format as hex

* Fix tests

* Rm comments
This commit is contained in:
Mark Mossberg
2017-06-30 17:47:55 -04:00
committed by GitHub
parent fcb375ac76
commit e4102e5000
5 changed files with 62 additions and 52 deletions
-6
View File
@@ -479,12 +479,6 @@ class Executor(object):
current_state = None
except TerminateState as e:
#logger.error("MemoryException at PC: 0x{:016x}. Cause: {}\n".format(current_state.cpu.instruction.address, e.cause))
#self.generate_testcase(current_state, "Memory Exception: " + str(e))
#self.generate_testcase(current_state, "Invalid PC Exception" + str(e))
#self.generate_testcase(current_state, "Program finished correctly")
#logger.error("Syscall not implemented: %s", str(e))
#Notify this worker is done
self.will_terminate_state(current_state, current_state_id, e)
+38 -30
View File
@@ -8,38 +8,25 @@ from ..utils.helpers import issymbolic
logger = logging.getLogger('MEMORY')
class MemoryException(Exception):
'''
Memory exceptions
'''
def __init__(self, cause, address):
def __init__(self, message, address=None):
'''
Builds a memory exception.
:param cause: exception message.
:param message: exception message.
:param address: memory address where the exception occurred.
'''
super(MemoryException, self, ).__init__('{} <{}>'.format(cause, address))
self.cause = cause
self.address = address
self.message = message
if address is not None and not issymbolic(address):
self.message += ' <{:x}>'.format(address)
def __str__(self):
return '%s <%s>'%(self.cause, '%08x'%self.address)
class InvalidMemoryAccess(MemoryException):
def __init__(self, address, mode):
self.mode = mode
super(InvalidMemoryAccess, self, ).__init__('Invalid mode trying to access memory in mode {}'.format(mode), address)
class InvalidSymbolicMemoryAccess(InvalidMemoryAccess):
def __init__(self, cause, address, size, constraint):
super(InvalidSymbolicMemoryAccess, self, ).__init__(cause, address)
#the crashing constraint you need to assert
self.constraint = constraint
self.size = size
def __str__(self):
return '%s <%s>'%(self.cause, repr(self.address))
return self.message
class ConcretizeMemory(MemoryException):
@@ -53,6 +40,28 @@ class ConcretizeMemory(MemoryException):
self.size = size
self.policy = policy
class InvalidMemoryAccess(MemoryException):
_message = 'Invalid memory access'
def __init__(self, address, mode):
assert mode in 'rwx'
suffix = ' (mode:{})'.format(mode)
message = self._message + suffix
super(InvalidMemoryAccess, self, ).__init__(message, address)
self.mode = mode
class InvalidSymbolicMemoryAccess(InvalidMemoryAccess):
_message = 'Invalid symbolic memory access'
def __init__(self, address, mode, size, constraint):
super(InvalidSymbolicMemoryAccess, self, ).__init__(address, mode)
#the crashing constraint you need to assert
self.constraint = constraint
self.size = size
class Map(object):
'''
A memory map.
@@ -501,7 +510,7 @@ class Memory(object):
return p << self.page_bit_size
counter+=1
if counter >= self.memory_size/self.page_size:
raise MemoryException('Not enough memory', 0)
raise MemoryException('Not enough memory')
return self._search( size, self.memory_size-size, counter )
@@ -752,7 +761,7 @@ class Memory(object):
#write and read potentially symbolic bytes at symbolic indexes
def read(self, addr, size):
if not self.access_ok(slice(addr, addr+size), 'r'):
raise MemoryException('No access reading', addr)
raise InvalidMemoryAccess(addr, 'r')
assert size > 0
result = []
@@ -806,7 +815,7 @@ class Memory(object):
def write(self, addr, buf):
size = len(buf)
if not self.access_ok(slice(addr, addr + size), 'w'):
raise MemoryException('No access writing', addr)
raise InvalidMemoryAccess(addr, 'w')
assert size > 0
stop = addr + size
start = addr
@@ -913,10 +922,9 @@ class SMemory(Memory):
logger.debug('Reading %d bytes from symbolic address %s', size, address)
try:
solutions = solver.get_all_values(self.constraints, address, maxcnt=0x1000) #if more than 0x3000 exception
except TooManySolutions, e:
except TooManySolutions as e:
m, M = solver.minmax(self.constraints, address)
logger.info('Got TooManySolutions on a symbolic read. Range [%x, %x]. Not crashing!', m, M)
logger.info('Memory:%s', self)
logger.debug('Got TooManySolutions on a symbolic read. Range [%x, %x]. Not crashing!', m, M)
crashing_condition = True
for start, end, perms, offset, name in self.mappings():
@@ -925,7 +933,7 @@ class SMemory(Memory):
crashing_condition = Operators.AND(Operators.OR( (address+size).ult(start), address.uge(end) ), crashing_condition)
if solver.can_be_true(self.constraints, crashing_condition):
raise InvalidSymbolicMemoryAccess('No access reading symbolic', address, size, crashing_condition)
raise InvalidSymbolicMemoryAccess(address, 'r', size, crashing_condition)
#INCOMPLETE Result! We could also fork once for every map
@@ -945,7 +953,7 @@ class SMemory(Memory):
crashing_condition = Operators.OR(address == base, crashing_condition)
if solver.can_be_true(self.constraints, crashing_condition):
raise InvalidSymbolicMemoryAccess('No access reading symbolic', address, size, crashing_condition)
raise InvalidSymbolicMemoryAccess(address, 'r', size, crashing_condition)
condition = False
for base in solutions:
@@ -997,7 +1005,7 @@ class SMemory(Memory):
crashing_condition = Operators.OR(address == base, crashing_condition)
if solver.can_be_true(self.constraints, crashing_condition):
raise InvalidSymbolicMemoryAccess('No access writing symbolic', address, size, crashing_condition)
raise InvalidSymbolicMemoryAccess(address, 'w', size, crashing_condition)
for offset in xrange(size):
for base in solutions:
@@ -1009,7 +1017,7 @@ class SMemory(Memory):
for offset in xrange(size):
if issymbolic(value[offset]):
if not self.access_ok(address+offset, 'w'):
raise MemoryException('No access writing', address+offset)
raise InvalidMemoryAccess(address+offset, 'w')
self._symbols[address+offset] = [(True, value[offset])]
else:
# overwrite all previous items
+8 -7
View File
@@ -9,20 +9,19 @@ from ..utils.event import Signal, forward_signals
#import exceptions
from .cpu.abstractcpu import ConcretizeRegister
from .memory import ConcretizeMemory
from .memory import ConcretizeMemory, MemoryException
from ..platforms.platform import *
class StateException(Exception):
''' All state related exceptions '''
def __init__(self, *args, **kwargs):
super(StateException, self).__init__(*args)
pass
class TerminateState(StateException):
''' Terminates current state exploration '''
def __init__(self, *args, **kwargs):
super(TerminateState, self).__init__(*args, **kwargs)
self.testcase = kwargs.get('testcase', False)
def __init__(self, message, testcase=False):
super(TerminateState, self).__init__(message)
self.testcase = testcase
class Concretize(StateException):
@@ -138,6 +137,8 @@ class State(object):
expression=expression,
setstate=setstate,
policy=e.policy)
except MemoryException as e:
raise TerminateState(e.message, testcase=True)
#Remove when code gets stable?
assert self.platform.constraints is self.constraints
+5 -5
View File
@@ -581,7 +581,7 @@ class kernel32(object):
try:
key_str = readStringFromPointer(platform, cpu, lpSubKey, utf16)
except MemoryException as me:
raise MemoryException("{}: {}".format(myname, me.cause), 0xFFFFFFFF)
raise MemoryException("{}: {}".format(myname, me.message), 0xFFFFFFFF)
except SymbolicAPIArgument:
raise ConcretizeArgument(platform.current, 1)
@@ -645,7 +645,7 @@ class kernel32(object):
try:
key_str = readStringFromPointer(platform, cpu, lpSubKey, utf16)
except MemoryException as me:
raise MemoryException("{}: {}".format(myname, me.cause), 0xFFFFFFFF)
raise MemoryException("{}: {}".format(myname, me.message), 0xFFFFFFFF)
except SymbolicAPIArgument:
raise ConcretizeArgument(platform.current, 1)
@@ -744,7 +744,7 @@ class kernel32(object):
try:
filename = readStringFromPointer(platform, cpu, lpFileName, utf16)
except MemoryException as me:
msg = "CreateFile{}: {}".format(utf16 and "W" or "A", me.cause)
msg = "CreateFile{}: {}".format(utf16 and "W" or "A", me.message)
raise MemoryException(msg, 0xFFFFFFFF)
except SymbolicAPIArgument:
raise ConcretizeArgument(platform.current, 0)
@@ -850,7 +850,7 @@ class kernel32(object):
try:
appname = readStringFromPointer(platform, cpu, lpApplicationName, utf16)
except MemoryException as me:
msg = "{}: {}".format(myname, me.cause)
msg = "{}: {}".format(myname, me.message)
raise MemoryException(msg, 0xFFFFFFFF)
except SymbolicAPIArgument:
raise ConcretizeArgument(platform.current, 0)
@@ -858,7 +858,7 @@ class kernel32(object):
try:
cmdline = readStringFromPointer(platform, cpu, lpCommandLine, utf16)
except MemoryException as me:
msg = "{}: {}".format(myname, me.cause)
msg = "{}: {}".format(myname, me.message)
raise MemoryException(msg, 0xFFFFFFFF)
except SymbolicAPIArgument:
raise ConcretizeArgument(platform.current, 1)
+11 -4
View File
@@ -1280,7 +1280,9 @@ class MemoryTest(unittest.TestCase):
self.assertEqual(mem[addr], 'a')
mem.mprotect(addr, size, 'w')
self.assertRaisesRegexp(MemoryException, "No access reading <%08x>"%addr, mem.__getitem__, addr)
with self.assertRaisesRegexp(InvalidMemoryAccess, 'Invalid memory access \(mode:.\) <{:x}>'.format(addr)):
_ = mem[addr]
def testmprotectFailSymbReading(self):
@@ -1333,7 +1335,10 @@ class MemoryTest(unittest.TestCase):
#print map(hex,sorted(solver.get_all_values(cs, x, 0x100000))), map(hex,solver.minmax(cs, x)), mem[x]
#No Access Reading <4160741376>
self.assertRaisesRegexp(MemoryException, r"No access reading.*", mem.__getitem__, x)
# self.assertRaisesRegexp(MemoryException, r"No access reading.*", mem.__getitem__, x)
with self.assertRaisesRegexp(InvalidSymbolicMemoryAccess, 'Invalid symbolic memory access.*'.format(addr)):
_ = mem[x]
# mem[addr] = 'a'
def testmprotectFailWriting(self):
mem = Memory32()
@@ -1346,7 +1351,8 @@ class MemoryTest(unittest.TestCase):
addr = mem.mmap(None, size, 'wx')
mem[addr] = 'a'
mem.mprotect(addr, size, 'r')
self.assertRaisesRegexp(MemoryException, "No access writing <%08x>"%addr, mem.__setitem__, addr, 'a')
with self.assertRaisesRegexp(InvalidMemoryAccess, 'Invalid memory access \(mode:w\) <{:x}>'.format(addr)):
mem[addr] = 'a'
def testmprotecNoReadthenOkRead(self):
mem = Memory32()
@@ -1359,7 +1365,8 @@ class MemoryTest(unittest.TestCase):
addr = mem.mmap(None, size, 'wx')
mem[addr] = 'a'
self.assertRaisesRegexp(MemoryException, "No access reading <%08x>"%addr, mem.__getitem__, addr)
with self.assertRaisesRegexp(InvalidMemoryAccess, 'Invalid memory access \(mode:r\) <{:x}>'.format(addr)):
_ = mem[addr]
mem.mprotect(addr, size, 'r')
self.assertEqual(mem[addr], 'a')