Fixes to stream formatting of doubles, they weren't being streamed before. Implemented the chk versions of printf and such, so that they all route through the logging interface as well. Implemented the concretization APIs.
This commit is contained in:
+47
-22
@@ -74,6 +74,9 @@ class DeepState(object):
|
||||
def read_uint8_t(self, ea, concretize=True, constrain=False):
|
||||
raise NotImplementedError("Must be implemented by engine.")
|
||||
|
||||
def write_uint8_t(self, ea, val):
|
||||
raise NotImplementedError("Must be implemented by engine.")
|
||||
|
||||
def concretize(self, val, constrain=False):
|
||||
raise NotImplementedError("Must be implemented by engine.")
|
||||
|
||||
@@ -86,36 +89,27 @@ class DeepState(object):
|
||||
def add_constraint(self, expr):
|
||||
raise NotImplementedError("Must be implemented by engine.")
|
||||
|
||||
def read_c_string(self, ea, concretize=True):
|
||||
def read_c_string(self, ea, concretize=True, constrain=False):
|
||||
"""Read a NUL-terminated string from `ea`."""
|
||||
assert isinstance(ea, (int, long))
|
||||
chars = []
|
||||
i = 0
|
||||
while True:
|
||||
b, ea = self.read_uint8_t(ea, concretize=concretize)
|
||||
b, ea = self.read_uint8_t(ea, concretize=concretize, constrain=constrain)
|
||||
if self.is_symbolic(b):
|
||||
concrete_b = self.concretize_min(b) # Find the NUL byte sooner.
|
||||
if not concrete_b:
|
||||
break
|
||||
|
||||
if concretize:
|
||||
chars.append(chr(concrete_b))
|
||||
else:
|
||||
chars.append(b)
|
||||
|
||||
continue
|
||||
|
||||
# Concretize if it's not symbolic; we might have a concrete bitvector.
|
||||
b = self.concretize(b)
|
||||
if not b:
|
||||
break
|
||||
|
||||
b_maybe_nul = self.concretize_min(b)
|
||||
if not b_maybe_nul:
|
||||
break # Stop at the first possible NUL byte.
|
||||
else:
|
||||
chars.append(chr(b))
|
||||
# Concretize if it's not symbolic; we might have a concrete bitvector.
|
||||
b = self.concretize(b)
|
||||
if not b:
|
||||
break
|
||||
chars.append(b)
|
||||
|
||||
next_ea = ea + len(chars) + 1
|
||||
if concretize:
|
||||
return "".join(chars), next_ea
|
||||
return "".join(chr(b) for b in chars), next_ea
|
||||
else:
|
||||
return chars, next_ea
|
||||
|
||||
@@ -262,14 +256,45 @@ class DeepState(object):
|
||||
return 1
|
||||
|
||||
def api_assume(self, arg):
|
||||
"""Implements the `DeepState_Assume` API function, which injects a constraint
|
||||
into the solver."""
|
||||
"""Implements the `DeepState_Assume` API function, which injects a
|
||||
constraint into the solver."""
|
||||
constraint = arg != 0
|
||||
if not self.add_constraint(constraint):
|
||||
self.log_message(LOG_LEVEL_FATAL,
|
||||
"Failed to add assumption {}".format(constraint))
|
||||
self.abandon_test()
|
||||
|
||||
def api_concretize_data(self, begin_ea, end_ea):
|
||||
"""Implements the `Deeptate_ConcretizeData` API function, which lets the
|
||||
programmer concretize some data in the exclusive range
|
||||
`[begin_ea, end_ea)`."""
|
||||
begin_ea = self.concretize(begin_ea, constrain=True)
|
||||
end_ea = self.concretize(end_ea, constrain=True)
|
||||
if end_ea < begin_ea:
|
||||
self.log_message(
|
||||
LOG_LEVEL_FATAL,
|
||||
"Invalid range [{:x}, {:x}) to McTest_Concretize".format(
|
||||
begin_ea, end_ea))
|
||||
self.abandon_test()
|
||||
|
||||
for i in xrange(end_ea - begin_ea):
|
||||
val, _ = self.read_uint8_t(begin_ea + i, concretize=True, constrain=True)
|
||||
_ = self.write_uint8_t(begin_ea + i, val)
|
||||
|
||||
return begin_ea
|
||||
|
||||
def api_concretize_cstr(self, begin_ea):
|
||||
"""Implements the `Deeptate_ConcretizeCStr` API function, which lets the
|
||||
programmer concretize a NUL-terminated string starting at `begin_ea`."""
|
||||
begin_ea = self.concretize(begin_ea, constrain=True)
|
||||
str_bytes, end_ea = self.read_c_string(begin_ea, concretize=False)
|
||||
next_ea = begin_ea
|
||||
for i, b in enumerate(str_bytes):
|
||||
b = self.concretize_min(b, constrain=True)
|
||||
next_ea = self.write_uint8_t(begin_ea + i, b)
|
||||
self.write_uint8_t(next_ea, 0)
|
||||
return begin_ea
|
||||
|
||||
def api_pass(self):
|
||||
"""Implements the `DeepState_Pass` API function, which marks this test as
|
||||
having passed, and stops further execution."""
|
||||
|
||||
@@ -76,6 +76,10 @@ class AngrTest(DeepState):
|
||||
val = ord(val)
|
||||
return val, ea + 1
|
||||
|
||||
def write_uint8_t(self, ea, val):
|
||||
self.state.mem[ea].uint8_t = val
|
||||
return ea + 1
|
||||
|
||||
def concretize(self, val, constrain=False):
|
||||
if isinstance(val, (int, long)):
|
||||
return val
|
||||
@@ -173,6 +177,21 @@ class SoftFail(angr.SimProcedure):
|
||||
AngrTest(procedure=self).api_soft_fail()
|
||||
|
||||
|
||||
class ConcretizeData(angr.SimProcedure):
|
||||
"""Implements the `Deeptate_ConcretizeData` API function, which lets the
|
||||
programmer concretize some data in the exclusive range
|
||||
`[begin_ea, end_ea)`."""
|
||||
def run(self, begin_ea, end_ea):
|
||||
return AngrTest(procedure=self).api_concretize_data(begin_ea, end_ea)
|
||||
|
||||
|
||||
class ConcretizeCStr(angr.SimProcedure):
|
||||
"""Implements the `Deeptate_ConcretizeCStr` API function, which lets the
|
||||
programmer concretize a NUL-terminated string starting at `begin_ea`."""
|
||||
def run(self, begin_ea):
|
||||
return AngrTest(procedure=self).api_concretize_cstr(begin_ea)
|
||||
|
||||
|
||||
class StreamInt(angr.SimProcedure):
|
||||
"""Implements _DeepState_StreamInt, which gives us an integer to stream, and
|
||||
the format to use for streaming."""
|
||||
@@ -237,8 +256,9 @@ def do_run_test(project, test, apis, run_state):
|
||||
for state in test_manager.deadended:
|
||||
AngrTest(state=state).report()
|
||||
|
||||
for state in test_manager.errored:
|
||||
print "ErrorL", state.error
|
||||
for error in test_manager.errored:
|
||||
print "Error", error.error
|
||||
error.debug()
|
||||
|
||||
def run_test(project, test, apis, run_state):
|
||||
"""Symbolically executes a single test function."""
|
||||
@@ -269,7 +289,10 @@ def main():
|
||||
translation_cache=True,
|
||||
support_selfmodifying_code=False,
|
||||
auto_load_libs=True,
|
||||
exclude_sim_procedures_list=['printf', 'fprintf'])
|
||||
exclude_sim_procedures_list=['printf', '__printf_chk',
|
||||
'vprintf', '__vprintf_chk',
|
||||
'fprintf', '__fprintf_chk',
|
||||
'vfprintf', '__vfprintf_chk'])
|
||||
|
||||
entry_state = project.factory.entry_state(
|
||||
add_options={angr.options.ZERO_FILL_UNCONSTRAINED_MEMORY,
|
||||
@@ -296,6 +319,8 @@ def main():
|
||||
|
||||
# Hook various functions.
|
||||
hook_function(project, apis['IsSymbolicUInt'], IsSymbolicUInt)
|
||||
hook_function(project, apis['ConcretizeData'], ConcretizeData)
|
||||
hook_function(project, apis['ConcretizeCStr'], ConcretizeCStr)
|
||||
hook_function(project, apis['Assume'], Assume)
|
||||
hook_function(project, apis['Pass'], Pass)
|
||||
hook_function(project, apis['Fail'], Fail)
|
||||
|
||||
@@ -74,6 +74,10 @@ class MCoreTest(DeepState):
|
||||
val = ord(val)
|
||||
return val, ea + 1
|
||||
|
||||
def write_uint8_t(self, ea, val):
|
||||
self.state.cpu.write_int(ea, val, size=8)
|
||||
return ea + 1
|
||||
|
||||
def concretize(self, val, constrain=False):
|
||||
if isinstance(val, (int, long)):
|
||||
return val
|
||||
@@ -191,6 +195,19 @@ def hook_SoftFail(state):
|
||||
MCoreTest(state).api_soft_fail()
|
||||
|
||||
|
||||
def hook_ConcretizeData(state, begin_ea, end_ea):
|
||||
"""Implements the `Deeptate_ConcretizeData` API function, which lets the
|
||||
programmer concretize some data in the exclusive range
|
||||
`[begin_ea, end_ea)`."""
|
||||
return MCoreTest(state).api_concretize_data(begin_ea, end_ea)
|
||||
|
||||
|
||||
def hook_ConcretizeCStr(state, begin_ea):
|
||||
"""Implements the `Deeptate_ConcretizeCStr` API function, which lets the
|
||||
programmer concretize a NUL-terminated string starting at `begin_ea`."""
|
||||
return MCoreTest(state).api_concretize_cstr(begin_ea)
|
||||
|
||||
|
||||
def hook_Log(state, level, ea):
|
||||
"""Implements DeepState_Log, which lets Manticore intercept and handle the
|
||||
printing of log messages from the simulated tests."""
|
||||
@@ -225,6 +242,8 @@ def do_run_test(state, apis, test):
|
||||
make_symbolic_input(state, apis['InputBegin'], apis['InputEnd'])
|
||||
|
||||
m.add_hook(apis['IsSymbolicUInt'], hook(hook_IsSymbolicUInt))
|
||||
m.add_hook(apis['ConcretizeData'], hook(hook_ConcretizeData))
|
||||
m.add_hook(apis['ConcretizeCStr'], hook(hook_ConcretizeCStr))
|
||||
m.add_hook(apis['Assume'], hook(hook_Assume))
|
||||
m.add_hook(apis['Pass'], hook(hook_Pass))
|
||||
m.add_hook(apis['Fail'], hook(hook_Fail))
|
||||
|
||||
@@ -16,22 +16,22 @@
|
||||
|
||||
#include <deepstate/DeepState.hpp>
|
||||
|
||||
TEST(Streaming, BasicLevels) {
|
||||
LOG(DEBUG) << "This is a debug message";
|
||||
LOG(INFO) << "This is an info message";
|
||||
LOG(WARNING) << "This is a warning message";
|
||||
LOG(ERROR) << "This is a error message";
|
||||
LOG(INFO) << "This is a info message again";
|
||||
ASSERT(true) << "This should not be printed.";
|
||||
}
|
||||
|
||||
TEST(Streaming, BasicTypes) {
|
||||
LOG(INFO) << 'a';
|
||||
LOG(INFO) << 1;
|
||||
LOG(INFO) << 1.0;
|
||||
LOG(INFO) << "string";
|
||||
LOG(INFO) << nullptr;
|
||||
}
|
||||
//TEST(Streaming, BasicLevels) {
|
||||
// LOG(DEBUG) << "This is a debug message";
|
||||
// LOG(INFO) << "This is an info message";
|
||||
// LOG(WARNING) << "This is a warning message";
|
||||
// LOG(ERROR) << "This is a error message";
|
||||
// LOG(INFO) << "This is a info message again";
|
||||
// ASSERT(true) << "This should not be printed.";
|
||||
//}
|
||||
//
|
||||
//TEST(Streaming, BasicTypes) {
|
||||
// LOG(INFO) << 'a';
|
||||
// LOG(INFO) << 1;
|
||||
// LOG(INFO) << 1.0;
|
||||
// LOG(INFO) << "string";
|
||||
// LOG(INFO) << nullptr;
|
||||
//}
|
||||
|
||||
TEST(Formatting, OverridePrintf) {
|
||||
printf("hello string=%s hex_lower=%x hex_upper=%X octal=%o char=%c dec=%d"
|
||||
|
||||
+9
-6
@@ -186,14 +186,17 @@ int DeepState_IsSymbolicUInt(uint32_t x) {
|
||||
}
|
||||
|
||||
/* Defined in Stream.c */
|
||||
extern void _DeepState_StreamInt(enum DeepState_LogLevel level, const char *format,
|
||||
const char *unpack, uint64_t *val);
|
||||
extern void _DeepState_StreamInt(enum DeepState_LogLevel level,
|
||||
const char *format,
|
||||
const char *unpack, uint64_t *val);
|
||||
|
||||
extern void _DeepState_StreamFloat(enum DeepState_LogLevel level, const char *format,
|
||||
const char *unpack, double *val);
|
||||
extern void _DeepState_StreamFloat(enum DeepState_LogLevel level,
|
||||
const char *format,
|
||||
const char *unpack, double *val);
|
||||
|
||||
extern void _DeepState_StreamString(enum DeepState_LogLevel level, const char *format,
|
||||
const char *str);
|
||||
extern void _DeepState_StreamString(enum DeepState_LogLevel level,
|
||||
const char *format,
|
||||
const char *str);
|
||||
|
||||
/* A DeepState-specific symbol that is needed for hooking. */
|
||||
struct DeepState_IndexEntry {
|
||||
|
||||
+86
-24
@@ -14,12 +14,31 @@
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
/* Helps to avoid conflicting declaration types of `__printf_chk`. */
|
||||
#define printf printf_foo
|
||||
#define vprintf vprintf_foo
|
||||
#define fprintf fprintf_foo
|
||||
#define vfprintf vfprintf_foo
|
||||
#define __printf_chk __printf_chk_foo
|
||||
#define __vprintf_chk __vprintf_chk_foo
|
||||
#define __fprintf_chk __fprintf_chk_foo
|
||||
#define __vfprintf_chk __vfprintf_chk_foo
|
||||
|
||||
#include <stdarg.h>
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
|
||||
#include "deepstate/DeepState.h"
|
||||
|
||||
#undef printf
|
||||
#undef vprintf
|
||||
#undef fprintf
|
||||
#undef vfprintf
|
||||
#undef __printf_chk
|
||||
#undef __vprintf_chk
|
||||
#undef __fprintf_chk
|
||||
#undef __vfprintf_chk
|
||||
|
||||
DEEPSTATE_BEGIN_EXTERN_C
|
||||
|
||||
/* Returns a printable string version of the log level. */
|
||||
@@ -47,9 +66,10 @@ enum {
|
||||
char DeepState_LogBuf[DeepState_LogBufSize + 1] = {};
|
||||
|
||||
/* Log a C string. */
|
||||
DEEPSTATE_NOINLINE
|
||||
void DeepState_Log(enum DeepState_LogLevel level, const char *str) {
|
||||
memset(DeepState_LogBuf, 0, DeepState_LogBufSize);
|
||||
snprintf(DeepState_LogBuf, DeepState_LogBufSize, "%s: %s",
|
||||
snprintf(DeepState_LogBuf, DeepState_LogBufSize, "%s: %s\n",
|
||||
DeepState_LogLevelStr(level), str);
|
||||
fputs(DeepState_LogBuf, stderr);
|
||||
|
||||
@@ -61,48 +81,90 @@ void DeepState_Log(enum DeepState_LogLevel level, const char *str) {
|
||||
}
|
||||
|
||||
/* Log some formatted output. */
|
||||
void DeepState_LogFormat(enum DeepState_LogLevel level, const char *format, ...) {
|
||||
DEEPSTATE_NOINLINE
|
||||
void DeepState_LogVFormat(enum DeepState_LogLevel level,
|
||||
const char *format, va_list args) {
|
||||
DeepState_LogStream(level);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
DeepState_StreamVFormat(level, format, args);
|
||||
va_end(args);
|
||||
DeepState_LogStream(level);
|
||||
}
|
||||
|
||||
/* Log some formatted output. */
|
||||
void DeepState_LogVFormat(enum DeepState_LogLevel level,
|
||||
const char *format, va_list args) {
|
||||
DeepState_LogStream(level);
|
||||
DeepState_StreamVFormat(level, format, args);
|
||||
DeepState_LogStream(level);
|
||||
DEEPSTATE_NOINLINE
|
||||
void DeepState_LogFormat(enum DeepState_LogLevel level,
|
||||
const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
DeepState_LogVFormat(level, format, args);
|
||||
va_end(args);
|
||||
}
|
||||
|
||||
/* Override libc! */
|
||||
DEEPSTATE_NOINLINE
|
||||
int printf(const char *format, ...) {
|
||||
DeepState_LogStream(DeepState_LogInfo);
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
DeepState_StreamVFormat(DeepState_LogInfo, format, args);
|
||||
DeepState_LogVFormat(DeepState_LogInfo, format, args);
|
||||
va_end(args);
|
||||
DeepState_LogStream(DeepState_LogInfo);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int fprintf(FILE *file, const char *format, ...) {
|
||||
enum DeepState_LogLevel level = DeepState_LogInfo;
|
||||
if (stderr == file) {
|
||||
level = DeepState_LogDebug;
|
||||
} else if (stdout != file) {
|
||||
return 0; /* TODO(pag): This is probably evil. */
|
||||
}
|
||||
|
||||
DeepState_LogStream(level);
|
||||
DEEPSTATE_NOINLINE
|
||||
int __printf_chk(int flag, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
DeepState_StreamVFormat(level, format, args);
|
||||
DeepState_LogVFormat(DeepState_LogInfo, format, args);
|
||||
va_end(args);
|
||||
DeepState_LogStream(level);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEEPSTATE_NOINLINE
|
||||
int vprintf(const char *format, va_list args) {
|
||||
DeepState_LogVFormat(DeepState_LogInfo, format, args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEEPSTATE_NOINLINE
|
||||
int __vprintf_chk(int flag, const char *format, va_list args) {
|
||||
DeepState_LogVFormat(DeepState_LogInfo, format, args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEEPSTATE_NOINLINE
|
||||
int vfprintf(FILE *file, const char *format, va_list args) {
|
||||
if (stderr == file) {
|
||||
DeepState_LogVFormat(DeepState_LogDebug, format, args);
|
||||
} else if (stdout == file) {
|
||||
DeepState_LogVFormat(DeepState_LogInfo, format, args);
|
||||
} else {
|
||||
DeepState_LogStream(DeepState_LogWarning);
|
||||
DeepState_Log(DeepState_LogWarning,
|
||||
"Ignorning vfprintf with non-stdout/stderr stream.");
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEEPSTATE_NOINLINE
|
||||
int fprintf(FILE *file, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(file, format, args);
|
||||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEEPSTATE_NOINLINE
|
||||
int __fprintf_chk(int flag, FILE *file, const char *format, ...) {
|
||||
va_list args;
|
||||
va_start(args, format);
|
||||
vfprintf(file, format, args);
|
||||
va_end(args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DEEPSTATE_NOINLINE
|
||||
int __vfprintf_chk(int flag, FILE *file, const char *format, va_list args) {
|
||||
vfprintf(file, format, args);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
+11
-5
@@ -255,8 +255,7 @@ void DeepState_StreamDouble(enum DeepState_LogLevel level, double val) {
|
||||
void DeepState_LogStream(enum DeepState_LogLevel level) {
|
||||
struct DeepState_Stream *stream = &(DeepState_Streams[level]);
|
||||
if (stream->size) {
|
||||
stream->message[stream->size] = '\n';
|
||||
stream->message[stream->size + 1] = '\0';
|
||||
stream->message[stream->size] = '\0';
|
||||
stream->message[DeepState_StreamSize] = '\0';
|
||||
DeepState_Log(level, stream->message);
|
||||
memset(stream->message, 0, DeepState_StreamSize);
|
||||
@@ -501,6 +500,8 @@ get_length_char:
|
||||
stream->value.as_fp64 = va_arg(args, double);
|
||||
}
|
||||
DeepState_StreamUnpack(stream, 'd');
|
||||
_DeepState_StreamFloat(level, format_buf, stream->unpack,
|
||||
&(stream->value.as_fp64));
|
||||
break;
|
||||
|
||||
case 's':
|
||||
@@ -527,14 +528,19 @@ void DeepState_StreamVFormat(enum DeepState_LogLevel level, const char *format_,
|
||||
va_list args) {
|
||||
char *begin = NULL;
|
||||
char *end = NULL;
|
||||
char *format = DeepState_Format;
|
||||
char *format = &(DeepState_Format[0]);
|
||||
int i = 0;
|
||||
char ch = '\0';
|
||||
char next_ch = '\0';
|
||||
size_t len = strlen(format_);
|
||||
|
||||
strncpy(format, format_, DeepState_StreamSize);
|
||||
format[DeepState_StreamSize] = '\0';
|
||||
if (len >= DeepState_StreamSize) {
|
||||
DeepState_Abandon("Format string is too long.");
|
||||
}
|
||||
|
||||
/* Concretize the string format. */
|
||||
memcpy(format, format_, len);
|
||||
format[len] = '\0';
|
||||
DeepState_ConcretizeCStr(format);
|
||||
|
||||
for (i = 0; '\0' != (ch = format[i]); ) {
|
||||
|
||||
Reference in New Issue
Block a user