From 6459bd93d0d5ab25226f7ab7ed3ccf449f15696c Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Wed, 8 Aug 2018 12:42:48 -0400 Subject: [PATCH 001/228] Fixes Issue #96 to always log failures. --- src/include/deepstate/Stream.hpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/include/deepstate/Stream.hpp b/src/include/deepstate/Stream.hpp index e4c4c4d..f5bf58c 100644 --- a/src/include/deepstate/Stream.hpp +++ b/src/include/deepstate/Stream.hpp @@ -40,11 +40,10 @@ class Stream { DEEPSTATE_INLINE ~Stream(void) { if (do_log) { - if (has_something_to_log) { - DeepState_LogStream(level); - } else { - DeepState_ClearStream(level); + if (!has_something_to_log) { + DeepState_StreamCStr(level, "Condition failed"); } + DeepState_LogStream(level); } } From fa3820af157c311659ed3aaf8286efdd2a1464ea Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 8 Aug 2018 12:27:28 -0700 Subject: [PATCH 002/228] compile libfuzzer with UBSAN also --- CMakeLists.txt | 2 +- examples/CMakeLists.txt | 18 +++++++++--------- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index de68a02..d84ed65 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -98,7 +98,7 @@ if (BUILD_LIBFUZZER) src/lib/Stream.c ) - target_compile_options(${PROJECT_NAME}_LF PUBLIC -mno-avx -fsanitize=fuzzer-no-link) + target_compile_options(${PROJECT_NAME}_LF PUBLIC -mno-avx -fsanitize=fuzzer-no-link,undefined) target_include_directories(${PROJECT_NAME}_LF PUBLIC SYSTEM "${CMAKE_SOURCE_DIR}/src/include" diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index ab5ec63..062cab4 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -19,7 +19,7 @@ target_link_libraries(Crash deepstate) if (BUILD_LIBFUZZER) add_executable(Crash_LF Crash.cpp) target_link_libraries(Crash_LF deepstate_LF) - target_link_libraries (Crash_LF "-fsanitize=fuzzer") + target_link_libraries (Crash_LF "-fsanitize=fuzzer,undefined") set_target_properties(Crash_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() @@ -29,7 +29,7 @@ target_link_libraries(OneOf deepstate) if (BUILD_LIBFUZZER) add_executable(OneOf_LF OneOf.cpp) target_link_libraries(OneOf_LF deepstate_LF) - target_link_libraries (OneOf_LF "-fsanitize=fuzzer") + target_link_libraries (OneOf_LF "-fsanitize=fuzzer,undefined") set_target_properties(OneOf_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() @@ -39,7 +39,7 @@ target_link_libraries(Fixture deepstate) if (BUILD_LIBFUZZER) add_executable(Fixture_LF Fixture.cpp) target_link_libraries(Fixture_LF deepstate_LF) - target_link_libraries (Fixture_LF "-fsanitize=fuzzer") + target_link_libraries (Fixture_LF "-fsanitize=fuzzer,undefined") set_target_properties(Fixture_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() @@ -49,7 +49,7 @@ target_link_libraries(Primes deepstate) if (BUILD_LIBFUZZER) add_executable(Primes_LF Primes.cpp) target_link_libraries(Primes_LF deepstate_LF) - target_link_libraries (Primes_LF "-fsanitize=fuzzer") + target_link_libraries (Primes_LF "-fsanitize=fuzzer,undefined") set_target_properties(Primes_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() @@ -59,7 +59,7 @@ target_link_libraries(Euler deepstate) if (BUILD_LIBFUZZER) add_executable(Euler_LF Euler.cpp) target_link_libraries(Euler_LF deepstate_LF) - target_link_libraries (Euler_LF "-fsanitize=fuzzer") + target_link_libraries (Euler_LF "-fsanitize=fuzzer,undefined") set_target_properties(Euler_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() @@ -69,7 +69,7 @@ target_link_libraries(IntegerOverflow deepstate) if (BUILD_LIBFUZZER) add_executable(IntegerOverflow_LF IntegerOverflow.cpp) target_link_libraries(IntegerOverflow_LF deepstate_LF) - target_link_libraries (IntegerOverflow_LF "-fsanitize=fuzzer") + target_link_libraries (IntegerOverflow_LF "-fsanitize=fuzzer,undefined") set_target_properties(IntegerOverflow_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() @@ -79,7 +79,7 @@ target_link_libraries(IntegerArithmetic deepstate) if (BUILD_LIBFUZZER) add_executable(IntegerArithmetic_LF IntegerArithmetic.cpp) target_link_libraries(IntegerArithmetic_LF deepstate_LF) - target_link_libraries (IntegerArithmetic_LF "-fsanitize=fuzzer") + target_link_libraries (IntegerArithmetic_LF "-fsanitize=fuzzer,undefined") set_target_properties(IntegerArithmetic_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() @@ -89,7 +89,7 @@ target_link_libraries(Lists deepstate) if (BUILD_LIBFUZZER) add_executable(Lists_LF Lists.cpp) target_link_libraries(Lists_LF deepstate_LF) - target_link_libraries (Lists_LF "-fsanitize=fuzzer") + target_link_libraries (Lists_LF "-fsanitize=fuzzer,undefined") set_target_properties(Lists_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() @@ -99,7 +99,7 @@ target_link_libraries(StreamingAndFormatting deepstate) if (BUILD_LIBFUZZER) add_executable(StreamingAndFormatting_LF StreamingAndFormatting.cpp) target_link_libraries(StreamingAndFormatting_LF deepstate_LF) - target_link_libraries (StreamingAndFormatting_LF "-fsanitize=fuzzer") + target_link_libraries (StreamingAndFormatting_LF "-fsanitize=fuzzer,undefined") set_target_properties(StreamingAndFormatting_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() From 9747c8596a19acf2f496ee1dd1b8d7adb9c0b660 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 9 Aug 2018 13:42:51 -0700 Subject: [PATCH 003/228] instructions on replaying tests --- README.md | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) diff --git a/README.md b/README.md index 7ffaa43..dd545e2 100644 --- a/README.md +++ b/README.md @@ -85,6 +85,29 @@ deepstate-angr --num_workers 4 --output_test_dir out $DEEPSTATE/build/examples/I └── f1d3ff8443297732862df21dc4e57262.pass ``` +To run these tests, you can just use the native executable, e.g.: + +```shell +$DEEPSTATE/build/examples/IntegerOverflow --input_test_dir out +``` + +to run all the generated tests, or + +```shell +$DEEPSTATE/build/examples/IntegerOverflow --input_test_files_dir out/IntegerOverflow.cpp/SignedInteger_AdditionOverflow --input_which_test SignedInteger_AdditionOverflow +``` + +to run the tests in one directory (in this case, you want to specify +which test to run, also). You can also run a single test, e.g.: + +```shell +$DEEPSTATE/build/examples/IntegerOverflow --input_test_file out/IntegerOverflow.cpp/SignedInteger_AdditionOverflow/a512f8ffb2c1bb775a9779ec60b699cb.fail--input_which_test SignedInteger_AdditionOverflow +``` + +In the absence of an `--input_which_test` argument, DeepState defaults +to the last-defined test. Run the native executable with the `--help` +argument to see all DeepState options. + ## Usage DeepState consists of a static library, used to write test harnesses, and command-line _executors_ written in Python. At this time, the best documentation is in the [examples](/examples) and in our [paper](https://agroce.github.io/bar18.pdf). From 0fbd80a0b1328950bb5f9aa6d58711d5476c2035 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 27 Aug 2018 09:02:50 -0700 Subject: [PATCH 004/228] less confusing output for assumes --- src/include/deepstate/Stream.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/deepstate/Stream.hpp b/src/include/deepstate/Stream.hpp index f5bf58c..e2db526 100644 --- a/src/include/deepstate/Stream.hpp +++ b/src/include/deepstate/Stream.hpp @@ -41,7 +41,7 @@ class Stream { DEEPSTATE_INLINE ~Stream(void) { if (do_log) { if (!has_something_to_log) { - DeepState_StreamCStr(level, "Condition failed"); + DeepState_StreamCStr(level, "Checked condition"); } DeepState_LogStream(level); } From cb55fa66eca6a8df8ebabe136fbca1eda14b5e1e Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Tue, 28 Aug 2018 15:53:50 -0300 Subject: [PATCH 005/228] Fix manticore --- .travis.yml | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 9dc83af..7ad3edc 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,9 +7,7 @@ install: - pip install pyflakes - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev -- sudo pip install -U pip ; sudo pip install manticore -- sudo pip uninstall -y Manticore || echo "Manticore not cached" -- sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip +- sudo pip install -U pip ; sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip - mkdir build - cd build - cmake .. From 38b438d55ebbf9d072551f506a912d9f445ad09a Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Tue, 28 Aug 2018 16:16:58 -0300 Subject: [PATCH 006/228] Update .travis.yml --- .travis.yml | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7ad3edc..cd8ec52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,10 @@ install: - pip install pyflakes - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev -- sudo pip install -U pip ; sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip +- sudo pip2 install -U pip2 +- wget https://github.com/trailofbits/manticore/archive/last_python2.zip +- unzip last_python2.zip +- cd manticore-last_python2 ; python2 setup install --user ; cd - - mkdir build - cd build - cmake .. From 316a8c59cef090d9ecdf383c7c961edfb4e7987c Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Tue, 28 Aug 2018 17:05:17 -0300 Subject: [PATCH 007/228] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index cd8ec52..22a1da2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,7 +7,7 @@ install: - pip install pyflakes - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev -- sudo pip2 install -U pip2 +- sudo pip2 install -U pip - wget https://github.com/trailofbits/manticore/archive/last_python2.zip - unzip last_python2.zip - cd manticore-last_python2 ; python2 setup install --user ; cd - From ef30504908beaa13ae934cf3880828870788a261 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Tue, 28 Aug 2018 18:16:30 -0300 Subject: [PATCH 008/228] Fix manticore version --- bin/setup.py.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/setup.py.in b/bin/setup.py.in index f1eca5b..b926ffa 100644 --- a/bin/setup.py.in +++ b/bin/setup.py.in @@ -30,7 +30,7 @@ setuptools.setup( author_email="peter@trailofbits.com", license="Apache-2.0", keywords="tdd testing symbolic execution", - install_requires=['claripy==7.8.6.16','angr==7.8.7.1', 'manticore'], + install_requires=['claripy==7.8.6.16','angr==7.8.7.1', 'manticore==0.1.10'], entry_points={ 'console_scripts': [ 'deepstate = deepstate.main_manticore:main', From 5a2c6460f8052614d7df4f8a8636a96e03ab3f9b Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Tue, 28 Aug 2018 18:16:52 -0300 Subject: [PATCH 009/228] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 22a1da2..e950aae 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ install: - sudo pip2 install -U pip - wget https://github.com/trailofbits/manticore/archive/last_python2.zip - unzip last_python2.zip -- cd manticore-last_python2 ; python2 setup install --user ; cd - +- cd manticore-last_python2 ; python2 setup.py install --user ; cd - - mkdir build - cd build - cmake .. From e7a7b7d68f050d990a8521a6dee8c6c7228d9801 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Tue, 28 Aug 2018 19:54:34 -0300 Subject: [PATCH 010/228] Update .travis.yml --- .travis.yml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index e950aae..d83e607 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,10 +7,9 @@ install: - pip install pyflakes - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev -- sudo pip2 install -U pip -- wget https://github.com/trailofbits/manticore/archive/last_python2.zip -- unzip last_python2.zip -- cd manticore-last_python2 ; python2 setup.py install --user ; cd - +- sudo pip2 install -U pip +- sudo pip install z3-solver +- sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip - mkdir build - cd build - cmake .. From 91376842ba749f4f447d7e775e2bde5b5ee6eb59 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 11:27:22 -0700 Subject: [PATCH 011/228] provide a mode where bytes read are made explicit --- src/include/deepstate/DeepState.h | 1 + src/lib/DeepState.c | 10 ++++++++++ 2 files changed, 11 insertions(+) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 17dd324..518411f 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -62,6 +62,7 @@ DECLARE_string(output_test_dir); DECLARE_bool(take_over); DECLARE_bool(abort_on_fail); +DECLARE_bool(verbose_reads); enum { DeepState_InputSize = 8192 diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index db3a0ed..7797616 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -36,6 +36,7 @@ DEFINE_string(output_test_dir, "", "Directory where tests will be saved."); DEFINE_bool(take_over, false, "Replay test cases in take-over mode."); DEFINE_bool(abort_on_fail, false, "Abort on file replay failure (useful in file fuzzing)."); +DEFINE_bool(verbose_reads, false, "Report on bytes being read during execution of test."); /* Pointer to the last registers DeepState_TestInfo data structure */ struct DeepState_TestInfo *DeepState_LastTestInfo = NULL; @@ -140,6 +141,9 @@ void DeepState_SymbolizeData(void *begin, void *end) { if (DeepState_InputIndex >= DeepState_InputSize) { DeepState_Abandon("Read too many symbols"); } + if (FLAGS_verbose_reads) { + printf ("Reading byte at %u\n", DeepState_InputIndex); + } bytes[i] = DeepState_Input[DeepState_InputIndex++]; } } @@ -216,6 +220,9 @@ int DeepState_Bool(void) { if (DeepState_InputIndex >= DeepState_InputSize) { DeepState_Abandon("Read too many symbols"); } + if (FLAGS_verbose_reads) { + printf ("Reading byte as boolean at %u\n", DeepState_InputIndex); + } return DeepState_Input[DeepState_InputIndex++] & 1; } @@ -227,6 +234,9 @@ int DeepState_Bool(void) { type val = 0; \ _Pragma("unroll") \ for (size_t i = 0; i < sizeof(type); ++i) { \ + if (FLAGS_verbose_reads) { \ + printf ("Reading byte at %u\n", DeepState_InputIndex); \ + } \ val = (val << 8) | ((type) DeepState_Input[DeepState_InputIndex++]); \ } \ return val; \ From 4a003b944caf57be71e3b8130866fb03203d968a Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 11:36:09 -0700 Subject: [PATCH 012/228] signal OneOfs also --- src/include/deepstate/DeepState.hpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index f607bc8..6380d30 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -327,10 +327,16 @@ inline static void ForAll(Closure func) { template inline static void OneOf(FuncTys&&... funcs) { + if (FLAGS_verbose_reads) { + printf("DeepState: STARTING OneOf CALL\n"); + } std::function func_arr[sizeof...(FuncTys)] = {funcs...}; unsigned index = DeepState_UIntInRange( 0U, static_cast(sizeof...(funcs))-1); func_arr[Pump(index, sizeof...(funcs))](); + if (FLAGS_verbose_reads) { + printf("DeepState: FINISHED OneOf CALL\n"); + } } inline static char OneOf(const char *str) { From 9923c591c11a01b512e76424b0e9dc9807acfb0b Mon Sep 17 00:00:00 2001 From: root Date: Sat, 1 Sep 2018 20:48:09 +0000 Subject: [PATCH 013/228] add entry point for reducer --- bin/deepstate/reducer.py | 137 +++++++++++++++++++++++++++++++++++++++ bin/setup.py.in | 1 + 2 files changed, 138 insertions(+) create mode 100644 bin/deepstate/reducer.py diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py new file mode 100644 index 0000000..ad02d11 --- /dev/null +++ b/bin/deepstate/reducer.py @@ -0,0 +1,137 @@ +import sys +import subprocess +import os +import shutil + +def main(): + if "--help" in sys.argv: + print "usage: deepstate-reduce binary input-test output-test [string] [--which test]" + print + print "Reduces input-test by trying to delete OneOf blocks and lower byte values." + print + print "Writes reduced test to output-test." + print + print "Optional string gives an reduction criteria (searched for in test output)." + print "If no string is provided, looks for Failure or Crash." + print + print "--which test allows control over which DeepState test is executed, if none" + print "is provided, defaults to last test defined." + sys.exit(0) + + args = sys.argv + + try: + which = args.index("--which") + whichTest = args[which+1] + args = args[:which] + args[which + 2:] + except: + whichTest = None + + deepstate = args[1] + test = args[2] + out = args[3] + if len(args) > 4: + checkString = args[4] + else: + checkString = None + + def runCandidate(candidate): + with open(".reducer.out", 'w') as outf: + cmd = [deepstate + " --input_test_file " + + candidate + " --verbose_reads"] + if whichTest is not None: + cmd += ["--input_which_test", whichTest] + subprocess.call(cmd, shell=True, stdout=outf, stderr=outf) + result = [] + with open(".reducer.out", 'r') as inf: + for line in inf: + result.append(line) + return result + + def checks(result): + for line in result: + if checkString: + if checkString in line: + return True + else: + if "ERROR: Failed:" in line: + return True + if "ERROR: Crashed" in line: + return True + return False + + def structure(result): + OneOfs = [] + currentOneOf = [] + for line in result: + if "STARTING OneOf CALL" in line: + currentOneOf.append(-1) + elif "Reading byte at" in line: + lastRead = int(line.split()[-1]) + if currentOneOf[-1] == -1: + currentOneOf[-1] = lastRead + elif "FINISHED OneOf CALL" in line: + OneOfs.append((currentOneOf[-1], lastRead)) + currentOneOf = currentOneOf[:-1] + return (OneOfs, lastRead) + + initial = runCandidate(test) + if not checks(initial): + print "STARTING TEST DOES NOT SATISFY REDUCTION CRITERIA" + return 1 + + with open(test, 'rb') as test: + currentTest = bytearray(test.read()) + + print "ORIGINAL TEST HAS", len(currentTest), "BYTES" + + s = structure(initial) + print "LAST BYTE READ IS", s[1] + + if s[1] < len(currentTest): + print "SHRINKING TO IGNORE UNREAD BYTES" + currentTest = currentTest[:s[1]+1] + + changed = True + while changed: + changed = False + cuts = s[0] + for c in cuts: + newTest = currentTest[:c[0]] + currentTest[c[1]+1:] + with open(".candidate.test", 'wb') as outf: + outf.write(newTest) + r = runCandidate(".candidate.test") + if checks(r): + print "ONEOF REMOVAL REDUCED TEST TO", len(newTest), "BYTES" + s = structure(r) + changed = True + currentTest = newTest + break + for b in range(0, len(currentTest)): + for v in range(0, currentTest[b]): + newTest = bytearray(currentTest) + newTest[b] = v + with open(".candidate.test", 'wb') as outf: + outf.write(newTest) + r = runCandidate(".candidate.test") + if checks(r): + print "BYTE REDUCTION: BYTE", b, "FROM", currentTest[b], "TO", v + s = structure(r) + changed = True + currentTest = newTest + break + if not changed: + print "NO REDUCTIONS FOUND" + + if (s[1] + 1) > len(currentTest): + print "PADDING TEST WITH", (s[1] + 1) - len(currentTest), "ZEROS" + padding = bytearray('\x00' * ((s[1] + 1) - len(currentTest))) + currentTest = currentTest + padding + + with open(out, 'wb') as outf: + outf.write(currentTest) + + return 0 + +if "__main__" == __name__: + exit(main()) diff --git a/bin/setup.py.in b/bin/setup.py.in index b926ffa..dfb965e 100644 --- a/bin/setup.py.in +++ b/bin/setup.py.in @@ -36,5 +36,6 @@ setuptools.setup( 'deepstate = deepstate.main_manticore:main', 'deepstate-angr = deepstate.main_angr:main', 'deepstate-manticore = deepstate.main_manticore:main', + 'deepstate-reduce = deepstate.reducer:main', ] }) From 54d2c8180a1de75be786da05c4ac787acc8379a7 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 14:04:31 -0700 Subject: [PATCH 014/228] update README, nicer output from reducer --- README.md | 52 ++++++++++++++++++++++++++++++++++++++++ bin/deepstate/reducer.py | 5 +++- 2 files changed, 56 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index dd545e2..041b3e6 100644 --- a/README.md +++ b/README.md @@ -144,6 +144,58 @@ memory during a test, if that memory would not be freed on a test failure. This will leak memory and libFuzzer will run out of memory very quickly in each fuzzing session. +## Test case reduction + +While tests generated by symbolic execution are likely to be highly +concise already, fuzzer-generated tests may be much larger than they +need to be. + +DeepState provides a test case reducer to shrink tests intelligently, +aware of the structure of a DeepState test. For example, if your +executable is named `TestFileSystem` and the test you want to reduce +is named `rmdirfail.test` you would use it like this: + +```shell +deepstate-reduce ./TestFileSystem rmdirfail.test minrmdirfail.test +``` + +In many cases, this will result in finding a different failure or +crash that allow smaller test cases, so you can also provide a string +that controls which test outputs are considered valid reductions (by +default, the reducer looks for any test that fails or crashes): + +```shell +deepstate-reduce ./TestFileSystem rmdirfail.test minrmdirfail.test "FATAL: /root/testfs/super.c(252)" +``` + +The output will look something like: +```shell +ORIGINAL TEST HAS 119 BYTES +LAST BYTE READ IS 123 +ONEOF REMOVAL REDUCED TEST TO 103 BYTES +BYTE REDUCTION: BYTE 3 FROM 4 TO 0 +BYTE REDUCTION: BYTE 7 FROM 2 TO 1 +BYTE REDUCTION: BYTE 15 FROM 3 TO 2 +BYTE REDUCTION: BYTE 19 FROM 4 TO 0 +BYTE REDUCTION: BYTE 55 FROM 3 TO 1 +BYTE REDUCTION: BYTE 59 FROM 2 TO 0 +BYTE REDUCTION: BYTE 75 FROM 2 TO 0 +BYTE REDUCTION: BYTE 79 FROM 4 TO 0 +ONEOF REMOVAL REDUCED TEST TO 91 BYTES +BYTE REDUCTION: BYTE 59 FROM 4 TO 0 +ONEOF REMOVAL REDUCED TEST TO 87 BYTES +ONEOF REMOVAL REDUCED TEST TO 75 BYTES +ONEOF REMOVAL REDUCED TEST TO 55 BYTES +ONEOF REMOVAL REDUCED TEST TO 51 BYTES +NO REDUCTIONS FOUND +PADDING TEST WITH 5 ZEROS + +WRITING REDUCED TEST TO minrmdirfail.test +``` + +You can use `--which ` to specify which test to +run, as with the `--input_which_test` options to test replay. + ## Fuzzing with AFL DeepState can also be used with a file-based fuzzer (e.g. AFL). There diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index ad02d11..11bac2b 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -127,7 +127,10 @@ def main(): print "PADDING TEST WITH", (s[1] + 1) - len(currentTest), "ZEROS" padding = bytearray('\x00' * ((s[1] + 1) - len(currentTest))) currentTest = currentTest + padding - + + print + print "WRITING REDUCED TEST TO", out + with open(out, 'wb') as outf: outf.write(currentTest) From 2fdd239827411b148fae4a855a7e7fd8436c956f Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 14:19:29 -0700 Subject: [PATCH 015/228] make pyflakes happy by removing spurious imports --- bin/deepstate/reducer.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 11bac2b..85094c7 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -1,7 +1,5 @@ import sys import subprocess -import os -import shutil def main(): if "--help" in sys.argv: From b2e1d86cf78dcf8b79322901ac93e85959e5f164 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 14:27:39 -0700 Subject: [PATCH 016/228] allow byte range removal too --- bin/deepstate/reducer.py | 14 +++++++++++++- 1 file changed, 13 insertions(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 85094c7..9f8589d 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -105,6 +105,18 @@ def main(): changed = True currentTest = newTest break + for b in range(0, len(currentTest)): + for v in range(b+1, len(currentTest)): + newTest = currentTest[:b] + currentTest[v:] + with open(".candidate.test", 'wb') as outf: + outf.write(newTest) + r = runCandidate(".candidate.test") + if checks(r): + print "BYTE RANGE REMOVAL REDUCED TEST TO", len(newTest), "BYTES" + s = structure(r) + changed = True + currentTest = newTest + break for b in range(0, len(currentTest)): for v in range(0, currentTest[b]): newTest = bytearray(currentTest) @@ -117,7 +129,7 @@ def main(): s = structure(r) changed = True currentTest = newTest - break + break if not changed: print "NO REDUCTIONS FOUND" From 90a94ef2fbaacc383a24b39158ae330a9d270956 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 14:31:58 -0700 Subject: [PATCH 017/228] start with new pass on reduction --- bin/deepstate/reducer.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 9f8589d..5dc9215 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -105,6 +105,8 @@ def main(): changed = True currentTest = newTest break + if changed: + continue for b in range(0, len(currentTest)): for v in range(b+1, len(currentTest)): newTest = currentTest[:b] + currentTest[v:] @@ -117,6 +119,8 @@ def main(): changed = True currentTest = newTest break + if changed: + continue for b in range(0, len(currentTest)): for v in range(0, currentTest[b]): newTest = bytearray(currentTest) From 97618c2a24dd432ecb140cc7d423bc17a2cb85d6 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 15:53:21 -0700 Subject: [PATCH 018/228] start addressing peter's comments --- bin/deepstate/reducer.py | 20 ++++++++++++++++++-- 1 file changed, 18 insertions(+), 2 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 5dc9215..403e39e 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -1,5 +1,21 @@ +#!/usr/bin/env python +# Copyright (c) 2018 Trail of Bits, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + import sys import subprocess +import argparse def main(): if "--help" in sys.argv: @@ -134,8 +150,8 @@ def main(): changed = True currentTest = newTest break - if not changed: - print "NO REDUCTIONS FOUND" + + print "NO REDUCTIONS FOUND" if (s[1] + 1) > len(currentTest): print "PADDING TEST WITH", (s[1] + 1) - len(currentTest), "ZEROS" From 69a84c7b6808581c00f01697bff296031800957b Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 17:22:40 -0700 Subject: [PATCH 019/228] fix C code according to pgoodman comments, annotate multi-byte reads --- bin/deepstate/reducer.py | 2 ++ src/include/deepstate/DeepState.hpp | 4 ++-- src/lib/DeepState.c | 16 +++++++++++----- 3 files changed, 15 insertions(+), 7 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 403e39e..334ef80 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -32,6 +32,8 @@ def main(): print "is provided, defaults to last test defined." sys.exit(0) + parser = argparse.ArgumentParser(description="Intelligently reduce test case") + args = sys.argv try: diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index 6380d30..460155b 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -328,14 +328,14 @@ inline static void ForAll(Closure func) { template inline static void OneOf(FuncTys&&... funcs) { if (FLAGS_verbose_reads) { - printf("DeepState: STARTING OneOf CALL\n"); + printf("STARTING OneOf CALL\n"); } std::function func_arr[sizeof...(FuncTys)] = {funcs...}; unsigned index = DeepState_UIntInRange( 0U, static_cast(sizeof...(funcs))-1); func_arr[Pump(index, sizeof...(funcs))](); if (FLAGS_verbose_reads) { - printf("DeepState: FINISHED OneOf CALL\n"); + printf("FINISHED OneOf CALL\n"); } } diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 7797616..f9ce633 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -142,7 +142,7 @@ void DeepState_SymbolizeData(void *begin, void *end) { DeepState_Abandon("Read too many symbols"); } if (FLAGS_verbose_reads) { - printf ("Reading byte at %u\n", DeepState_InputIndex); + printf("Reading byte at %u\n", DeepState_InputIndex); } bytes[i] = DeepState_Input[DeepState_InputIndex++]; } @@ -221,7 +221,7 @@ int DeepState_Bool(void) { DeepState_Abandon("Read too many symbols"); } if (FLAGS_verbose_reads) { - printf ("Reading byte as boolean at %u\n", DeepState_InputIndex); + printf("Reading byte as boolean at %u\n", DeepState_InputIndex); } return DeepState_Input[DeepState_InputIndex++] & 1; } @@ -232,13 +232,19 @@ int DeepState_Bool(void) { DeepState_Abandon("Read too many symbols"); \ } \ type val = 0; \ + if (FLAGS_verbose_reads) { \ + printf("STARTING MULTI-BYTE READ\n"); \ + } \ _Pragma("unroll") \ for (size_t i = 0; i < sizeof(type); ++i) { \ - if (FLAGS_verbose_reads) { \ - printf ("Reading byte at %u\n", DeepState_InputIndex); \ - } \ + if (FLAGS_verbose_reads) { \ + printf("Reading byte at %u\n", DeepState_InputIndex); \ + } \ val = (val << 8) | ((type) DeepState_Input[DeepState_InputIndex++]); \ } \ + if (FLAGS_verbose_reads) { \ + printf("FINISHED MULTI-BYTE READ\n"); \ + } \ return val; \ } From d33caaf4194b2f6077ea1fbb213328a242966eba Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 17:23:50 -0700 Subject: [PATCH 020/228] fix spacing --- src/lib/DeepState.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index f9ce633..9aea252 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -234,7 +234,7 @@ int DeepState_Bool(void) { type val = 0; \ if (FLAGS_verbose_reads) { \ printf("STARTING MULTI-BYTE READ\n"); \ - } \ + } \ _Pragma("unroll") \ for (size_t i = 0; i < sizeof(type); ++i) { \ if (FLAGS_verbose_reads) { \ @@ -244,7 +244,7 @@ int DeepState_Bool(void) { } \ if (FLAGS_verbose_reads) { \ printf("FINISHED MULTI-BYTE READ\n"); \ - } \ + } \ return val; \ } From 21c23d1152d3ccdee7acdbf7f7bba9b9b786c47f Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 17:26:14 -0700 Subject: [PATCH 021/228] silence pyflakes until we use the parser --- bin/deepstate/reducer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 334ef80..93730cb 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -33,6 +33,8 @@ def main(): sys.exit(0) parser = argparse.ArgumentParser(description="Intelligently reduce test case") + if parser: + pass args = sys.argv From 2764bcfe3a54b1b952f3446c26a888071d21f6ac Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 21:02:33 -0700 Subject: [PATCH 022/228] Edit readme to match new options to reducer --- README.md | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 041b3e6..f6b323c 100644 --- a/README.md +++ b/README.md @@ -161,11 +161,13 @@ deepstate-reduce ./TestFileSystem rmdirfail.test minrmdirfail.test In many cases, this will result in finding a different failure or crash that allow smaller test cases, so you can also provide a string -that controls which test outputs are considered valid reductions (by -default, the reducer looks for any test that fails or crashes): +that controls the criteria for which test outputs are considered valid +reductions (by default, the reducer looks for any test that fails or +crashes). Only outputs containing the `--criteria` are considered to +be valid reductions: ```shell -deepstate-reduce ./TestFileSystem rmdirfail.test minrmdirfail.test "FATAL: /root/testfs/super.c(252)" +deepstate-reduce ./TestFileSystem rmdirfail.test minrmdirfail.test --criteria "FATAL: /root/testfs/super.c(252)" ``` The output will look something like: @@ -193,7 +195,7 @@ PADDING TEST WITH 5 ZEROS WRITING REDUCED TEST TO minrmdirfail.test ``` -You can use `--which ` to specify which test to +You can use `--which_test ` to specify which test to run, as with the `--input_which_test` options to test replay. ## Fuzzing with AFL From f6cceffa339e4c521cc022c9a65b0e38e6761c7c Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 21:04:24 -0700 Subject: [PATCH 023/228] fix argument name --- bin/deepstate/reducer.py | 40 +++++++++++++++++++++++----------------- 1 file changed, 23 insertions(+), 17 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 93730cb..37aff6e 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -32,26 +32,32 @@ def main(): print "is provided, defaults to last test defined." sys.exit(0) + parser = argparse.ArgumentParser(description="Intelligently reduce test case") - if parser: - pass - - args = sys.argv - try: - which = args.index("--which") - whichTest = args[which+1] - args = args[:which] + args[which + 2:] - except: - whichTest = None + parser.add_argument( + "binary", type=str, help="Path to the test binary to run.") - deepstate = args[1] - test = args[2] - out = args[3] - if len(args) > 4: - checkString = args[4] - else: - checkString = None + parser.add_argument( + "input_test", type=str, help="Path to test to reduce.") + + parser.add_argument( + "output_test", type=str, help="Path for reduced test.") + + parser.add_argument( + "--which_test", type=str, help="Which test run run.", default=None) + + parser.add_argument( + "--criteria", type=str, help="String to search for in valid reduction outputs.", + default=None) + + args = parser.parse_args() + + deepstate = args.binary + test = args.input_test + out = args.output_test + checkString = args.criteria + whichTest = args.which_test def runCandidate(candidate): with open(".reducer.out", 'w') as outf: From ab03350142b47315ab4d26e272f2496f4834d7e1 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 21:09:23 -0700 Subject: [PATCH 024/228] get rid of my help --- bin/deepstate/reducer.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 37aff6e..d9e8e96 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -18,21 +18,6 @@ import subprocess import argparse def main(): - if "--help" in sys.argv: - print "usage: deepstate-reduce binary input-test output-test [string] [--which test]" - print - print "Reduces input-test by trying to delete OneOf blocks and lower byte values." - print - print "Writes reduced test to output-test." - print - print "Optional string gives an reduction criteria (searched for in test output)." - print "If no string is provided, looks for Failure or Crash." - print - print "--which test allows control over which DeepState test is executed, if none" - print "is provided, defaults to last test defined." - sys.exit(0) - - parser = argparse.ArgumentParser(description="Intelligently reduce test case") parser.add_argument( From 473ad72d07d8f4b0295eddea62dbf4c9870cf479 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 21:11:06 -0700 Subject: [PATCH 025/228] fix help --- bin/deepstate/reducer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index d9e8e96..bb167e5 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -30,7 +30,7 @@ def main(): "output_test", type=str, help="Path for reduced test.") parser.add_argument( - "--which_test", type=str, help="Which test run run.", default=None) + "--which_test", type=str, help="Which test to run (equivalent to --input_which_test).", default=None) parser.add_argument( "--criteria", type=str, help="String to search for in valid reduction outputs.", From faa241b160f249a7c6f9d523d7620d6f70720639 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Sep 2018 21:58:04 -0700 Subject: [PATCH 026/228] remove sys import --- bin/deepstate/reducer.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index bb167e5..c123252 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -13,9 +13,8 @@ # See the License for the specific language governing permissions and # limitations under the License. -import sys -import subprocess import argparse +import subprocess def main(): parser = argparse.ArgumentParser(description="Intelligently reduce test case") From e08c7c84792bf4c7e312f0ce90818dcd409b8c17 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 2 Sep 2018 13:03:44 -0700 Subject: [PATCH 027/228] reduce + del operation --- bin/deepstate/reducer.py | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index c123252..4f5a7df 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -144,6 +144,19 @@ def main(): changed = True currentTest = newTest break + for b in range(0, len(currentTest)): + newTest = byteArray(currentTest) + newTest[b] = currentTest[b]-1 + newTest = newTest[:b+1] + newTest[b+2] + with open(".candidate.test", 'wb') as outf: + outf.write(newTest) + r = runCandidate(".candidate.test") + if checks(r): + print "BYTE REDUCE AND DELETE AT BYTE", b + s = structure(r) + changed = True + currentTest = newTest + break print "NO REDUCTIONS FOUND" From b0ca3ee60e118b0385760ac08a4b52aa66e135a8 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 2 Sep 2018 13:05:44 -0700 Subject: [PATCH 028/228] fix typo in type name --- bin/deepstate/reducer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 4f5a7df..66a2643 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -145,7 +145,7 @@ def main(): currentTest = newTest break for b in range(0, len(currentTest)): - newTest = byteArray(currentTest) + newTest = bytearray(currentTest) newTest[b] = currentTest[b]-1 newTest = newTest[:b+1] + newTest[b+2] with open(".candidate.test", 'wb') as outf: From ba25358ebf36b89a8e4f5c61ad34b8749eef66ef Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 2 Sep 2018 13:07:23 -0700 Subject: [PATCH 029/228] handle zero bytes in reduce-delete --- bin/deepstate/reducer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 66a2643..26a6eab 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -145,6 +145,8 @@ def main(): currentTest = newTest break for b in range(0, len(currentTest)): + if currentTest[b] == 0: + continue newTest = bytearray(currentTest) newTest[b] = currentTest[b]-1 newTest = newTest[:b+1] + newTest[b+2] From 3625454fbb75b9bdcd1145c211a5471d90545f71 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 2 Sep 2018 13:16:30 -0700 Subject: [PATCH 030/228] range, not value --- bin/deepstate/reducer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 26a6eab..e61ab33 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -149,7 +149,7 @@ def main(): continue newTest = bytearray(currentTest) newTest[b] = currentTest[b]-1 - newTest = newTest[:b+1] + newTest[b+2] + newTest = newTest[:b+1] + newTest[b+2:] with open(".candidate.test", 'wb') as outf: outf.write(newTest) r = runCandidate(".candidate.test") From 494a5eaaf46246434490312b1857db6cdb56dbb2 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 2 Sep 2018 20:17:13 -0700 Subject: [PATCH 031/228] fix indent to two --- bin/deepstate/reducer.py | 274 +++++++++++++++++++-------------------- 1 file changed, 137 insertions(+), 137 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index e61ab33..1821175 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -17,163 +17,163 @@ import argparse import subprocess def main(): - parser = argparse.ArgumentParser(description="Intelligently reduce test case") + parser = argparse.ArgumentParser(description="Intelligently reduce test case") - parser.add_argument( - "binary", type=str, help="Path to the test binary to run.") + parser.add_argument( + "binary", type=str, help="Path to the test binary to run.") - parser.add_argument( - "input_test", type=str, help="Path to test to reduce.") + parser.add_argument( + "input_test", type=str, help="Path to test to reduce.") - parser.add_argument( - "output_test", type=str, help="Path for reduced test.") + parser.add_argument( + "output_test", type=str, help="Path for reduced test.") - parser.add_argument( - "--which_test", type=str, help="Which test to run (equivalent to --input_which_test).", default=None) + parser.add_argument( + "--which_test", type=str, help="Which test to run (equivalent to --input_which_test).", default=None) - parser.add_argument( - "--criteria", type=str, help="String to search for in valid reduction outputs.", - default=None) + parser.add_argument( + "--criteria", type=str, help="String to search for in valid reduction outputs.", + default=None) - args = parser.parse_args() + args = parser.parse_args() - deepstate = args.binary - test = args.input_test - out = args.output_test - checkString = args.criteria - whichTest = args.which_test + deepstate = args.binary + test = args.input_test + out = args.output_test + checkString = args.criteria + whichTest = args.which_test - def runCandidate(candidate): - with open(".reducer.out", 'w') as outf: - cmd = [deepstate + " --input_test_file " + - candidate + " --verbose_reads"] - if whichTest is not None: - cmd += ["--input_which_test", whichTest] - subprocess.call(cmd, shell=True, stdout=outf, stderr=outf) - result = [] - with open(".reducer.out", 'r') as inf: - for line in inf: - result.append(line) - return result + def runCandidate(candidate): + with open(".reducer.out", 'w') as outf: + cmd = [deepstate + " --input_test_file " + + candidate + " --verbose_reads"] + if whichTest is not None: + cmd += ["--input_which_test", whichTest] + subprocess.call(cmd, shell=True, stdout=outf, stderr=outf) + result = [] + with open(".reducer.out", 'r') as inf: + for line in inf: + result.append(line) + return result - def checks(result): - for line in result: - if checkString: - if checkString in line: - return True - else: - if "ERROR: Failed:" in line: - return True - if "ERROR: Crashed" in line: - return True - return False + def checks(result): + for line in result: + if checkString: + if checkString in line: + return True + else: + if "ERROR: Failed:" in line: + return True + if "ERROR: Crashed" in line: + return True + return False - def structure(result): - OneOfs = [] - currentOneOf = [] - for line in result: - if "STARTING OneOf CALL" in line: - currentOneOf.append(-1) - elif "Reading byte at" in line: - lastRead = int(line.split()[-1]) - if currentOneOf[-1] == -1: - currentOneOf[-1] = lastRead - elif "FINISHED OneOf CALL" in line: - OneOfs.append((currentOneOf[-1], lastRead)) - currentOneOf = currentOneOf[:-1] - return (OneOfs, lastRead) + def structure(result): + OneOfs = [] + currentOneOf = [] + for line in result: + if "STARTING OneOf CALL" in line: + currentOneOf.append(-1) + elif "Reading byte at" in line: + lastRead = int(line.split()[-1]) + if currentOneOf[-1] == -1: + currentOneOf[-1] = lastRead + elif "FINISHED OneOf CALL" in line: + OneOfs.append((currentOneOf[-1], lastRead)) + currentOneOf = currentOneOf[:-1] + return (OneOfs, lastRead) - initial = runCandidate(test) - if not checks(initial): - print "STARTING TEST DOES NOT SATISFY REDUCTION CRITERIA" - return 1 + initial = runCandidate(test) + if not checks(initial): + print "STARTING TEST DOES NOT SATISFY REDUCTION CRITERIA" + return 1 - with open(test, 'rb') as test: - currentTest = bytearray(test.read()) + with open(test, 'rb') as test: + currentTest = bytearray(test.read()) - print "ORIGINAL TEST HAS", len(currentTest), "BYTES" + print "ORIGINAL TEST HAS", len(currentTest), "BYTES" - s = structure(initial) - print "LAST BYTE READ IS", s[1] + s = structure(initial) + print "LAST BYTE READ IS", s[1] - if s[1] < len(currentTest): - print "SHRINKING TO IGNORE UNREAD BYTES" - currentTest = currentTest[:s[1]+1] + if s[1] < len(currentTest): + print "SHRINKING TO IGNORE UNREAD BYTES" + currentTest = currentTest[:s[1]+1] - changed = True - while changed: - changed = False - cuts = s[0] - for c in cuts: - newTest = currentTest[:c[0]] + currentTest[c[1]+1:] - with open(".candidate.test", 'wb') as outf: - outf.write(newTest) - r = runCandidate(".candidate.test") - if checks(r): - print "ONEOF REMOVAL REDUCED TEST TO", len(newTest), "BYTES" - s = structure(r) - changed = True - currentTest = newTest - break - if changed: - continue - for b in range(0, len(currentTest)): - for v in range(b+1, len(currentTest)): - newTest = currentTest[:b] + currentTest[v:] - with open(".candidate.test", 'wb') as outf: - outf.write(newTest) - r = runCandidate(".candidate.test") - if checks(r): - print "BYTE RANGE REMOVAL REDUCED TEST TO", len(newTest), "BYTES" - s = structure(r) - changed = True - currentTest = newTest - break - if changed: - continue - for b in range(0, len(currentTest)): - for v in range(0, currentTest[b]): - newTest = bytearray(currentTest) - newTest[b] = v - with open(".candidate.test", 'wb') as outf: - outf.write(newTest) - r = runCandidate(".candidate.test") - if checks(r): - print "BYTE REDUCTION: BYTE", b, "FROM", currentTest[b], "TO", v - s = structure(r) - changed = True - currentTest = newTest - break - for b in range(0, len(currentTest)): - if currentTest[b] == 0: - continue - newTest = bytearray(currentTest) - newTest[b] = currentTest[b]-1 - newTest = newTest[:b+1] + newTest[b+2:] - with open(".candidate.test", 'wb') as outf: - outf.write(newTest) - r = runCandidate(".candidate.test") - if checks(r): - print "BYTE REDUCE AND DELETE AT BYTE", b - s = structure(r) - changed = True - currentTest = newTest - break + changed = True + while changed: + changed = False + cuts = s[0] + for c in cuts: + newTest = currentTest[:c[0]] + currentTest[c[1]+1:] + with open(".candidate.test", 'wb') as outf: + outf.write(newTest) + r = runCandidate(".candidate.test") + if checks(r): + print "ONEOF REMOVAL REDUCED TEST TO", len(newTest), "BYTES" + s = structure(r) + changed = True + currentTest = newTest + break + if changed: + continue + for b in range(0, len(currentTest)): + for v in range(b+1, len(currentTest)): + newTest = currentTest[:b] + currentTest[v:] + with open(".candidate.test", 'wb') as outf: + outf.write(newTest) + r = runCandidate(".candidate.test") + if checks(r): + print "BYTE RANGE REMOVAL REDUCED TEST TO", len(newTest), "BYTES" + s = structure(r) + changed = True + currentTest = newTest + break + if changed: + continue + for b in range(0, len(currentTest)): + for v in range(0, currentTest[b]): + newTest = bytearray(currentTest) + newTest[b] = v + with open(".candidate.test", 'wb') as outf: + outf.write(newTest) + r = runCandidate(".candidate.test") + if checks(r): + print "BYTE REDUCTION: BYTE", b, "FROM", currentTest[b], "TO", v + s = structure(r) + changed = True + currentTest = newTest + break + for b in range(0, len(currentTest)): + if currentTest[b] == 0: + continue + newTest = bytearray(currentTest) + newTest[b] = currentTest[b]-1 + newTest = newTest[:b+1] + newTest[b+2:] + with open(".candidate.test", 'wb') as outf: + outf.write(newTest) + r = runCandidate(".candidate.test") + if checks(r): + print "BYTE REDUCE AND DELETE AT BYTE", b + s = structure(r) + changed = True + currentTest = newTest + break - print "NO REDUCTIONS FOUND" + print "NO REDUCTIONS FOUND" - if (s[1] + 1) > len(currentTest): - print "PADDING TEST WITH", (s[1] + 1) - len(currentTest), "ZEROS" - padding = bytearray('\x00' * ((s[1] + 1) - len(currentTest))) - currentTest = currentTest + padding + if (s[1] + 1) > len(currentTest): + print "PADDING TEST WITH", (s[1] + 1) - len(currentTest), "ZEROS" + padding = bytearray('\x00' * ((s[1] + 1) - len(currentTest))) + currentTest = currentTest + padding + + print + print "WRITING REDUCED TEST TO", out - print - print "WRITING REDUCED TEST TO", out - - with open(out, 'wb') as outf: - outf.write(currentTest) + with open(out, 'wb') as outf: + outf.write(currentTest) - return 0 + return 0 if "__main__" == __name__: exit(main()) From cc8acc2b92bcdacc5c7b8ea7a91092034f5e8f51 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 3 Sep 2018 10:59:16 -0700 Subject: [PATCH 032/228] fix output --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index f6b323c..389553f 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,8 @@ deepstate-reduce ./TestFileSystem rmdirfail.test minrmdirfail.test --criteria "F ``` The output will look something like: -```shell + +``` ORIGINAL TEST HAS 119 BYTES LAST BYTE READ IS 123 ONEOF REMOVAL REDUCED TEST TO 103 BYTES From 5a7e6ad76bdd3caa6efeaa226bf3f8324d44b007 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 3 Sep 2018 13:05:20 -0700 Subject: [PATCH 033/228] get ready for python 3, refactor code to be easier to follow/change --- bin/deepstate/reducer.py | 116 +++++++++++++++++++-------------------- 1 file changed, 58 insertions(+), 58 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 1821175..12a4927 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -13,6 +13,7 @@ # See the License for the specific language governing permissions and # limitations under the License. +from __future__ import print_function import argparse import subprocess @@ -68,6 +69,12 @@ def main(): return True return False + def writeAndRunCandidate(test): + with open(".candidate.test", 'wb') as outf: + outf.write(test) + r = runCandidate(".candidate.test") + return r + def structure(result): OneOfs = [] currentOneOf = [] @@ -85,90 +92,83 @@ def main(): initial = runCandidate(test) if not checks(initial): - print "STARTING TEST DOES NOT SATISFY REDUCTION CRITERIA" + print("STARTING TEST DOES NOT SATISFY REDUCTION CRITERIA") return 1 with open(test, 'rb') as test: currentTest = bytearray(test.read()) - print "ORIGINAL TEST HAS", len(currentTest), "BYTES" + print("ORIGINAL TEST HAS", len(currentTest), "BYTES") s = structure(initial) - print "LAST BYTE READ IS", s[1] + print("LAST BYTE READ IS", s[1]) if s[1] < len(currentTest): - print "SHRINKING TO IGNORE UNREAD BYTES" + print("SHRINKING TO IGNORE UNREAD BYTES") currentTest = currentTest[:s[1]+1] changed = True while changed: changed = False + cuts = s[0] for c in cuts: newTest = currentTest[:c[0]] + currentTest[c[1]+1:] - with open(".candidate.test", 'wb') as outf: - outf.write(newTest) - r = runCandidate(".candidate.test") + r = writeAndRunCandidate(".candidate.test") if checks(r): - print "ONEOF REMOVAL REDUCED TEST TO", len(newTest), "BYTES" - s = structure(r) + print("ONEOF REMOVAL REDUCED TEST TO", len(newTest), "BYTES") changed = True - currentTest = newTest - break - if changed: - continue - for b in range(0, len(currentTest)): - for v in range(b+1, len(currentTest)): - newTest = currentTest[:b] + currentTest[v:] - with open(".candidate.test", 'wb') as outf: - outf.write(newTest) - r = runCandidate(".candidate.test") - if checks(r): - print "BYTE RANGE REMOVAL REDUCED TEST TO", len(newTest), "BYTES" - s = structure(r) - changed = True - currentTest = newTest - break - if changed: - continue - for b in range(0, len(currentTest)): - for v in range(0, currentTest[b]): - newTest = bytearray(currentTest) - newTest[b] = v - with open(".candidate.test", 'wb') as outf: - outf.write(newTest) - r = runCandidate(".candidate.test") - if checks(r): - print "BYTE REDUCTION: BYTE", b, "FROM", currentTest[b], "TO", v - s = structure(r) - changed = True - currentTest = newTest - break - for b in range(0, len(currentTest)): - if currentTest[b] == 0: - continue - newTest = bytearray(currentTest) - newTest[b] = currentTest[b]-1 - newTest = newTest[:b+1] + newTest[b+2:] - with open(".candidate.test", 'wb') as outf: - outf.write(newTest) - r = runCandidate(".candidate.test") - if checks(r): - print "BYTE REDUCE AND DELETE AT BYTE", b - s = structure(r) - changed = True - currentTest = newTest break - print "NO REDUCTIONS FOUND" + if not changed: + for b in range(0, len(currentTest)): + for v in range(b+1, len(currentTest)): + newTest = currentTest[:b] + currentTest[v:] + r = writeAndRunCandidate(".candidate.test") + if checks(r): + print("BYTE RANGE REMOVAL REDUCED TEST TO", len(newTest), "BYTES") + changed = True + break + + if not changed: + for b in range(0, len(currentTest)): + for v in range(0, currentTest[b]): + newTest = bytearray(currentTest) + newTest[b] = v + r = writeAndRunCandidate(newTest) + if checks(r): + print("BYTE REDUCTION: BYTE", b, "FROM", currentTest[b], "TO", v) + changed = True + break + if changed: + break + + if not changed: + for b in range(0, len(currentTest)): + if currentTest[b] == 0: + continue + newTest = bytearray(currentTest) + newTest[b] = currentTest[b]-1 + newTest = newTest[:b+1] + newTest[b+2:] + r = writeAndRunCandidate(newTest) + if checks(r): + print("BYTE REDUCE AND DELETE AT BYTE", b) + changed = True + break + + if changed: + currentTest = newTest + s = structure(r) + + print("NO REDUCTIONS FOUND") if (s[1] + 1) > len(currentTest): - print "PADDING TEST WITH", (s[1] + 1) - len(currentTest), "ZEROS" + print("PADDING TEST WITH", (s[1] + 1) - len(currentTest), "ZEROS") padding = bytearray('\x00' * ((s[1] + 1) - len(currentTest))) currentTest = currentTest + padding - print - print "WRITING REDUCED TEST TO", out + print() + print("WRITING REDUCED TEST WITH", len(currentTest), "BYTES TO", out) with open(out, 'wb') as outf: outf.write(currentTest) From 6f3a4a9bdd829946ac6144032d877b0a881f7ab4 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 3 Sep 2018 13:09:06 -0700 Subject: [PATCH 034/228] handle shrinking correctly --- bin/deepstate/reducer.py | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 12a4927..0d21940 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -101,9 +101,8 @@ def main(): print("ORIGINAL TEST HAS", len(currentTest), "BYTES") s = structure(initial) - print("LAST BYTE READ IS", s[1]) - - if s[1] < len(currentTest): + if (s[1]+1) < len(currentTest): + print("LAST BYTE READ IS", s[1]) print("SHRINKING TO IGNORE UNREAD BYTES") currentTest = currentTest[:s[1]+1] From 5961ce366c98885ed603815bd4a83b4fae872f6a Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 3 Sep 2018 13:17:40 -0700 Subject: [PATCH 035/228] fix bug introduced in refactor --- bin/deepstate/reducer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 0d21940..baea53b 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -113,7 +113,7 @@ def main(): cuts = s[0] for c in cuts: newTest = currentTest[:c[0]] + currentTest[c[1]+1:] - r = writeAndRunCandidate(".candidate.test") + r = writeAndRunCandidate(newTest) if checks(r): print("ONEOF REMOVAL REDUCED TEST TO", len(newTest), "BYTES") changed = True @@ -123,7 +123,7 @@ def main(): for b in range(0, len(currentTest)): for v in range(b+1, len(currentTest)): newTest = currentTest[:b] + currentTest[v:] - r = writeAndRunCandidate(".candidate.test") + r = writeAndRunCandidate(newTest) if checks(r): print("BYTE RANGE REMOVAL REDUCED TEST TO", len(newTest), "BYTES") changed = True From cd34e03d5b82cec7b6bbc374bb94707cdaf83fed Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 3 Sep 2018 13:20:09 -0700 Subject: [PATCH 036/228] add break --- bin/deepstate/reducer.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index baea53b..383bda7 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -128,6 +128,8 @@ def main(): print("BYTE RANGE REMOVAL REDUCED TEST TO", len(newTest), "BYTES") changed = True break + if changed: + break if not changed: for b in range(0, len(currentTest)): From 4c16c7d61f6a3c3caae6e5461022df49014622f5 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 3 Sep 2018 13:29:42 -0700 Subject: [PATCH 037/228] allow searching for a satisfying test --- bin/deepstate/reducer.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 383bda7..9addf9b 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -36,6 +36,10 @@ def main(): "--criteria", type=str, help="String to search for in valid reduction outputs.", default=None) + parser.add_argument( + "--search", action="store_true", help="Allow initial test to not satisfy criteria (search for test).", + default=None) + args = parser.parse_args() deepstate = args.binary @@ -91,7 +95,7 @@ def main(): return (OneOfs, lastRead) initial = runCandidate(test) - if not checks(initial): + if (not args.search) and (not checks(initial)): print("STARTING TEST DOES NOT SATISFY REDUCTION CRITERIA") return 1 From 913a2c2d12212ffdb65d62b4938f7ed07602fb29 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 3 Sep 2018 13:42:18 -0700 Subject: [PATCH 038/228] match output --- README.md | 26 +++++++++++--------------- 1 file changed, 11 insertions(+), 15 deletions(-) diff --git a/README.md b/README.md index 389553f..efaf3e7 100644 --- a/README.md +++ b/README.md @@ -174,26 +174,22 @@ The output will look something like: ``` ORIGINAL TEST HAS 119 BYTES -LAST BYTE READ IS 123 ONEOF REMOVAL REDUCED TEST TO 103 BYTES -BYTE REDUCTION: BYTE 3 FROM 4 TO 0 -BYTE REDUCTION: BYTE 7 FROM 2 TO 1 -BYTE REDUCTION: BYTE 15 FROM 3 TO 2 -BYTE REDUCTION: BYTE 19 FROM 4 TO 0 -BYTE REDUCTION: BYTE 55 FROM 3 TO 1 -BYTE REDUCTION: BYTE 59 FROM 2 TO 0 -BYTE REDUCTION: BYTE 75 FROM 2 TO 0 -BYTE REDUCTION: BYTE 79 FROM 4 TO 0 -ONEOF REMOVAL REDUCED TEST TO 91 BYTES -BYTE REDUCTION: BYTE 59 FROM 4 TO 0 ONEOF REMOVAL REDUCED TEST TO 87 BYTES -ONEOF REMOVAL REDUCED TEST TO 75 BYTES -ONEOF REMOVAL REDUCED TEST TO 55 BYTES +ONEOF REMOVAL REDUCED TEST TO 67 BYTES ONEOF REMOVAL REDUCED TEST TO 51 BYTES +BYTE RANGE REMOVAL REDUCED TEST TO 50 BYTES +BYTE RANGE REMOVAL REDUCED TEST TO 49 BYTES +BYTE REDUCTION: BYTE 3 FROM 4 TO 0 +BYTE REDUCTION: BYTE 43 FROM 4 TO 0 +ONEOF REMOVAL REDUCED TEST TO 33 BYTES +ONEOF REMOVAL REDUCED TEST TO 17 BYTES +BYTE REDUCTION: BYTE 7 FROM 2 TO 1 +BYTE REDUCTION: BYTE 15 FROM 2 TO 1 NO REDUCTIONS FOUND -PADDING TEST WITH 5 ZEROS +PADDING TEST WITH 3 ZEROS -WRITING REDUCED TEST TO minrmdirfail.test +WRITING REDUCED TEST WITH 20 BYTES TO minrmdirfail.test ``` You can use `--which_test ` to specify which test to From 304f334a63cacd52a4693b4327c672b3eb730000 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 3 Sep 2018 20:09:25 -0700 Subject: [PATCH 039/228] note replay and minimization in features --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index efaf3e7..37f4718 100644 --- a/README.md +++ b/README.md @@ -18,6 +18,7 @@ The [2018 IEEE Cybersecurity Development Conference](https://secdev.ieee.org/201 * Find out which tool works best for your code under test * Different tools find different bugs/vulnerabilities * Fair way to benchmark/bakeoff tools +* Provides test replay for regression and effective automatic test case minimization * Supports API-sequence generation with extensions to Google Test interface * Concise readable way (OneOf) to say "run one of these blocks of code" * Same construct supports fixed value set non-determinism From 86a157c3925bd5c602fd8f2be83cea7db949f87f Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 3 Sep 2018 20:17:16 -0700 Subject: [PATCH 040/228] Change wording --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 37f4718..83d73fa 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ The [2018 IEEE Cybersecurity Development Conference](https://secdev.ieee.org/201 * Find out which tool works best for your code under test * Different tools find different bugs/vulnerabilities * Fair way to benchmark/bakeoff tools -* Provides test replay for regression and effective automatic test case minimization +* Provides test replay for regression plus effective automatic test case reduction to aid debugging * Supports API-sequence generation with extensions to Google Test interface * Concise readable way (OneOf) to say "run one of these blocks of code" * Same construct supports fixed value set non-determinism From d412dff96595863628ff6a08af97c6a09449b3f7 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 12:27:15 -0700 Subject: [PATCH 041/228] just see if bytes match --- bin/deepstate/reducer.py | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 9addf9b..9a6fc0a 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -40,6 +40,10 @@ def main(): "--search", action="store_true", help="Allow initial test to not satisfy criteria (search for test).", default=None) + parser.add_argument( + "--matches", action="store_true", help="Try reducing matching 2-byte patterns together.", + default=None) + args = parser.parse_args() deepstate = args.binary @@ -161,6 +165,14 @@ def main(): changed = True break + if args.matches and (not changed): + for b1 in range(0, len(currentTest)-4): + for b2 = range(b1+2, len(currentTest)-4): + v1 = (currentTest[b1], currentTest[b1+1]) + v2 = (currentTest[b2], currentTest[b2+1]) + if v1 == v2: + print("BYTE SEQUENCE MATCH AT", b1, b2) + if changed: currentTest = newTest s = structure(r) From c00c11f5f24a52923c3ec5ab14e319d198da6c95 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 12:34:54 -0700 Subject: [PATCH 042/228] fix for loop --- bin/deepstate/reducer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 9a6fc0a..010e330 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -167,7 +167,7 @@ def main(): if args.matches and (not changed): for b1 in range(0, len(currentTest)-4): - for b2 = range(b1+2, len(currentTest)-4): + for b2 in range(b1+2, len(currentTest)-4): v1 = (currentTest[b1], currentTest[b1+1]) v2 = (currentTest[b2], currentTest[b2+1]) if v1 == v2: From 3978ea0fe9f5134c98badaa22b27df5e200ea1ee Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 12:41:59 -0700 Subject: [PATCH 043/228] print actual values --- bin/deepstate/reducer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 010e330..b32059a 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -171,7 +171,7 @@ def main(): v1 = (currentTest[b1], currentTest[b1+1]) v2 = (currentTest[b2], currentTest[b2+1]) if v1 == v2: - print("BYTE SEQUENCE MATCH AT", b1, b2) + print("BYTE SEQUENCE MATCH AT", b1, b2, v1) if changed: currentTest = newTest From a2926c0aea66449b6e5f62808bda4d13330110fa Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 12:55:04 -0700 Subject: [PATCH 044/228] ignore double zeros --- bin/deepstate/reducer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index b32059a..31de9f1 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -170,7 +170,7 @@ def main(): for b2 in range(b1+2, len(currentTest)-4): v1 = (currentTest[b1], currentTest[b1+1]) v2 = (currentTest[b2], currentTest[b2+1]) - if v1 == v2: + if (v1 == v2) and (v1 != (0,0)): print("BYTE SEQUENCE MATCH AT", b1, b2, v1) if changed: From 3d560daaf41e004c6947915bc3e8560ddfe5d2fc Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 13:22:56 -0700 Subject: [PATCH 045/228] try actual reduction --- bin/deepstate/reducer.py | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 31de9f1..57a5eb7 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -170,8 +170,28 @@ def main(): for b2 in range(b1+2, len(currentTest)-4): v1 = (currentTest[b1], currentTest[b1+1]) v2 = (currentTest[b2], currentTest[b2+1]) - if (v1 == v2) and (v1 != (0,0)): - print("BYTE SEQUENCE MATCH AT", b1, b2, v1) + if (v1 == v2): + ba = bytearray(v1) + print("BYTE SEQUENCE MATCH AT", b1, b2, ba) + part1 = currentTest[:b1] + part2 = currentTest[b1+2:b2] + part3 = currentTest[b2+2:] + banews = [] + banews.append(ba[0:1]) + banews.append(ba[1:2]) + if ba[0] > 0: + banews.append(bytearray[ba[0]-1]) + for banew in banews: + newTest = part1 + banew + part2 + banew + part3 + r = writeAndRunCandidate(newTest) + if checks(r): + print("BYTE PATTERN", ba, "AT", b1, "AND", b2, "CHANGED TO", banew) + changed = True + break + if changed: + break + if changed: + break if changed: currentTest = newTest From 845f237d37e098656f8ecc97bc77d565441d27bf Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 13:23:10 -0700 Subject: [PATCH 046/228] try actual reduction --- bin/deepstate/reducer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 57a5eb7..267263d 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -172,7 +172,6 @@ def main(): v2 = (currentTest[b2], currentTest[b2+1]) if (v1 == v2): ba = bytearray(v1) - print("BYTE SEQUENCE MATCH AT", b1, b2, ba) part1 = currentTest[:b1] part2 = currentTest[b1+2:b2] part3 = currentTest[b2+2:] From 6c613126c1333db64dc1288add0cd0a20fd5ea0e Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 13:27:01 -0700 Subject: [PATCH 047/228] fix convert to bytearray --- bin/deepstate/reducer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 267263d..73a07e3 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -179,7 +179,7 @@ def main(): banews.append(ba[0:1]) banews.append(ba[1:2]) if ba[0] > 0: - banews.append(bytearray[ba[0]-1]) + banews.append(bytearray([ba[0]-1])) for banew in banews: newTest = part1 + banew + part2 + banew + part3 r = writeAndRunCandidate(newTest) From 47f29219dd79876bc6f95ea5e785478780ac1410 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 13:33:58 -0700 Subject: [PATCH 048/228] verbose --- bin/deepstate/reducer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 73a07e3..bd60c56 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -182,6 +182,7 @@ def main(): banews.append(bytearray([ba[0]-1])) for banew in banews: newTest = part1 + banew + part2 + banew + part3 + print(len(newTest),len(currentTest)) r = writeAndRunCandidate(newTest) if checks(r): print("BYTE PATTERN", ba, "AT", b1, "AND", b2, "CHANGED TO", banew) From 83cdc2f070d76ef43a57456194df7996eae9b27a Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 13:39:23 -0700 Subject: [PATCH 049/228] less verbose --- bin/deepstate/reducer.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index bd60c56..73a07e3 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -182,7 +182,6 @@ def main(): banews.append(bytearray([ba[0]-1])) for banew in banews: newTest = part1 + banew + part2 + banew + part3 - print(len(newTest),len(currentTest)) r = writeAndRunCandidate(newTest) if checks(r): print("BYTE PATTERN", ba, "AT", b1, "AND", b2, "CHANGED TO", banew) From 3e521bcb489eff633f2f07cae777b0b656a33c3c Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 13:49:14 -0700 Subject: [PATCH 050/228] verbose --- bin/deepstate/reducer.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 73a07e3..1443d85 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -181,6 +181,7 @@ def main(): if ba[0] > 0: banews.append(bytearray([ba[0]-1])) for banew in banews: + print(b1, b2, ba, " --> ", banew) newTest = part1 + banew + part2 + banew + part3 r = writeAndRunCandidate(newTest) if checks(r): From fc57ba16283b8ada95d0f7667cc17ab0ac3057a8 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 13:59:16 -0700 Subject: [PATCH 051/228] change output --- bin/deepstate/reducer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 1443d85..cfc53ad 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -181,7 +181,7 @@ def main(): if ba[0] > 0: banews.append(bytearray([ba[0]-1])) for banew in banews: - print(b1, b2, ba, " --> ", banew) + print(b1, b2, repr(ba), " TO ", repr(banew)) newTest = part1 + banew + part2 + banew + part3 r = writeAndRunCandidate(newTest) if checks(r): From 44074cfd498ba083234b69c90195c76dcc5d602b Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 14:08:35 -0700 Subject: [PATCH 052/228] try byte reductions --- bin/deepstate/reducer.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index cfc53ad..e64abc8 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -179,9 +179,11 @@ def main(): banews.append(ba[0:1]) banews.append(ba[1:2]) if ba[0] > 0: + banews.append(bytearray([ba[0]-1, ba[1]])) banews.append(bytearray([ba[0]-1])) + if ba[1] > 0: + banews.append(bytearray([ba[0], ba[1]-1])) for banew in banews: - print(b1, b2, repr(ba), " TO ", repr(banew)) newTest = part1 + banew + part2 + banew + part3 r = writeAndRunCandidate(newTest) if checks(r): From edbc055b4be8c04229aab9867fa2280bc8a2f1b1 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 14:09:16 -0700 Subject: [PATCH 053/228] nicer output --- bin/deepstate/reducer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index e64abc8..cf267ac 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -187,7 +187,7 @@ def main(): newTest = part1 + banew + part2 + banew + part3 r = writeAndRunCandidate(newTest) if checks(r): - print("BYTE PATTERN", ba, "AT", b1, "AND", b2, "CHANGED TO", banew) + print("BYTE PATTERN", tuple(ba), "AT", b1, "AND", b2, "CHANGED TO", tuple(banew)) changed = True break if changed: From 03c47607cf0e31859f18516fa53adae0371a9a2f Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 18:49:38 -0700 Subject: [PATCH 054/228] timeout instead of control over which to run --- bin/deepstate/reducer.py | 169 +++++++++++++++++++++------------------ 1 file changed, 90 insertions(+), 79 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index cf267ac..c407e25 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -16,6 +16,7 @@ from __future__ import print_function import argparse import subprocess +import time def main(): parser = argparse.ArgumentParser(description="Intelligently reduce test case") @@ -41,8 +42,11 @@ def main(): default=None) parser.add_argument( - "--matches", action="store_true", help="Try reducing matching 2-byte patterns together.", - default=None) + "--timeout", type=int, help="After this amount of time (in seconds), give up on reduction.", + default=1200) + + class TimeoutException(Exception): + pass args = parser.parse_args() @@ -53,6 +57,8 @@ def main(): whichTest = args.which_test def runCandidate(candidate): + if (time.time() - start) > args.timeout: + raise TimeoutException with open(".reducer.out", 'w') as outf: cmd = [deepstate + " --input_test_file " + candidate + " --verbose_reads"] @@ -114,92 +120,97 @@ def main(): print("SHRINKING TO IGNORE UNREAD BYTES") currentTest = currentTest[:s[1]+1] + start = time.time() + changed = True - while changed: - changed = False + try: + while changed: + changed = False - cuts = s[0] - for c in cuts: - newTest = currentTest[:c[0]] + currentTest[c[1]+1:] - r = writeAndRunCandidate(newTest) - if checks(r): - print("ONEOF REMOVAL REDUCED TEST TO", len(newTest), "BYTES") - changed = True - break - - if not changed: - for b in range(0, len(currentTest)): - for v in range(b+1, len(currentTest)): - newTest = currentTest[:b] + currentTest[v:] - r = writeAndRunCandidate(newTest) - if checks(r): - print("BYTE RANGE REMOVAL REDUCED TEST TO", len(newTest), "BYTES") - changed = True - break - if changed: - break - - if not changed: - for b in range(0, len(currentTest)): - for v in range(0, currentTest[b]): - newTest = bytearray(currentTest) - newTest[b] = v - r = writeAndRunCandidate(newTest) - if checks(r): - print("BYTE REDUCTION: BYTE", b, "FROM", currentTest[b], "TO", v) - changed = True - break - if changed: - break - - if not changed: - for b in range(0, len(currentTest)): - if currentTest[b] == 0: - continue - newTest = bytearray(currentTest) - newTest[b] = currentTest[b]-1 - newTest = newTest[:b+1] + newTest[b+2:] - r = writeAndRunCandidate(newTest) + cuts = s[0] + for c in cuts: + newTest = currentTest[:c[0]] + currentTest[c[1]+1:] + r = writeAndRunCandidate(newTest) if checks(r): - print("BYTE REDUCE AND DELETE AT BYTE", b) + print("ONEOF REMOVAL REDUCED TEST TO", len(newTest), "BYTES") changed = True break - if args.matches and (not changed): - for b1 in range(0, len(currentTest)-4): - for b2 in range(b1+2, len(currentTest)-4): - v1 = (currentTest[b1], currentTest[b1+1]) - v2 = (currentTest[b2], currentTest[b2+1]) - if (v1 == v2): - ba = bytearray(v1) - part1 = currentTest[:b1] - part2 = currentTest[b1+2:b2] - part3 = currentTest[b2+2:] - banews = [] - banews.append(ba[0:1]) - banews.append(ba[1:2]) - if ba[0] > 0: - banews.append(bytearray([ba[0]-1, ba[1]])) - banews.append(bytearray([ba[0]-1])) - if ba[1] > 0: - banews.append(bytearray([ba[0], ba[1]-1])) - for banew in banews: - newTest = part1 + banew + part2 + banew + part3 - r = writeAndRunCandidate(newTest) - if checks(r): - print("BYTE PATTERN", tuple(ba), "AT", b1, "AND", b2, "CHANGED TO", tuple(banew)) - changed = True - break - if changed: + if not changed: + for b in range(0, len(currentTest)): + for v in range(b+1, len(currentTest)): + newTest = currentTest[:b] + currentTest[v:] + r = writeAndRunCandidate(newTest) + if checks(r): + print("BYTE RANGE REMOVAL REDUCED TEST TO", len(newTest), "BYTES") + changed = True break - if changed: - break + if changed: + break - if changed: - currentTest = newTest - s = structure(r) + if not changed: + for b in range(0, len(currentTest)): + for v in range(0, currentTest[b]): + newTest = bytearray(currentTest) + newTest[b] = v + r = writeAndRunCandidate(newTest) + if checks(r): + print("BYTE REDUCTION: BYTE", b, "FROM", currentTest[b], "TO", v) + changed = True + break + if changed: + break - print("NO REDUCTIONS FOUND") + if not changed: + for b in range(0, len(currentTest)): + if currentTest[b] == 0: + continue + newTest = bytearray(currentTest) + newTest[b] = currentTest[b]-1 + newTest = newTest[:b+1] + newTest[b+2:] + r = writeAndRunCandidate(newTest) + if checks(r): + print("BYTE REDUCE AND DELETE AT BYTE", b) + changed = True + break + + if not changed: + for b1 in range(0, len(currentTest)-4): + for b2 in range(b1+2, len(currentTest)-4): + v1 = (currentTest[b1], currentTest[b1+1]) + v2 = (currentTest[b2], currentTest[b2+1]) + if (v1 == v2): + ba = bytearray(v1) + part1 = currentTest[:b1] + part2 = currentTest[b1+2:b2] + part3 = currentTest[b2+2:] + banews = [] + banews.append(ba[0:1]) + banews.append(ba[1:2]) + if ba[0] > 0: + banews.append(bytearray([ba[0]-1, ba[1]])) + banews.append(bytearray([ba[0]-1])) + if ba[1] > 0: + banews.append(bytearray([ba[0], ba[1]-1])) + for banew in banews: + newTest = part1 + banew + part2 + banew + part3 + r = writeAndRunCandidate(newTest) + if checks(r): + print("BYTE PATTERN", tuple(ba), "AT", b1, "AND", b2, "CHANGED TO", tuple(banew)) + changed = True + break + if changed: + break + if changed: + break + + if changed: + currentTest = newTest + s = structure(r) + else: + print("NO (MORE) REDUCTIONS FOUND") + except TimeoutException: + print("REDUCTION TIMED OUT AFTER", args.timeout, "SECONDS") if (s[1] + 1) > len(currentTest): print("PADDING TEST WITH", (s[1] + 1) - len(currentTest), "ZEROS") From bb1ca0f8c06c40d4f29ba606ea0fd8c7326e50ee Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Sep 2018 18:51:51 -0700 Subject: [PATCH 055/228] move start time --- bin/deepstate/reducer.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index c407e25..77880bf 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -56,6 +56,8 @@ def main(): checkString = args.criteria whichTest = args.which_test + start = time.time() + def runCandidate(candidate): if (time.time() - start) > args.timeout: raise TimeoutException @@ -120,8 +122,6 @@ def main(): print("SHRINKING TO IGNORE UNREAD BYTES") currentTest = currentTest[:s[1]+1] - start = time.time() - changed = True try: while changed: From 819e89df5fe6ab634ec0e052d9871cf26c78a50e Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 6 Sep 2018 11:11:15 -0700 Subject: [PATCH 056/228] more consistent aggressive byte reduction --- bin/deepstate/reducer.py | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 77880bf..c7fb97b 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -188,10 +188,12 @@ def main(): banews.append(ba[0:1]) banews.append(ba[1:2]) if ba[0] > 0: - banews.append(bytearray([ba[0]-1, ba[1]])) + for v in range(0, ba[0]): + banews.append(bytearray([v, ba[1]])) banews.append(bytearray([ba[0]-1])) if ba[1] > 0: - banews.append(bytearray([ba[0], ba[1]-1])) + for v in range(0, ba[1]): + banews.append(bytearray([ba[0], v)) for banew in banews: newTest = part1 + banew + part2 + banew + part3 r = writeAndRunCandidate(newTest) From 6d2a06d9a0c005244c06c78812436b1aaef39331 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 6 Sep 2018 11:12:15 -0700 Subject: [PATCH 057/228] fix parenthesis issue --- bin/deepstate/reducer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index c7fb97b..fae6299 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -193,7 +193,7 @@ def main(): banews.append(bytearray([ba[0]-1])) if ba[1] > 0: for v in range(0, ba[1]): - banews.append(bytearray([ba[0], v)) + banews.append(bytearray([ba[0], v])) for banew in banews: newTest = part1 + banew + part2 + banew + part3 r = writeAndRunCandidate(newTest) From 293ac413bebd0e0f3ad105ac33b1242254f37fbd Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 8 Sep 2018 09:56:39 -0700 Subject: [PATCH 058/228] Point to testfs example in README --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 83d73fa..2d38959 100644 --- a/README.md +++ b/README.md @@ -111,7 +111,7 @@ argument to see all DeepState options. ## Usage -DeepState consists of a static library, used to write test harnesses, and command-line _executors_ written in Python. At this time, the best documentation is in the [examples](/examples) and in our [paper](https://agroce.github.io/bar18.pdf). +DeepState consists of a static library, used to write test harnesses, and command-line _executors_ written in Python. At this time, the best documentation is in the [examples](/examples) and in our [paper](https://agroce.github.io/bar18.pdf). A more extensive example, using DeepState and libFuzzer to test a user-mode file system, is available [here](https://github.com/agroce/testfs); in particular the [Tests.cpp](https://github.com/agroce/testfs/blob/master/Tests.cpp) file and CMakeLists.txt show DeepState usage. ## Fuzzing with libFuzzer From 4c7673560e034874903c6431981a9be29bf633ed Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 17 Sep 2018 13:27:56 -0700 Subject: [PATCH 059/228] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2d38959..70b5dca 100644 --- a/README.md +++ b/README.md @@ -161,7 +161,7 @@ deepstate-reduce ./TestFileSystem rmdirfail.test minrmdirfail.test ``` In many cases, this will result in finding a different failure or -crash that allow smaller test cases, so you can also provide a string +crash that allows smaller test cases, so you can also provide a string that controls the criteria for which test outputs are considered valid reductions (by default, the reducer looks for any test that fails or crashes). Only outputs containing the `--criteria` are considered to From a8b914b35f68baea87eb8d1dd70c3a0f768d0b4f Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Mon, 24 Sep 2018 13:54:33 -0300 Subject: [PATCH 060/228] Reliable SIGSEGV in clang 6.0 This will also fix #95 --- examples/Crash.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Crash.cpp b/examples/Crash.cpp index 7aa1fc5..45e6983 100644 --- a/examples/Crash.cpp +++ b/examples/Crash.cpp @@ -22,7 +22,7 @@ using namespace deepstate; DEEPSTATE_NOINLINE static unsigned segfault(unsigned x) { if (x == 0x1234) { // Magic number for engine to discover unsigned *p = NULL; - *p = 0xdeadbeef; // Trigger segfault here + *(p+1) = 0xdeadbeef; // Trigger segfault here } return x; From 9a8e5cca2391de2b20c4c1ca617381d7bfaa9570 Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Wed, 26 Sep 2018 11:44:04 -0700 Subject: [PATCH 061/228] Disable static builds on macOS --- CMakeLists.txt | 7 ++++--- examples/CMakeLists.txt | 9 +++++---- src/include/deepstate/Klee.h | 9 +++++++-- 3 files changed, 16 insertions(+), 9 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index d84ed65..c50e85a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -65,9 +65,10 @@ target_compile_options(${PROJECT_NAME} PUBLIC -mno-avx) target_compile_options(${PROJECT_NAME}32 PUBLIC -m32 -g3 -mno-avx) -target_link_libraries(${PROJECT_NAME} -static "-Wl,--allow-multiple-definition,--no-export-dynamic") - -target_link_libraries(${PROJECT_NAME}32 -static "-Wl,--allow-multiple-definition,--no-export-dynamic") +if (NOT APPLE) + target_link_libraries(${PROJECT_NAME} -static "-Wl,--allow-multiple-definition,--no-export-dynamic") + target_link_libraries(${PROJECT_NAME}32 -static "-Wl,--allow-multiple-definition,--no-export-dynamic") +endif() target_include_directories(${PROJECT_NAME} PUBLIC SYSTEM "${CMAKE_SOURCE_DIR}/src/include" diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index 062cab4..f8e7a21 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -12,7 +12,6 @@ # See the License for the specific language governing permissions and # limitations under the License. - add_executable(Crash Crash.cpp) target_link_libraries(Crash deepstate) @@ -103,9 +102,11 @@ if (BUILD_LIBFUZZER) set_target_properties(StreamingAndFormatting_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() -add_executable(Squares Squares.c) -target_link_libraries(Squares deepstate) -set_target_properties(Squares PROPERTIES COMPILE_DEFINITIONS "DEEPSTATE_TEST") +if (NOT APPLE) + add_executable(Squares Squares.c) + target_link_libraries(Squares deepstate) + set_target_properties(Squares PROPERTIES COMPILE_DEFINITIONS "DEEPSTATE_TEST") +endif() add_executable(TakeOver TakeOver.cpp) target_link_libraries(TakeOver deepstate) diff --git a/src/include/deepstate/Klee.h b/src/include/deepstate/Klee.h index 2c8a4c5..c91f16b 100644 --- a/src/include/deepstate/Klee.h +++ b/src/include/deepstate/Klee.h @@ -97,7 +97,12 @@ static void klee_posix_prefer_cex(void *object, uintptr_t condition) { /* static KLEE_GET_VALUE(d, double); */ static KLEE_GET_VALUE(l, long) { - DeepState_MinInt(val); + if (sizeof(long) == sizeof(int)) { + return DeepState_MinInt((int) val); + } else { + // TODO: We need a MinInt64 function. + return DeepState_MinInt(val); + } } /* Unsupported. */ @@ -105,7 +110,7 @@ static KLEE_GET_VALUE(l, long) { /* TODO(joe): Implement */ static KLEE_GET_VALUE(_i32, int32_t) { - DeepState_MinInt(val); + return DeepState_MinInt(val); } /* TODO(joe): Implement */ From b1da5d6d487a3209c81ca99c99ac823b44b97937 Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Thu, 27 Sep 2018 16:45:08 -0700 Subject: [PATCH 062/228] Improved the CMakeLists.txt just slightly. Provided a default, weak-attributed main function into libdeepstate so that tests don't need to define them. The weak attribute means that any main function defined by libfuzzer will be a strong symbol and take over, so there won't be a conflict. Adjusted examples accordingly to omit now redundant conditionally-compiled main functions, as that leaked out too many underlying details. --- CMakeLists.txt | 28 ++++++++++++++++++++++------ examples/Crash.cpp | 7 ------- examples/Euler.cpp | 6 ------ examples/Fixture.cpp | 7 ------- examples/IntegerArithmetic.cpp | 7 ------- examples/IntegerOverflow.cpp | 8 +------- examples/Lists.cpp | 7 ------- examples/OneOf.cpp | 7 ------- examples/Primes.cpp | 7 ------- examples/StreamingAndFormatting.cpp | 6 ------ src/lib/DeepState.c | 6 ++++++ src/lib/Log.c | 11 +++++++++++ 12 files changed, 40 insertions(+), 67 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index c50e85a..eb62c96 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,15 +15,31 @@ project(deepstate) cmake_minimum_required(VERSION 2.8) +if (NOT DEFINED BUILD_LIBFUZZER AND DEFINED $ENV{BUILD_LIBFUZZER}) + set(BUILD_LIBFUZZER "$ENV{BUILD_LIBFUZZER}") +endif() + +if (BUILD_LIBFUZZER) + if(NOT DEFINED CMAKE_C_COMPILER) + set(CMAKE_C_COMPILER clang) + endif() + + if(NOT DEFINED CMAKE_CXX_COMPILER) + set(CMAKE_CXX_COMPILER clang++) + endif() + + if (NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "Clang" AND NOT "${CMAKE_C_COMPILER_ID}" STREQUAL "AppleClang") + message(FATAL_ERROR "DeepState's libFuzzer mode requires the Clang C compiler.") + endif() + + if (NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "Clang" AND NOT "${CMAKE_CXX_COMPILER_ID}" STREQUAL "AppleClang") + message(FATAL_ERROR "DeepState's libFuzzer mode requires the Clang C++ compiler.") + endif() +endif() + enable_language(C) enable_language(CXX) -set(BUILD_LIBFUZZER "$ENV{BUILD_LIBFUZZER}") -if (BUILD_LIBFUZZER) - SET(CMAKE_C_COMPILER clang) - SET(CMAKE_CXX_COMPILER clang++) -endif() - set(CMAKE_POSITION_INDEPENDENT_CODE ON) if(NOT CMAKE_BUILD_TYPE) diff --git a/examples/Crash.cpp b/examples/Crash.cpp index 45e6983..88a0d4a 100644 --- a/examples/Crash.cpp +++ b/examples/Crash.cpp @@ -35,10 +35,3 @@ TEST(Crash, SegFault) { ASSERT_EQ(x, x); } - -#ifndef LIBFUZZER -int main(int argc, char *argv[]) { - DeepState_InitOptions(argc, argv); - return DeepState_Run(); -} -#endif diff --git a/examples/Euler.cpp b/examples/Euler.cpp index 8f2dd0d..b7b771a 100644 --- a/examples/Euler.cpp +++ b/examples/Euler.cpp @@ -39,9 +39,3 @@ TEST(Euler, SumsOfLikePowers) { << "^5 + " << d << "^5 = " << e << "^5"; } -#ifndef LIBFUZZER -int main(int argc, char *argv[]) { - DeepState_InitOptions(argc, argv); - return DeepState_Run(); -} -#endif diff --git a/examples/Fixture.cpp b/examples/Fixture.cpp index 2c864c6..ba288b5 100644 --- a/examples/Fixture.cpp +++ b/examples/Fixture.cpp @@ -35,10 +35,3 @@ class MyTest : public deepstate::Test { TEST_F(MyTest, Something) { ASSUME_NE(x, 0); } - -#ifndef LIBFUZZER -int main(int argc, char *argv[]) { - DeepState_InitOptions(argc, argv); - return DeepState_Run(); -} -#endif diff --git a/examples/IntegerArithmetic.cpp b/examples/IntegerArithmetic.cpp index 7af644d..2ac07c2 100644 --- a/examples/IntegerArithmetic.cpp +++ b/examples/IntegerArithmetic.cpp @@ -44,10 +44,3 @@ TEST(Arithmetic, InvertibleMultiplication_CanFail) { << x << " != (" << x << " / " << y << ") * " << y; }); } - -#ifndef LIBFUZZER -int main(int argc, char *argv[]) { - DeepState_InitOptions(argc, argv); - return DeepState_Run(); -} -#endif diff --git a/examples/IntegerOverflow.cpp b/examples/IntegerOverflow.cpp index c5add45..d3d592f 100644 --- a/examples/IntegerOverflow.cpp +++ b/examples/IntegerOverflow.cpp @@ -15,7 +15,7 @@ */ #include - +#include using namespace deepstate; DEEPSTATE_NOINLINE int ident1(int x) { @@ -40,9 +40,3 @@ TEST(SignedInteger, MultiplicationOverflow) { << x << " squared overflowed."; } -#ifndef LIBFUZZER -int main(int argc, char *argv[]) { - DeepState_InitOptions(argc, argv); - return DeepState_Run(); -} -#endif diff --git a/examples/Lists.cpp b/examples/Lists.cpp index 8d21f6c..1456869 100644 --- a/examples/Lists.cpp +++ b/examples/Lists.cpp @@ -30,10 +30,3 @@ TEST(Vector, DoubleReversal) { << "Double reverse of vectors must be equal."; }); } - -#ifndef LIBFUZZER -int main(int argc, char *argv[]) { - DeepState_InitOptions(argc, argv); - DeepState_Run(); -} -#endif diff --git a/examples/OneOf.cpp b/examples/OneOf.cpp index 46cd551..a8e949a 100644 --- a/examples/OneOf.cpp +++ b/examples/OneOf.cpp @@ -63,10 +63,3 @@ TEST(OneOfExample, ProduceSixtyOrHigher) { << x << " is >= 60: " << " did " << choices << " from " << start; } } - -#ifndef LIBFUZZER -int main(int argc, char *argv[]) { - DeepState_InitOptions(argc, argv); - return DeepState_Run(); -} -#endif diff --git a/examples/Primes.cpp b/examples/Primes.cpp index 1401d35..52e3354 100644 --- a/examples/Primes.cpp +++ b/examples/Primes.cpp @@ -52,10 +52,3 @@ TEST(PrimePolynomial, OnlyGeneratesPrimes_NoStreaming) { DeepState_Assert(poly != (y * z)); DeepState_Assert(IsPrime(Pump(poly))); } - -#ifndef LIBFUZZER -int main(int argc, char *argv[]) { - DeepState_InitOptions(argc, argv); - return DeepState_Run(); -} -#endif diff --git a/examples/StreamingAndFormatting.cpp b/examples/StreamingAndFormatting.cpp index f34c8fe..9c5ff3d 100644 --- a/examples/StreamingAndFormatting.cpp +++ b/examples/StreamingAndFormatting.cpp @@ -40,9 +40,3 @@ TEST(Formatting, OverridePrintf) { printf("hello again!"); } -#ifndef LIBFUZZER -int main(int argc, char *argv[]) { - DeepState_InitOptions(argc, argv); - return DeepState_Run(); -} -#endif diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 9aea252..fb5fede 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -618,4 +618,10 @@ void __stack_chk_fail(void) { __builtin_unreachable(); } +__attribute__((weak)) +int main(int argc, char *argv[]) { + DeepState_InitOptions(argc, argv); + return DeepState_Run(); +} + DEEPSTATE_END_EXTERN_C diff --git a/src/lib/Log.c b/src/lib/Log.c index cbcb03f..dd22ea9 100644 --- a/src/lib/Log.c +++ b/src/lib/Log.c @@ -126,6 +126,14 @@ void DeepState_LogFormat(enum DeepState_LogLevel level, va_end(args); } +#pragma clang diagnostic push +#pragma GCC diagnostic ignored "-Wunknown-warning-option" +/*#pragma clang diagnostic ignored "-Wbuiltin-declaration-mismatch" +*/ + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch" + /* Override libc! */ DEEPSTATE_NOINLINE int puts(const char *str) { @@ -216,4 +224,7 @@ int __vfprintf_chk(int flag, FILE *file, const char *format, va_list args) { return 0; } +#pragma clang diagnostic pop +#pragma GCC diagnostic pop + DEEPSTATE_END_EXTERN_C From b3f20d974600890bc2a2473569ebea8384c2bba7 Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Thu, 27 Sep 2018 16:47:22 -0700 Subject: [PATCH 063/228] Minor tweak --- src/lib/Log.c | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/lib/Log.c b/src/lib/Log.c index dd22ea9..e09eab3 100644 --- a/src/lib/Log.c +++ b/src/lib/Log.c @@ -127,9 +127,7 @@ void DeepState_LogFormat(enum DeepState_LogLevel level, } #pragma clang diagnostic push -#pragma GCC diagnostic ignored "-Wunknown-warning-option" -/*#pragma clang diagnostic ignored "-Wbuiltin-declaration-mismatch" -*/ +#pragma clang diagnostic ignored "-Wunknown-warning-option" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wbuiltin-declaration-mismatch" From 400d826b0a3e369a1ae1d5bfbe484fb2993472af Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Thu, 27 Sep 2018 17:14:19 -0700 Subject: [PATCH 064/228] Make sure DeepState_Setup is not inlined for default-provided main functions. --- src/lib/DeepState.c | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index fb5fede..e6395ed 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -367,8 +367,13 @@ const struct DeepState_IndexEntry DeepState_API[] = { }; /* Set up DeepState. */ +DEEPSTATE_NOINLINE void DeepState_Setup(void) { - DeepState_AllocCurrentTestRun(); + static int was_setup = 0; + if (!was_setup) { + DeepState_AllocCurrentTestRun(); + was_setup = 1; + } /* TODO(pag): Sort the test cases by file name and line number. */ } @@ -620,8 +625,12 @@ void __stack_chk_fail(void) { __attribute__((weak)) int main(int argc, char *argv[]) { + int ret = 0; + DeepState_Setup(); DeepState_InitOptions(argc, argv); - return DeepState_Run(); + ret = DeepState_Run(); + DeepState_Teardown(); + return ret; } DEEPSTATE_END_EXTERN_C From fd0acedf8bd779ab712fc542ee62a0cb617dd785 Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Fri, 28 Sep 2018 11:12:06 -0700 Subject: [PATCH 065/228] Minor fix for OneOf on std::vector. --- src/include/deepstate/DeepState.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index 460155b..2d8ca64 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -351,7 +351,7 @@ inline static const T &OneOf(const std::vector &arr) { if (arr.empty()) { DeepState_Abandon("Empty vector passed to OneOf."); } - return arr[DeepState_IntInRange(0, arr.size - 1)]; + return arr[DeepState_IntInRange(0, arr.size() - 1)]; } From 61bc977f35592f2625430c46fca503231d24f54c Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Sat, 29 Sep 2018 14:20:06 -0400 Subject: [PATCH 066/228] removed $ from EVN more info: https://cmake.org/pipermail/cmake/2011-October/046706.html --- CMakeLists.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index eb62c96..a9ae409 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -15,7 +15,7 @@ project(deepstate) cmake_minimum_required(VERSION 2.8) -if (NOT DEFINED BUILD_LIBFUZZER AND DEFINED $ENV{BUILD_LIBFUZZER}) +if (NOT DEFINED BUILD_LIBFUZZER AND DEFINED ENV{BUILD_LIBFUZZER}) set(BUILD_LIBFUZZER "$ENV{BUILD_LIBFUZZER}") endif() From 3f69f87385a7efd5c62cf2922cb05a3c69afa4a3 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Sat, 29 Sep 2018 15:13:05 -0400 Subject: [PATCH 067/228] Workaround to avoid incompatible python packages --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index d83e607..b70ea7b 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,6 +10,7 @@ install: - sudo pip2 install -U pip - sudo pip install z3-solver - sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip +- sudo pip2 install cffi==1.7.0 pycparser==2.18 - mkdir build - cd build - cmake .. From 7617021494f211b6d904f174c25e1dc1495f2a7e Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Sat, 29 Sep 2018 15:20:56 -0400 Subject: [PATCH 068/228] Update .travis.yml --- .travis.yml | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index b70ea7b..13a15d2 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,18 +4,17 @@ sudo: true python: - "2.7" install: -- pip install pyflakes +- sudo pip2 install pyflakes - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev - sudo pip2 install -U pip -- sudo pip install z3-solver -- sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip +- sudo pip2 install z3-solver +- sudo pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip - sudo pip2 install cffi==1.7.0 pycparser==2.18 - mkdir build - cd build - cmake .. -- make -- python setup.py install +- sudo make install - cd .. env: - TASK=ARITHMETIC From 13e0b536c628ec6ff795ebead63b58769dd7dbe0 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Sat, 29 Sep 2018 15:32:43 -0400 Subject: [PATCH 069/228] Downgrade pycparser to 2.18 --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 13a15d2..58f0cb4 100644 --- a/.travis.yml +++ b/.travis.yml @@ -15,6 +15,8 @@ install: - cd build - cmake .. - sudo make install +- sudo pip2 uninstall -y pycparser==2.19 +- sudo pip2 install pycparser==2.18 - cd .. env: - TASK=ARITHMETIC From 09a38461e49f1c348876ba4519b1c9720b63b841 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 6 Nov 2018 01:04:49 -0700 Subject: [PATCH 070/228] Change SECDEV to past tense... --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 70b5dca..0761136 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ DeepState is a framework that provides C and C++ developers with a common interface to various symbolic execution and fuzzing engines. Users can write one test harness using a Google Test-like API, then execute it using multiple backends without having to learn the complexities of the underlying engines. It supports writing unit tests and API sequence tests, as well as automatic test generation. Read more about the goals and design of DeepState in our [paper](https://agroce.github.io/bar18.pdf). -The [2018 IEEE Cybersecurity Development Conference](https://secdev.ieee.org/2018/home) will include a full tutorial on effective use of DeepState. +The [2018 IEEE Cybersecurity Development Conference](https://secdev.ieee.org/2018/home) included a full tutorial on effective use of DeepState. ## Overview of Features From 5cdc1f62ce74efb98a183e3ef049724176ec8396 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 11:14:42 -0300 Subject: [PATCH 071/228] Update .travis.yml --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index 58f0cb4..b7d4e37 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,13 +10,13 @@ install: - sudo pip2 install -U pip - sudo pip2 install z3-solver - sudo pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip -- sudo pip2 install cffi==1.7.0 pycparser==2.18 +- sudo pip2 install cffi==1.7.0 pycparser==2.18 cle==7.8.9.26 pyvex==7.8.9.26 - mkdir build - cd build - cmake .. - sudo make install -- sudo pip2 uninstall -y pycparser==2.19 -- sudo pip2 install pycparser==2.18 +#- sudo pip2 uninstall -y pycparser==2.19 +#- sudo pip2 install pycparser==2.18 - cd .. env: - TASK=ARITHMETIC From cd308c113287fc423c36df5d7b0532b9cd4763f2 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 11:21:20 -0300 Subject: [PATCH 072/228] Forced angr version --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index b7d4e37..842b160 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,7 @@ install: - sudo pip2 install -U pip - sudo pip2 install z3-solver - sudo pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip -- sudo pip2 install cffi==1.7.0 pycparser==2.18 cle==7.8.9.26 pyvex==7.8.9.26 +- sudo pip2 install cffi==1.7.0 pycparser==2.18 cle==7.8.9.26 pyvex==7.8.9.26 angr==7.8.7.1 - mkdir build - cd build - cmake .. From 511575fe79f682bd357c8b03c9368888d2db066a Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 11:27:12 -0300 Subject: [PATCH 073/228] pip2 -> pip --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 842b160..6957a5c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,13 +4,13 @@ sudo: true python: - "2.7" install: -- sudo pip2 install pyflakes - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev - sudo pip2 install -U pip -- sudo pip2 install z3-solver -- sudo pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip -- sudo pip2 install cffi==1.7.0 pycparser==2.18 cle==7.8.9.26 pyvex==7.8.9.26 angr==7.8.7.1 +- sudo pip install pyflakes +- sudo pip install z3-solver +- sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip +- sudo pip install cffi==1.7.0 pycparser==2.18 cle==7.8.9.26 pyvex==7.8.9.26 angr==7.8.7.1 - mkdir build - cd build - cmake .. From a2443242e960caad440ffc38178ef0656cbb5223 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 11:32:35 -0300 Subject: [PATCH 074/228] Update .travis.yml --- .travis.yml | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 6957a5c..7c1a72a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -10,7 +10,8 @@ install: - sudo pip install pyflakes - sudo pip install z3-solver - sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip -- sudo pip install cffi==1.7.0 pycparser==2.18 cle==7.8.9.26 pyvex==7.8.9.26 angr==7.8.7.1 +- sudo pip install cffi==1.7.0 pycparser==2.18 cle==7.8.9.26 pyvex==7.8.9.26 +- sudo pip install angr==7.8.7.1 - mkdir build - cd build - cmake .. From 685645d5b417f16c9db2d7987cd2a60b5be51712 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 11:36:42 -0300 Subject: [PATCH 075/228] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 7c1a72a..9f87090 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ install: - sudo pip install z3-solver - sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip - sudo pip install cffi==1.7.0 pycparser==2.18 cle==7.8.9.26 pyvex==7.8.9.26 -- sudo pip install angr==7.8.7.1 +#- sudo pip install angr==7.8.7.1 - mkdir build - cd build - cmake .. From 9f08d7455143598d8b1ef76964a66ef8d315d8bd Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 11:39:56 -0300 Subject: [PATCH 076/228] Upgraded to xenial --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 9f87090..23aca89 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,5 @@ language: python -dist: trusty +dist: xenial sudo: true python: - "2.7" From 028356e1fdba6f4e457fd39af63e520702c32576 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 11:42:59 -0300 Subject: [PATCH 077/228] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 23aca89..7e0dea0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -11,7 +11,7 @@ install: - sudo pip install z3-solver - sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip - sudo pip install cffi==1.7.0 pycparser==2.18 cle==7.8.9.26 pyvex==7.8.9.26 -#- sudo pip install angr==7.8.7.1 +- sudo pip install angr==7.8.7.1 - mkdir build - cd build - cmake .. From 579de65fad98be32945cb3f1d4febe2d62e72c11 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 12:21:56 -0300 Subject: [PATCH 078/228] Update .travis.yml --- .travis.yml | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/.travis.yml b/.travis.yml index 7e0dea0..d1b76e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -7,11 +7,12 @@ install: - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev - sudo pip2 install -U pip -- sudo pip install pyflakes -- sudo pip install z3-solver -- sudo pip install https://github.com/trailofbits/manticore/archive/last_python2.zip -- sudo pip install cffi==1.7.0 pycparser==2.18 cle==7.8.9.26 pyvex==7.8.9.26 -- sudo pip install angr==7.8.7.1 +- pip install pyflakes --user +- pip install z3-solver --user +- pip install https://github.com/trailofbits/manticore/archive/last_python2.zip --user +- pip install cffi==1.7.0 pycparser==2.18 --user +- pip install cle==7.8.9.26 pyvex==7.8.9.26 --user +- pip install angr==7.8.7.1 --user - mkdir build - cd build - cmake .. From 0d94c21e08132a5752f82065ff54e162b7facdb4 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 12:53:49 -0300 Subject: [PATCH 079/228] Update .travis.yml --- .travis.yml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/.travis.yml b/.travis.yml index d1b76e0..856479c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,8 +1,8 @@ -language: python +language: bash dist: xenial sudo: true -python: -- "2.7" +#python: +#- "2.7" install: - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev From f1c8e3142bbe48f4d76f057af2bb1d63ba933eb8 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 13:45:05 -0300 Subject: [PATCH 080/228] Update .travis.yml --- .travis.yml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/.travis.yml b/.travis.yml index 856479c..56252be 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,13 +6,13 @@ sudo: true install: - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev -- sudo pip2 install -U pip -- pip install pyflakes --user -- pip install z3-solver --user -- pip install https://github.com/trailofbits/manticore/archive/last_python2.zip --user -- pip install cffi==1.7.0 pycparser==2.18 --user -- pip install cle==7.8.9.26 pyvex==7.8.9.26 --user -- pip install angr==7.8.7.1 --user +#- sudo pip2 install -U pip +- pip2 install pyflakes --user +- pip2 install z3-solver --user +- pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip --user +- pip2 install cffi==1.7.0 pycparser==2.18 --user +- pip2 install cle==7.8.9.26 pyvex==7.8.9.26 --user +- pip2 install angr==7.8.7.1 --user - mkdir build - cd build - cmake .. From 530c704dbb676cbba7031788676f81fc64b2419c Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 13:57:06 -0300 Subject: [PATCH 081/228] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 56252be..dc0c269 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,6 +12,7 @@ install: - pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip --user - pip2 install cffi==1.7.0 pycparser==2.18 --user - pip2 install cle==7.8.9.26 pyvex==7.8.9.26 --user +- pip2 uninstall unicorn - pip2 install angr==7.8.7.1 --user - mkdir build - cd build From 5b6f6c4dd2f6bdf91eaf887d16fbd2d5c3dbabf1 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 14:06:25 -0300 Subject: [PATCH 082/228] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index dc0c269..365355e 100644 --- a/.travis.yml +++ b/.travis.yml @@ -12,7 +12,7 @@ install: - pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip --user - pip2 install cffi==1.7.0 pycparser==2.18 --user - pip2 install cle==7.8.9.26 pyvex==7.8.9.26 --user -- pip2 uninstall unicorn +- pip2 uninstall unicorn -y - pip2 install angr==7.8.7.1 --user - mkdir build - cd build From b8e1ca9a020af4124a394dd6117ecb0b8a6c7143 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 14:17:05 -0300 Subject: [PATCH 083/228] Disabled manticore in .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index 365355e..00c6748 100644 --- a/.travis.yml +++ b/.travis.yml @@ -9,7 +9,7 @@ install: #- sudo pip2 install -U pip - pip2 install pyflakes --user - pip2 install z3-solver --user -- pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip --user +#- pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip --user - pip2 install cffi==1.7.0 pycparser==2.18 --user - pip2 install cle==7.8.9.26 pyvex==7.8.9.26 --user - pip2 uninstall unicorn -y From 183004409612ea3a991c16707f0b4a7a9fdf6dcd Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 14:45:14 -0300 Subject: [PATCH 084/228] Updated to angr 7.8.9.26 --- .travis.yml | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/.travis.yml b/.travis.yml index 00c6748..7e86447 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,20 +6,12 @@ sudo: true install: - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev -#- sudo pip2 install -U pip -- pip2 install pyflakes --user -- pip2 install z3-solver --user -#- pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip --user -- pip2 install cffi==1.7.0 pycparser==2.18 --user -- pip2 install cle==7.8.9.26 pyvex==7.8.9.26 --user -- pip2 uninstall unicorn -y -- pip2 install angr==7.8.7.1 --user +- pip2 install angr==7.8.9.26 --user +- pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip --user - mkdir build - cd build - cmake .. - sudo make install -#- sudo pip2 uninstall -y pycparser==2.19 -#- sudo pip2 install pycparser==2.18 - cd .. env: - TASK=ARITHMETIC From 10047d784d0b3f81c6a19e7cef810dcbcd0259cd Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 14:52:03 -0300 Subject: [PATCH 085/228] Update .travis.yml --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 7e86447..d79e79c 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ sudo: true install: - sudo apt-get -y update - sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev +- pip2 install pyflakes --user - pip2 install angr==7.8.9.26 --user - pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip --user - mkdir build From b47520a450fa78052a17648fa73b6d54e6648817 Mon Sep 17 00:00:00 2001 From: ggrieco-tob <31542053+ggrieco-tob@users.noreply.github.com> Date: Wed, 7 Nov 2018 14:56:25 -0300 Subject: [PATCH 086/228] Update .travis.yml --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index d79e79c..2cc49e8 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ sudo: true #- "2.7" install: - sudo apt-get -y update -- sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev +- sudo apt-get -y install build-essential gcc-multilib cmake python python-pip python-setuptools libffi-dev python-nose - pip2 install pyflakes --user - pip2 install angr==7.8.9.26 --user - pip2 install https://github.com/trailofbits/manticore/archive/last_python2.zip --user From 22578565f1d91618205e8d3e4e9c2ac38e4562ea Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 11 Nov 2018 15:23:22 -0700 Subject: [PATCH 087/228] Add a link to the slides for now (placeholder until ToB official link) --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 0761136..1866f80 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ DeepState is a framework that provides C and C++ developers with a common interface to various symbolic execution and fuzzing engines. Users can write one test harness using a Google Test-like API, then execute it using multiple backends without having to learn the complexities of the underlying engines. It supports writing unit tests and API sequence tests, as well as automatic test generation. Read more about the goals and design of DeepState in our [paper](https://agroce.github.io/bar18.pdf). -The [2018 IEEE Cybersecurity Development Conference](https://secdev.ieee.org/2018/home) included a full tutorial on effective use of DeepState. +The [2018 IEEE Cybersecurity Development Conference](https://secdev.ieee.org/2018/home) included a [full tutorial](http://www.petergoodman.me/docs/secdev-2018-slides.pdf) on effective use of DeepState. ## Overview of Features From 4257a68f169682239e933086c695d632d675c641 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 20 Nov 2018 11:46:52 -0700 Subject: [PATCH 088/228] Fix link to tutorial to point to official ToB github, not Peter's site --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 1866f80..737780e 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,7 @@ DeepState is a framework that provides C and C++ developers with a common interface to various symbolic execution and fuzzing engines. Users can write one test harness using a Google Test-like API, then execute it using multiple backends without having to learn the complexities of the underlying engines. It supports writing unit tests and API sequence tests, as well as automatic test generation. Read more about the goals and design of DeepState in our [paper](https://agroce.github.io/bar18.pdf). -The [2018 IEEE Cybersecurity Development Conference](https://secdev.ieee.org/2018/home) included a [full tutorial](http://www.petergoodman.me/docs/secdev-2018-slides.pdf) on effective use of DeepState. +The [2018 IEEE Cybersecurity Development Conference](https://secdev.ieee.org/2018/home) included a [full tutorial](https://github.com/trailofbits/publications/tree/master/workshops/DeepState:%20Bringing%20vulnerability%20detection%20tools%20into%20the%20development%20lifecycle%20-%20SecDev%202018) on effective use of DeepState. ## Overview of Features From 8051817526973907f31aab63912c8f507a701baa Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 20 Nov 2018 12:16:55 -0700 Subject: [PATCH 089/228] simple fix for libFuzzer ranges --- src/include/deepstate/DeepState.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 518411f..0436f3c 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -235,7 +235,10 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { DEEPSTATE_INLINE static tname DeepState_ ## Tname ## InRange( \ tname low, tname high) { \ tname x = DeepState_ ## Tname(); \ - (void) DeepState_Assume(low <= x && x <= high); \ + if (!DeepState_UsingLibFuzzer) \ + (void) DeepState_Assume(low <= x && x <= high); \ + else \ + x = low + (x%((high+1)-low)); \ return x; \ } From a3ad1135e7a5afb0cd6ad306a4a46d14f55b4417 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 29 Nov 2018 13:25:21 -0700 Subject: [PATCH 090/228] also use mod if replaying --- src/include/deepstate/DeepState.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 0436f3c..5fce7a4 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -235,7 +235,8 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { DEEPSTATE_INLINE static tname DeepState_ ## Tname ## InRange( \ tname low, tname high) { \ tname x = DeepState_ ## Tname(); \ - if (!DeepState_UsingLibFuzzer) \ + if (!(DeepState_UsingLibFuzzer || HAS_FLAGS_input_test_file \ + || HAS_FLAGS_input_test_dir || HAS_FLAGS_input_test_files_dir)) \ (void) DeepState_Assume(low <= x && x <= high); \ else \ x = low + (x%((high+1)-low)); \ From 5c723e0f62fd0c4271a2295c3bb3ace4c9ae90be Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 29 Nov 2018 13:31:46 -0700 Subject: [PATCH 091/228] fix wrong name for HAS_FLAG --- src/include/deepstate/DeepState.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 5fce7a4..23d1f4b 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -235,8 +235,8 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { DEEPSTATE_INLINE static tname DeepState_ ## Tname ## InRange( \ tname low, tname high) { \ tname x = DeepState_ ## Tname(); \ - if (!(DeepState_UsingLibFuzzer || HAS_FLAGS_input_test_file \ - || HAS_FLAGS_input_test_dir || HAS_FLAGS_input_test_files_dir)) \ + if (!(DeepState_UsingLibFuzzer || HAS_FLAG_input_test_file \ + || HAS_FLAG_input_test_dir || HAS_FLAG_input_test_files_dir)) \ (void) DeepState_Assume(low <= x && x <= high); \ else \ x = low + (x%((high+1)-low)); \ From a0bfead4cf493d78c8fde96679188a0ef3a1bcc8 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 30 Nov 2018 12:17:18 -0700 Subject: [PATCH 092/228] verbose --- src/include/deepstate/DeepState.h | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 23d1f4b..496372f 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -238,8 +238,11 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { if (!(DeepState_UsingLibFuzzer || HAS_FLAG_input_test_file \ || HAS_FLAG_input_test_dir || HAS_FLAG_input_test_files_dir)) \ (void) DeepState_Assume(low <= x && x <= high); \ - else \ + else { \ + DeepState_LogFormat(DeepState_LogInfo, \ + "Fixing value\n"); \ x = low + (x%((high+1)-low)); \ + \} return x; \ } From 5dff6925f5e6f1ae0a1a62424a5eae537a488c24 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 30 Nov 2018 12:24:27 -0700 Subject: [PATCH 093/228] more verbose assumption failures --- src/lib/DeepState.c | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index e6395ed..b872fa5 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -298,6 +298,9 @@ int32_t DeepState_MaxInt(int32_t v) { void _DeepState_Assume(int expr, const char *expr_str, const char *file, unsigned line) { if (!expr) { + DeepState_LogFormat(DeepState_LogError, + "%s(%u): Assumption %s failed", + file, line, expr_str); DeepState_Abandon("Assumption failed"); } } From 72d3b5bcf9acacd42c925e0657f04099393d29bc Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 30 Nov 2018 12:29:55 -0700 Subject: [PATCH 094/228] tell when computing a range --- src/include/deepstate/DeepState.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 496372f..0419420 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -235,14 +235,14 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { DEEPSTATE_INLINE static tname DeepState_ ## Tname ## InRange( \ tname low, tname high) { \ tname x = DeepState_ ## Tname(); \ + DeepState_LogFormat(DeepState_LogInfo, "Computing a range"); \ if (!(DeepState_UsingLibFuzzer || HAS_FLAG_input_test_file \ || HAS_FLAG_input_test_dir || HAS_FLAG_input_test_files_dir)) \ (void) DeepState_Assume(low <= x && x <= high); \ - else { \ - DeepState_LogFormat(DeepState_LogInfo, \ - "Fixing value\n"); \ + else { + DeepState_LogFormat(DeepState_LogInfo, "Fixing value"); \ x = low + (x%((high+1)-low)); \ - \} + \} return x; \ } From b61bfd162af46e09e355210d27564abbf6758a5a Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 30 Nov 2018 12:43:30 -0700 Subject: [PATCH 095/228] fix various issues --- src/include/deepstate/DeepState.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 0419420..bcc03f9 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -235,14 +235,14 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { DEEPSTATE_INLINE static tname DeepState_ ## Tname ## InRange( \ tname low, tname high) { \ tname x = DeepState_ ## Tname(); \ - DeepState_LogFormat(DeepState_LogInfo, "Computing a range"); \ + DeepState_LogFormat(DeepState_LogInfo, "Computing a range"); \ if (!(DeepState_UsingLibFuzzer || HAS_FLAG_input_test_file \ || HAS_FLAG_input_test_dir || HAS_FLAG_input_test_files_dir)) \ (void) DeepState_Assume(low <= x && x <= high); \ - else { + else { \ DeepState_LogFormat(DeepState_LogInfo, "Fixing value"); \ x = low + (x%((high+1)-low)); \ - \} + } \ return x; \ } From 9bd1e6b7f0c7591ba6f58fb4d220ce69159d4494 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 30 Nov 2018 12:52:02 -0700 Subject: [PATCH 096/228] fixup --- src/include/deepstate/DeepState.h | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index bcc03f9..23d1f4b 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -235,14 +235,11 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { DEEPSTATE_INLINE static tname DeepState_ ## Tname ## InRange( \ tname low, tname high) { \ tname x = DeepState_ ## Tname(); \ - DeepState_LogFormat(DeepState_LogInfo, "Computing a range"); \ if (!(DeepState_UsingLibFuzzer || HAS_FLAG_input_test_file \ || HAS_FLAG_input_test_dir || HAS_FLAG_input_test_files_dir)) \ (void) DeepState_Assume(low <= x && x <= high); \ - else { \ - DeepState_LogFormat(DeepState_LogInfo, "Fixing value"); \ + else \ x = low + (x%((high+1)-low)); \ - } \ return x; \ } From 87dd39d93cd878f98f3e44d2bf81aa0e9902ba01 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 1 Dec 2018 12:47:43 -0700 Subject: [PATCH 097/228] fix formatting --- src/include/deepstate/DeepState.h | 4 ++-- src/lib/DeepState.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 23d1f4b..1020910 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -236,10 +236,10 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { tname low, tname high) { \ tname x = DeepState_ ## Tname(); \ if (!(DeepState_UsingLibFuzzer || HAS_FLAG_input_test_file \ - || HAS_FLAG_input_test_dir || HAS_FLAG_input_test_files_dir)) \ + || HAS_FLAG_input_test_dir || HAS_FLAG_input_test_files_dir)) \ (void) DeepState_Assume(low <= x && x <= high); \ else \ - x = low + (x%((high+1)-low)); \ + x = low + (x%((high+1)-low)); \ return x; \ } diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index b872fa5..26c9fee 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -299,8 +299,8 @@ void _DeepState_Assume(int expr, const char *expr_str, const char *file, unsigned line) { if (!expr) { DeepState_LogFormat(DeepState_LogError, - "%s(%u): Assumption %s failed", - file, line, expr_str); + "%s(%u): Assumption %s failed", + file, line, expr_str); DeepState_Abandon("Assumption failed"); } } From 8b912a8ce1dc8db658a3f5f1246484807b5318db Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 2 Dec 2018 20:34:19 -0700 Subject: [PATCH 098/228] allow abort in libfuzzer --- src/lib/DeepState.c | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 26c9fee..91bbfc4 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -601,6 +601,13 @@ extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { enum DeepState_TestRunResult result = DeepState_RunTestLLVM(test); + const char* abort_check = getenv("LIBFUZZER_ABORT_ON_FAIL"); + if (abort_check != NULL) { + if ((result == DeepState_TestRunFail) || (result == DeepState_TestRunCrash)) { + abort(); + } + } + DeepState_Teardown(); DeepState_CurrentTestRun = NULL; free(mem); From e92f39fb5c8c59d3f41d4fafe3e255444099c5c7 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 4 Dec 2018 19:43:46 -0700 Subject: [PATCH 099/228] control log level --- src/include/deepstate/DeepState.h | 2 ++ src/lib/DeepState.c | 2 ++ src/lib/Log.c | 3 ++- 3 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 1020910..09f2414 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -64,6 +64,8 @@ DECLARE_bool(take_over); DECLARE_bool(abort_on_fail); DECLARE_bool(verbose_reads); +DECLARE_int(log_level); + enum { DeepState_InputSize = 8192 }; diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 91bbfc4..bb54b95 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -38,6 +38,8 @@ DEFINE_bool(take_over, false, "Replay test cases in take-over mode."); DEFINE_bool(abort_on_fail, false, "Abort on file replay failure (useful in file fuzzing)."); DEFINE_bool(verbose_reads, false, "Report on bytes being read during execution of test."); +DEFINE_int(log_level, 0, "Minimum level of logging to output.") + /* Pointer to the last registers DeepState_TestInfo data structure */ struct DeepState_TestInfo *DeepState_LastTestInfo = NULL; diff --git a/src/lib/Log.c b/src/lib/Log.c index e09eab3..4f4d642 100644 --- a/src/lib/Log.c +++ b/src/lib/Log.c @@ -73,7 +73,8 @@ char DeepState_LogBuf[DeepState_LogBufSize + 1] = {}; /* Log a C string. */ DEEPSTATE_NOINLINE void DeepState_Log(enum DeepState_LogLevel level, const char *str) { - if (DeepState_UsingLibFuzzer && (level < DeepState_LogExternal)) { + if ((DeepState_UsingLibFuzzer && (level < DeepState_LogExternal)) || + (level < FLAGS_log_level)) { return; } memset(DeepState_LogBuf, 0, DeepState_LogBufSize); From 8205c0d0747b4d9af0f49b413f4367c7f9e9e12b Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 4 Dec 2018 19:51:34 -0700 Subject: [PATCH 100/228] missing semicolon --- src/lib/DeepState.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index bb54b95..7c07c31 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -38,7 +38,7 @@ DEFINE_bool(take_over, false, "Replay test cases in take-over mode."); DEFINE_bool(abort_on_fail, false, "Abort on file replay failure (useful in file fuzzing)."); DEFINE_bool(verbose_reads, false, "Report on bytes being read during execution of test."); -DEFINE_int(log_level, 0, "Minimum level of logging to output.") +DEFINE_int(log_level, 0, "Minimum level of logging to output."); /* Pointer to the last registers DeepState_TestInfo data structure */ struct DeepState_TestInfo *DeepState_LastTestInfo = NULL; From c56651c5c0b77399e70d13ecb873c4cd0f2716ef Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Dec 2018 11:28:35 -0700 Subject: [PATCH 101/228] fix to ranges --- src/include/deepstate/DeepState.h | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 09f2414..76d7167 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -240,8 +240,8 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { if (!(DeepState_UsingLibFuzzer || HAS_FLAG_input_test_file \ || HAS_FLAG_input_test_dir || HAS_FLAG_input_test_files_dir)) \ (void) DeepState_Assume(low <= x && x <= high); \ - else \ - x = low + (x%((high+1)-low)); \ + else if ((x < low) || (x > high)) \ + x = low + (x%(((high-low)+1))); \ return x; \ } From 5288d5da3d81e578faa00ffb6bd2d40ea98bb205 Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Wed, 5 Dec 2018 13:55:57 -0500 Subject: [PATCH 102/228] Saturating version of InRange, new variable UsingSymExec --- bin/deepstate/common.py | 3 +++ bin/deepstate/main_angr.py | 7 ++++++ bin/deepstate/main_manticore.py | 8 +++++++ src/include/deepstate/DeepState.h | 38 +++++++++++++++++++++++++------ src/include/deepstate/Log.h | 1 + src/lib/DeepState.c | 9 ++++++++ src/lib/Log.c | 2 +- 7 files changed, 60 insertions(+), 8 deletions(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 8ca19ee..59828aa 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -87,6 +87,9 @@ class DeepState(object): def write_uint8_t(self, ea, val): raise NotImplementedError("Must be implemented by engine.") + def write_uint32_t(self, ea, val): + raise NotImplementedError("Must be implemented by engine.") + def concretize(self, val, constrain=False): raise NotImplementedError("Must be implemented by engine.") diff --git a/bin/deepstate/main_angr.py b/bin/deepstate/main_angr.py index 5478c94..b122d49 100644 --- a/bin/deepstate/main_angr.py +++ b/bin/deepstate/main_angr.py @@ -84,6 +84,10 @@ class DeepAngr(DeepState): self.state.memory.store(ea, val, size=1) return ea + 1 + def write_uint32_t(self, ea, val): + self.state.memory.store(ea, val, size=4) + return ea + 4 + def concretize(self, val, constrain=False): if isinstance(val, (int, long)): return val @@ -336,6 +340,9 @@ def hook_apis(args, project, run_state): mc = DeepAngr(state=run_state) apis = mc.read_api_table(ea_of_api_table) + # Tell the system that we're using symbolic execution. + mc.write_uint32_t(apis["UsingSymExec"], 1) + # Hook various functions. hook_function(project, apis['IsSymbolicUInt'], IsSymbolicUInt) hook_function(project, apis['ConcretizeData'], ConcretizeData) diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index 8f0a356..c467f97 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -87,6 +87,10 @@ class DeepManticore(DeepState): self.state.cpu.write_int(ea, val, size=8) return ea + 1 + def write_uint32_t(self, ea, val): + self.state.cpu.write_int(ea, val, size=32) + return ea + 1 + def concretize(self, val, constrain=False): if isinstance(val, (int, long)): return val @@ -418,6 +422,10 @@ def main_takeover(m, args, takeover_symbol): base = get_base(m) apis = mc.read_api_table(ea_of_api_table, base) + + # Tell the system that we're using symbolic execution. + mc.write_uint32_t(apis["UsingSymExec"], 1) + del mc fake_test = TestInfo(takeover_ea, '_takeover_test', '_takeover_file', 0) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 1020910..613a732 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -230,17 +230,41 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { } } -/* Return a symbolic value in a the range `[low_inc, high_inc]`. */ +/* Return a symbolic value in a the range `[low_inc, high_inc]`. + * + * Current implementation saturates values. An alternative implementation + * worth exploring, and perhaps supporting in addition to saturation, is + * something like: + * + * x = symbolic_value; + * size = (high - low) + 1 + * if (symbolic mode) { + * assume 0 <= x and x < size + * return x + * } else { + * return low + (x % size) + * } + * + * This type of version lets a reducer drive toward zero. + */ #define DEEPSTATE_MAKE_SYMBOLIC_RANGE(Tname, tname) \ DEEPSTATE_INLINE static tname DeepState_ ## Tname ## InRange( \ tname low, tname high) { \ - tname x = DeepState_ ## Tname(); \ - if (!(DeepState_UsingLibFuzzer || HAS_FLAG_input_test_file \ - || HAS_FLAG_input_test_dir || HAS_FLAG_input_test_files_dir)) \ + if (low > high) { \ + return DeepState_ ## Tname ## InRange(high, low); \ + } \ + const tname x = DeepState_ ## Tname(); \ + if (DeepState_UsingSymExec) { \ (void) DeepState_Assume(low <= x && x <= high); \ - else \ - x = low + (x%((high+1)-low)); \ - return x; \ + return x; \ + } \ + if (x < low) { \ + return low; \ + } else if (x > high) { \ + return high; \ + } else { \ + return x; \ + } \ } DEEPSTATE_MAKE_SYMBOLIC_RANGE(Size, size_t) diff --git a/src/include/deepstate/Log.h b/src/include/deepstate/Log.h index 8cb2767..7763c5d 100644 --- a/src/include/deepstate/Log.h +++ b/src/include/deepstate/Log.h @@ -24,6 +24,7 @@ DEEPSTATE_BEGIN_EXTERN_C extern int DeepState_UsingLibFuzzer; +extern int DeepState_UsingSymExec; struct DeepState_Stream; diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 91bbfc4..ad4a61a 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -38,6 +38,12 @@ DEFINE_bool(take_over, false, "Replay test cases in take-over mode."); DEFINE_bool(abort_on_fail, false, "Abort on file replay failure (useful in file fuzzing)."); DEFINE_bool(verbose_reads, false, "Report on bytes being read during execution of test."); +/* Set to 1 by Manticore/Angr/etc. when we're running symbolically. */ +int DeepState_UsingSymExec = 0; + +/* Set to 1 when we're using libFuzzer. */ +int DeepState_UsingLibFuzzer = 0; + /* Pointer to the last registers DeepState_TestInfo data structure */ struct DeepState_TestInfo *DeepState_LastTestInfo = NULL; @@ -366,6 +372,9 @@ const struct DeepState_IndexEntry DeepState_API[] = { {"StreamFloat", (void *) _DeepState_StreamFloat}, {"StreamString", (void *) _DeepState_StreamString}, + {"UsingLibFuzzer", (void *) &DeepState_UsingLibFuzzer}, + {"UsingSymExec", (void *) &DeepState_UsingSymExec}, + {NULL, NULL}, }; diff --git a/src/lib/Log.c b/src/lib/Log.c index e09eab3..63d67e4 100644 --- a/src/lib/Log.c +++ b/src/lib/Log.c @@ -66,7 +66,7 @@ enum { DeepState_LogBufSize = 4096 }; -int DeepState_UsingLibFuzzer = 0; +extern int DeepState_UsingLibFuzzer; char DeepState_LogBuf[DeepState_LogBufSize + 1] = {}; From 48092c7b4b7560ffaadb91272856e5eac707ca87 Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Wed, 5 Dec 2018 13:57:07 -0500 Subject: [PATCH 103/228] Update main_manticore.py --- bin/deepstate/main_manticore.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index c467f97..b7de01d 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -89,7 +89,7 @@ class DeepManticore(DeepState): def write_uint32_t(self, ea, val): self.state.cpu.write_int(ea, val, size=32) - return ea + 1 + return ea + 4 def concretize(self, val, constrain=False): if isinstance(val, (int, long)): From fa2cc6ab382b79f1ff3825a8890988db7cfd62a0 Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Wed, 5 Dec 2018 13:58:03 -0500 Subject: [PATCH 104/228] Update DeepState.h --- src/include/deepstate/DeepState.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 613a732..bc0661b 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -240,7 +240,7 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { * size = (high - low) + 1 * if (symbolic mode) { * assume 0 <= x and x < size - * return x + * return low + x * } else { * return low + (x % size) * } From 827e4cbe8258ed31e4e624e955ed034acc3e3775 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Dec 2018 17:31:45 -0700 Subject: [PATCH 105/228] switch to wrapping ranges --- src/include/deepstate/DeepState.h | 35 ++++++++++++++++--------------- 1 file changed, 18 insertions(+), 17 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index fd61563..ba0afb7 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -232,23 +232,8 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { } } -/* Return a symbolic value in a the range `[low_inc, high_inc]`. - * - * Current implementation saturates values. An alternative implementation - * worth exploring, and perhaps supporting in addition to saturation, is - * something like: - * - * x = symbolic_value; - * size = (high - low) + 1 - * if (symbolic mode) { - * assume 0 <= x and x < size - * return low + x - * } else { - * return low + (x % size) - * } - * - * This type of version lets a reducer drive toward zero. - */ +/* Return a symbolic value in a the range `[low_inc, high_inc]`. */ +/* Saturating version here is an alternative, but worse for fuzzing: #define DEEPSTATE_MAKE_SYMBOLIC_RANGE(Tname, tname) \ DEEPSTATE_INLINE static tname DeepState_ ## Tname ## InRange( \ tname low, tname high) { \ @@ -268,6 +253,22 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { return x; \ } \ } +*/ +#define DEEPSTATE_MAKE_SYMBOLIC_RANGE(Tname, tname) \ + DEEPSTATE_INLINE static tname DeepState_ ## Tname ## InRange( \ + tname low, tname high) { \ + if (low > high) { \ + return DeepState_ ## Tname ## InRange(high, low); \ + } \ + const tname x = DeepState_ ## Tname(); \ + const tname size = (high - low) + 1; \ + if (DeepState_UsingSymExec) { \ + (void) DeepState_Assume(0 <= x && x < size); \ + return low + x; \ + } else { \ + return low + (x % size); \ + } \ + } DEEPSTATE_MAKE_SYMBOLIC_RANGE(Size, size_t) DEEPSTATE_MAKE_SYMBOLIC_RANGE(Int64, int64_t) From c04168437b5d093f5d72297ea348cc98c0506850 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Dec 2018 20:54:11 -0700 Subject: [PATCH 106/228] go back to simple fix, but wrap when out of bounds and not symbolic --- src/include/deepstate/DeepState.h | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index ba0afb7..bbcf1bb 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -261,13 +261,14 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { return DeepState_ ## Tname ## InRange(high, low); \ } \ const tname x = DeepState_ ## Tname(); \ - const tname size = (high - low) + 1; \ if (DeepState_UsingSymExec) { \ - (void) DeepState_Assume(0 <= x && x < size); \ - return low + x; \ + (void) DeepState_Assume(low <= x && x <= high); \ } else { \ - return low + (x % size); \ + if ((x < low) || (x > high)) { \ + const tname size = (high - low) + 1; \ + x = low + (x % size); \ } \ + return x; \ } DEEPSTATE_MAKE_SYMBOLIC_RANGE(Size, size_t) From a608857d52e5f613a50f83a411cd17f8b10540f8 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Dec 2018 20:57:10 -0700 Subject: [PATCH 107/228] x can't be const now --- src/include/deepstate/DeepState.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index bbcf1bb..d500837 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -260,7 +260,7 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { if (low > high) { \ return DeepState_ ## Tname ## InRange(high, low); \ } \ - const tname x = DeepState_ ## Tname(); \ + tname x = DeepState_ ## Tname(); \ if (DeepState_UsingSymExec) { \ (void) DeepState_Assume(low <= x && x <= high); \ } else { \ From 478e5fd9b451a2ee722156ce9590d7e3d7da7901 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 5 Dec 2018 21:00:53 -0700 Subject: [PATCH 108/228] fix bad indentation --- src/include/deepstate/DeepState.h | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index d500837..11c4329 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -263,10 +263,9 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { tname x = DeepState_ ## Tname(); \ if (DeepState_UsingSymExec) { \ (void) DeepState_Assume(low <= x && x <= high); \ - } else { \ - if ((x < low) || (x > high)) { \ - const tname size = (high - low) + 1; \ - x = low + (x % size); \ + } else if ((x < low) || (x > high)) { \ + const tname size = (high - low) + 1; \ + x = low + (x % size); \ } \ return x; \ } From e7cb3ce8cde3df8068502535daf6fe7faf07328f Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 6 Dec 2018 05:09:23 -0700 Subject: [PATCH 109/228] try immediate return for manticore --- src/include/deepstate/DeepState.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 11c4329..ed8ecf8 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -260,12 +260,13 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { if (low > high) { \ return DeepState_ ## Tname ## InRange(high, low); \ } \ - tname x = DeepState_ ## Tname(); \ + const tname x = DeepState_ ## Tname(); \ if (DeepState_UsingSymExec) { \ (void) DeepState_Assume(low <= x && x <= high); \ + return x; } else if ((x < low) || (x > high)) { \ const tname size = (high - low) + 1; \ - x = low + (x % size); \ + return low + (x % size); \ } \ return x; \ } From 5cc17b00edefc41b787b6a37821bdf41011a2ee9 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 6 Dec 2018 05:15:42 -0700 Subject: [PATCH 110/228] fix if --- src/include/deepstate/DeepState.h | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index ed8ecf8..c103a72 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -263,8 +263,9 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { const tname x = DeepState_ ## Tname(); \ if (DeepState_UsingSymExec) { \ (void) DeepState_Assume(low <= x && x <= high); \ - return x; - } else if ((x < low) || (x > high)) { \ + return x; \ + } \ + if ((x < low) || (x > high)) { \ const tname size = (high - low) + 1; \ return low + (x % size); \ } \ From 062e62106cbb5fccc8f0d18dbb63ff1959316817 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 6 Dec 2018 15:13:52 -0700 Subject: [PATCH 111/228] Try writing symexec in do_run_test --- bin/deepstate/main_manticore.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index b7de01d..2ec04ca 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -335,6 +335,7 @@ def do_run_test(state, apis, test, hook_test=False): state = m.initial_state mc = DeepManticore(state) + mc.write_uint32_t(apis["UsingSymExec"], 8589934591) mc.begin_test(test) del mc From c2745be88234aebd5a8e1dbcee1c963f2d82e956 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 6 Dec 2018 17:16:38 -0700 Subject: [PATCH 112/228] move setting UsingSymExec to right place --- bin/deepstate/main_angr.py | 7 ++++--- bin/deepstate/main_manticore.py | 8 ++++---- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/bin/deepstate/main_angr.py b/bin/deepstate/main_angr.py index b122d49..46e3b66 100644 --- a/bin/deepstate/main_angr.py +++ b/bin/deepstate/main_angr.py @@ -281,6 +281,10 @@ def do_run_test(project, test, apis, run_state, should_call_state): test_state = run_state mc = DeepAngr(state=test_state) + + # Tell the system that we're using symbolic execution. + mc.write_uint32_t(apis["UsingSymExec"], 1) + mc.begin_test(test) del mc @@ -340,9 +344,6 @@ def hook_apis(args, project, run_state): mc = DeepAngr(state=run_state) apis = mc.read_api_table(ea_of_api_table) - # Tell the system that we're using symbolic execution. - mc.write_uint32_t(apis["UsingSymExec"], 1) - # Hook various functions. hook_function(project, apis['IsSymbolicUInt'], IsSymbolicUInt) hook_function(project, apis['ConcretizeData'], ConcretizeData) diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index 2ec04ca..1621963 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -335,7 +335,10 @@ def do_run_test(state, apis, test, hook_test=False): state = m.initial_state mc = DeepManticore(state) - mc.write_uint32_t(apis["UsingSymExec"], 8589934591) + + # Tell the system that we're using symbolic execution. + mc.write_uint32_t(apis["UsingSymExec"], 1) + mc.begin_test(test) del mc @@ -424,9 +427,6 @@ def main_takeover(m, args, takeover_symbol): base = get_base(m) apis = mc.read_api_table(ea_of_api_table, base) - # Tell the system that we're using symbolic execution. - mc.write_uint32_t(apis["UsingSymExec"], 1) - del mc fake_test = TestInfo(takeover_ea, '_takeover_test', '_takeover_file', 0) From 2f6dd8e047ef052838eda878cc2a49a2d13ebdca Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 6 Dec 2018 17:20:52 -0700 Subject: [PATCH 113/228] use all 1s just in case other-endian --- bin/deepstate/main_angr.py | 2 +- bin/deepstate/main_manticore.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/deepstate/main_angr.py b/bin/deepstate/main_angr.py index 46e3b66..a35bd58 100644 --- a/bin/deepstate/main_angr.py +++ b/bin/deepstate/main_angr.py @@ -283,7 +283,7 @@ def do_run_test(project, test, apis, run_state, should_call_state): mc = DeepAngr(state=test_state) # Tell the system that we're using symbolic execution. - mc.write_uint32_t(apis["UsingSymExec"], 1) + mc.write_uint32_t(apis["UsingSymExec"], 8589934591) mc.begin_test(test) del mc diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index 1621963..26d6672 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -337,7 +337,7 @@ def do_run_test(state, apis, test, hook_test=False): mc = DeepManticore(state) # Tell the system that we're using symbolic execution. - mc.write_uint32_t(apis["UsingSymExec"], 1) + mc.write_uint32_t(apis["UsingSymExec"], 8589934591) mc.begin_test(test) del mc From c9a4d676e3f4e85a899e236281434e7c48d4d08a Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 8 Dec 2018 00:48:14 -0700 Subject: [PATCH 114/228] Fix typo --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 737780e..3b78b9f 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ DeepState consists of a static library, used to write test harnesses, and comman If you install clang 6.0 or later, and run `cmake` when you install with the `BUILD_LIBFUZZER` environment variable defined, you can -generate tests using LlibFuzzer. Because both DeepState and libFuzzer +generate tests using libFuzzer. Because both DeepState and libFuzzer want to be `main`, this requires building a different executable for libFuzzer. The `examples` directory shows how this can be done. The libFuzzer executable works like any other libFuzzer executable, and From 375659421d4e07ab31fbc45c56bdb6596bc42593 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 8 Dec 2018 15:41:10 -0700 Subject: [PATCH 115/228] Simple brute-force fuzzer (#134) --- README.md | 37 ++++++++++- bin/deepstate/reducer.py | 2 + src/include/deepstate/DeepState.h | 100 +++++++++++++++++++++++++++++- src/lib/DeepState.c | 56 ++++++++++++++++- src/lib/Option.c | 3 +- 5 files changed, 189 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index 3b78b9f..c452288 100644 --- a/README.md +++ b/README.md @@ -29,7 +29,9 @@ The [2018 IEEE Cybersecurity Development Conference](https://secdev.ieee.org/201 ## Supported Platforms -DeepState currently targets Linux, with macOS support in progress. +DeepState currently targets Linux, with macOS support in progress +(some fuzzers work fine, but symbolic execution is not well-supported +yet, without a painful cross-compilation process). ## Dependencies @@ -113,6 +115,26 @@ argument to see all DeepState options. DeepState consists of a static library, used to write test harnesses, and command-line _executors_ written in Python. At this time, the best documentation is in the [examples](/examples) and in our [paper](https://agroce.github.io/bar18.pdf). A more extensive example, using DeepState and libFuzzer to test a user-mode file system, is available [here](https://github.com/agroce/testfs); in particular the [Tests.cpp](https://github.com/agroce/testfs/blob/master/Tests.cpp) file and CMakeLists.txt show DeepState usage. +## Built-In Fuzzer + +Every DeepState executable provides a simple built-in fuzzer that +generates tests using completely random data. Using this fuzzer is as +simple as calling the native executable with the `--fuzz` argument. +The fuzzer also takes a `seed` and `timeout` (default of two minutes) +to control the fuzzing. If you want to actually save the test cases +generated, you need to add a `--output_test_dir` arument to tell +DeepState where to put the generated tests. By default fuzzing saves +only failing and crashing tests. One more command line argument that +is particularly useful for fuzzing is the `--log_level` argument, +which controls how much output each test produces. By default, this +is set to show all the logging from your tests, which slows fuzzing, +but setting it to 2 or higher will only show messages produced by +tests failing or crashing. + +Note that while symbolic execution only works on Linux, without a +fairly complex cross-compliation process, the brute force fuzzer works +on macOS or (as far as we know) any Unix-like system. + ## Fuzzing with libFuzzer If you install clang 6.0 or later, and run `cmake` when you install @@ -121,7 +143,7 @@ generate tests using libFuzzer. Because both DeepState and libFuzzer want to be `main`, this requires building a different executable for libFuzzer. The `examples` directory shows how this can be done. The libFuzzer executable works like any other libFuzzer executable, and -the tests produced can be run using the normal DeepState executable. +the tests produced can be replayed using the normal DeepState executable. For example, generating some tests of the `OneOf` example (up to 5,000 runs), then running those tests to examine the results, would look like: @@ -143,7 +165,10 @@ corpus, but fuzzing will work even without an initial corpus, unlike AFL. One hint when using libFuzzer is to avoid dynamically allocating memory during a test, if that memory would not be freed on a test failure. This will leak memory and libFuzzer will run out of memory -very quickly in each fuzzing session. +very quickly in each fuzzing session. In theory, libFuzzer will work +on macOS, but getting everything to build with the right version of +clang can be difficult, since the Apple-provided LLVM is unlikely to +support libFuzzer on many versions of the operating system. ## Test case reduction @@ -196,6 +221,8 @@ WRITING REDUCED TEST WITH 20 BYTES TO minrmdirfail.test You can use `--which_test ` to specify which test to run, as with the `--input_which_test` options to test replay. +Test case reduction should work on any OS. + ## Fuzzing with AFL DeepState can also be used with a file-based fuzzer (e.g. AFL). There @@ -249,6 +276,10 @@ deferred instrumentation. You'll need code like: just before the call to `DeepState_Run()` (which reads the entire input file) in your `main`. +Because AFL and other file-based fuzzers only rely on the DeepState +native test executable, they should (like DeepState's built-in simple +fuzzer) work fine on macOS and other Unix-like OSes. + ## Contributing All accepted PRs are awarded bounties by Trail of Bits. Join the #deepstate channel on the [Empire Hacking Slack](https://empireslacking.herokuapp.com/) to discuss ongoing development and claim bounties. Check the [good first issue](https://github.com/trailofbits/deepstate/issues?q=is%3Aissue+is%3Aopen+label%3A%22good+first+issue%22) label for suggested contributions. diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index fae6299..87aa4ae 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -130,6 +130,8 @@ def main(): cuts = s[0] for c in cuts: newTest = currentTest[:c[0]] + currentTest[c[1]+1:] + if len(newTest) == len(currentTest): + continue # Ignore non-shrinking reductions r = writeAndRunCandidate(newTest) if checks(r): print("ONEOF REMOVAL REDUCED TEST TO", len(newTest), "BYTES") diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index c103a72..2059824 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -63,8 +64,12 @@ DECLARE_string(output_test_dir); DECLARE_bool(take_over); DECLARE_bool(abort_on_fail); DECLARE_bool(verbose_reads); +DECLARE_bool(fuzz); +DECLARE_bool(fuzz_save_passing); DECLARE_int(log_level); +DECLARE_int(seed); +DECLARE_int(timeout); enum { DeepState_InputSize = 8192 @@ -519,7 +524,9 @@ static void DeepState_RunTest(struct DeepState_TestInfo *test) { } else { DeepState_LogFormat(DeepState_LogInfo, "Passed: %s", test->test_name); if (HAS_FLAG_output_test_dir) { - DeepState_SavePassingTest(); + if (!FLAGS_fuzz || FLAGS_fuzz_save_passing) { + DeepState_SavePassingTest(); + } } exit(DeepState_TestRunPass); } @@ -588,6 +595,37 @@ DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) { return DeepState_TestRunCrash; } +/* Run a test case with input initialized by fuzzing. */ +static enum DeepState_TestRunResult +DeepState_FuzzOneTestCase(struct DeepState_TestInfo *test) { + DeepState_InputIndex = 0; + + for (int i = 0; i < DeepState_InputSize; i++) { + DeepState_Input[i] = (char)rand(); + } + + DeepState_Begin(test); + + enum DeepState_TestRunResult result = DeepState_ForkAndRunTest(test); + + if (result == DeepState_TestRunCrash) { + DeepState_LogFormat(DeepState_LogError, "Crashed: %s", test->test_name); + + if (HAS_FLAG_output_test_dir) { + DeepState_SaveCrashingTest(); + } + + DeepState_Crash(); + } + + if (FLAGS_abort_on_fail && ((result == DeepState_TestRunCrash) || + (result == DeepState_TestRunFail))) { + abort(); + } + + return result; +} + /* Run a single saved test case with input initialized from the file * `name` in directory `dir`. */ static enum DeepState_TestRunResult @@ -711,6 +749,60 @@ static int DeepState_RunSingleSavedTestCase(void) { return num_failed_tests; } +/* Fuzz test `FLAGS_input_which_test` or first test, if not defined. */ +static int DeepState_Fuzz(void) { + DeepState_LogFormat(DeepState_LogInfo, "Starting fuzzing"); + + if (HAS_FLAG_seed) { + srand(FLAGS_seed); + } else { + srand(time(NULL)); + } + + long start = (long)time(NULL); + long current = (long)time(NULL); + long diff = 0; + unsigned i = 0; + + int num_failed_tests = 0; + + struct DeepState_TestInfo *test = NULL; + + DeepState_Setup(); + + for (test = DeepState_FirstTest(); test != NULL; test = test->prev) { + if (HAS_FLAG_input_which_test) { + if (strncmp(FLAGS_input_which_test, test->test_name, strlen(FLAGS_input_which_test)) == 0) { + break; + } + } else { + DeepState_LogFormat(DeepState_LogInfo, + "No test specified, defaulting to last test defined"); + break; + } + } + + if (test == NULL) { + DeepState_LogFormat(DeepState_LogInfo, + "Could not find matching test for %s", + FLAGS_input_which_test); + return 0; + } + + while (diff < FLAGS_timeout) { + i++; + num_failed_tests += DeepState_FuzzOneTestCase(test); + + current = (long)time(NULL); + diff = current-start; + } + + DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests. %d failed tests.", + i, num_failed_tests); + + return num_failed_tests; +} + /* Run tests from `FLAGS_input_test_files_dir`, under `FLAGS_input_which_test` * or first test, if not defined. */ static int DeepState_RunSingleSavedTestDir(void) { @@ -811,7 +903,11 @@ static int DeepState_Run(void) { if (HAS_FLAG_input_test_files_dir) { return DeepState_RunSingleSavedTestDir(); - } + } + + if (FLAGS_fuzz) { + return DeepState_Fuzz(); + } int num_failed_tests = 0; int use_drfuzz = getenv("DYNAMORIO_EXE_PATH") != NULL; diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index fdf40ad..267386c 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -37,8 +37,12 @@ DEFINE_string(output_test_dir, "", "Directory where tests will be saved."); DEFINE_bool(take_over, false, "Replay test cases in take-over mode."); DEFINE_bool(abort_on_fail, false, "Abort on file replay failure (useful in file fuzzing)."); DEFINE_bool(verbose_reads, false, "Report on bytes being read during execution of test."); +DEFINE_bool(fuzz, false, "Perform brute force unguided fuzzing."); +DEFINE_bool(fuzz_save_passing, false, "Save passing tests during fuzzing."); DEFINE_int(log_level, 0, "Minimum level of logging to output."); +DEFINE_int(seed, 0, "Seed for brute force fuzzing (uses time if not set)."); +DEFINE_int(timeout, 120, "Timeout for brute force fuzzing."); /* Set to 1 by Manticore/Angr/etc. when we're running symbolically. */ int DeepState_UsingSymExec = 0; @@ -555,14 +559,60 @@ void DeepState_BeginDrFuzz(struct DeepState_TestInfo *test) { DrMemFuzzFunc(DeepState_Input, DeepState_InputSize); } +/* Right now "fake" a hexdigest by just using random bytes. Not ideal. */ +void makeFilename(char *name, size_t size) { + const char *entities = "0123456789abcdef"; + for (int i = 0; i < size; i++) { + name[i] = entities[rand()%16]; + } +} + +void writeInputData(char* name) { + size_t path_len = 2 + sizeof(char) * (strlen(FLAGS_output_test_dir) + strlen(name)); + char *path = (char *) malloc(path_len); + snprintf(path, path_len, "%s/%s", FLAGS_output_test_dir, name); + FILE *fp = fopen(path, "wb"); + if (fp == NULL) { + DeepState_LogFormat(DeepState_LogError, "Failed to create file `%s`", path); + free(path); + return; + } + size_t written = fwrite((void *)DeepState_Input, 1, DeepState_InputSize, fp); + if (written != DeepState_InputSize) { + DeepState_LogFormat(DeepState_LogError, "Failed to write to file `%s`", path); + } else { + DeepState_LogFormat(DeepState_LogInfo, "Saved test case to file `%s`", path); + } + free(path); + fclose(fp); +} + /* Save a passing test to the output test directory. */ -void DeepState_SavePassingTest(void) {} +void DeepState_SavePassingTest(void) { + char name[48]; + makeFilename(name, 40); + name[40] = 0; + strncat(name, ".pass", 48); + writeInputData(name); +} /* Save a failing test to the output test directory. */ -void DeepState_SaveFailingTest(void) {} +void DeepState_SaveFailingTest(void) { + char name[48]; + makeFilename(name, 40); + name[40] = 0; + strncat(name, ".fail", 48); + writeInputData(name); +} /* Save a crashing test to the output test directory. */ -void DeepState_SaveCrashingTest(void) {} +void DeepState_SaveCrashingTest(void) { + char name[48]; + makeFilename(name, 40); + name[40] = 0; + strncat(name, ".crash", 48); + writeInputData(name); +} /* Return the first test case to run. */ struct DeepState_TestInfo *DeepState_FirstTest(void) { diff --git a/src/lib/Option.c b/src/lib/Option.c index 9401006..5a0c8ed 100644 --- a/src/lib/Option.c +++ b/src/lib/Option.c @@ -125,7 +125,8 @@ static void ProcessOptionString(void) { if (' ' == *ch || DeepState_FakeSpace == *ch) { *ch = '\0'; state = kSeenSpace; - + } else if ('-' == *ch) { + state = kSeenDash; } else if (IsValidValueChar(*ch)) { /* E.g. `--tools bbcount`. */ state = kInValue; DeepState_OptionValues[num_options - 1] = ch; From 19b606be8e26a6c259a3bd59440a1dff2a79273e Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 9 Dec 2018 11:34:47 -0700 Subject: [PATCH 116/228] Fix ranges (C modulo can be negative) --- src/include/deepstate/DeepState.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 2059824..163d921 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -272,7 +272,7 @@ DEEPSTATE_INLINE static void DeepState_Check(int expr) { } \ if ((x < low) || (x > high)) { \ const tname size = (high - low) + 1; \ - return low + (x % size); \ + return low + ((x % size + size) % size); \ } \ return x; \ } From 66ef2abc1b29c2ec2a95c388fc015db9dae80dd5 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 9 Dec 2018 20:59:43 -0700 Subject: [PATCH 117/228] Fix so libFuzzer works on macOS --- CMakeLists.txt | 2 +- README.md | 17 ++++++++++++----- src/lib/DeepState.c | 2 ++ 3 files changed, 15 insertions(+), 6 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index a9ae409..448dfa7 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -115,7 +115,7 @@ if (BUILD_LIBFUZZER) src/lib/Stream.c ) - target_compile_options(${PROJECT_NAME}_LF PUBLIC -mno-avx -fsanitize=fuzzer-no-link,undefined) + target_compile_options(${PROJECT_NAME}_LF PUBLIC -DLIBFUZZER -mno-avx -fsanitize=fuzzer-no-link,undefined) target_include_directories(${PROJECT_NAME}_LF PUBLIC SYSTEM "${CMAKE_SOURCE_DIR}/src/include" diff --git a/README.md b/README.md index c452288..9508bc3 100644 --- a/README.md +++ b/README.md @@ -30,7 +30,7 @@ The [2018 IEEE Cybersecurity Development Conference](https://secdev.ieee.org/201 ## Supported Platforms DeepState currently targets Linux, with macOS support in progress -(some fuzzers work fine, but symbolic execution is not well-supported +(the fuzzers work fine, but symbolic execution is not well-supported yet, without a painful cross-compilation process). ## Dependencies @@ -165,10 +165,17 @@ corpus, but fuzzing will work even without an initial corpus, unlike AFL. One hint when using libFuzzer is to avoid dynamically allocating memory during a test, if that memory would not be freed on a test failure. This will leak memory and libFuzzer will run out of memory -very quickly in each fuzzing session. In theory, libFuzzer will work -on macOS, but getting everything to build with the right version of -clang can be difficult, since the Apple-provided LLVM is unlikely to -support libFuzzer on many versions of the operating system. +very quickly in each fuzzing session. Using libFuzzer on macOS +requires compiling DeepState and your program with a clang that +supports libFuzzer (which the Apple built-in probably won't); this can be as simple as doing: + +```shell +brew install llvm@6 +CC=/usr/local/opt/llvm\@6/bin/clang CXX=/usr/local/opt/llvm\@6/bin/clang++ cmake .. +make install +``` + +Other ways of getting an appropriate LLVM may also work. ## Test case reduction diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 267386c..b35c2b8 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -694,6 +694,7 @@ void __stack_chk_fail(void) { __builtin_unreachable(); } +#ifndef LIBFUZZER __attribute__((weak)) int main(int argc, char *argv[]) { int ret = 0; @@ -703,5 +704,6 @@ int main(int argc, char *argv[]) { DeepState_Teardown(); return ret; } +#endif DEEPSTATE_END_EXTERN_C From 5bbba1d3e46f5397310ef2b7cd022e5356a3c59b Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 9 Dec 2018 21:05:08 -0700 Subject: [PATCH 118/228] Remind to use BUILD_LIBFUZZER --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 9508bc3..6d8bdbe 100644 --- a/README.md +++ b/README.md @@ -171,7 +171,7 @@ supports libFuzzer (which the Apple built-in probably won't); this can be as sim ```shell brew install llvm@6 -CC=/usr/local/opt/llvm\@6/bin/clang CXX=/usr/local/opt/llvm\@6/bin/clang++ cmake .. +CC=/usr/local/opt/llvm\@6/bin/clang CXX=/usr/local/opt/llvm\@6/bin/clang++ BUILD_LIBFUZZER=TRUE cmake .. make install ``` From 18e8761576c059b760d25cebe19a93bb728835bd Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 11 Dec 2018 12:15:08 -0700 Subject: [PATCH 119/228] Remove dependency on angr/manticore on macOS --- bin/setup.py.in | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/bin/setup.py.in b/bin/setup.py.in index dfb965e..f4a03e1 100644 --- a/bin/setup.py.in +++ b/bin/setup.py.in @@ -30,7 +30,10 @@ setuptools.setup( author_email="peter@trailofbits.com", license="Apache-2.0", keywords="tdd testing symbolic execution", - install_requires=['claripy==7.8.6.16','angr==7.8.7.1', 'manticore==0.1.10'], + install_requires=[ + "claripy==7.8.6.16 ; sys_platform != 'darwin'", + "angr==7.8.7.1 ; sys_platform != 'darwin'", + "manticore==0.1.10 ; sys_platform != 'darwin'"], entry_points={ 'console_scripts': [ 'deepstate = deepstate.main_manticore:main', From b89d7d70732deb53683e0462d3247ed847b52120 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 15 Dec 2018 13:28:15 -0700 Subject: [PATCH 120/228] add a simple no fork mode for replay and fuzzing --- src/include/deepstate/DeepState.h | 6 +++++- src/lib/DeepState.c | 3 ++- 2 files changed, 7 insertions(+), 2 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 163d921..03b0438 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -66,6 +66,7 @@ DECLARE_bool(abort_on_fail); DECLARE_bool(verbose_reads); DECLARE_bool(fuzz); DECLARE_bool(fuzz_save_passing); +DECLARE_bool(no_fork); DECLARE_int(log_level); DECLARE_int(seed); @@ -533,7 +534,7 @@ static void DeepState_RunTest(struct DeepState_TestInfo *test) { } /* Run a test case, but in libFuzzer, so not inside a fork. */ -static int DeepState_RunTestLLVM(struct DeepState_TestInfo *test) { +static int DeepState_RunTestNoFork(struct DeepState_TestInfo *test) { /* Run the test. */ if (!setjmp(DeepState_ReturnToRun)) { /* Convert uncaught C++ exceptions into a test failure. */ @@ -577,6 +578,9 @@ static int DeepState_RunTestLLVM(struct DeepState_TestInfo *test) { /* Fork and run `test`. */ static enum DeepState_TestRunResult DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) { + if (FLAG_no_fork) { + return DeepState_RunTestNoFork(test); + } pid_t test_pid = fork(); if (!test_pid) { DeepState_RunTest(test); diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index b35c2b8..1e162ad 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -39,6 +39,7 @@ DEFINE_bool(abort_on_fail, false, "Abort on file replay failure (useful in file DEFINE_bool(verbose_reads, false, "Report on bytes being read during execution of test."); DEFINE_bool(fuzz, false, "Perform brute force unguided fuzzing."); DEFINE_bool(fuzz_save_passing, false, "Save passing tests during fuzzing."); +DEFINE_bool(no_fork, false, "Don't fork when running a test.") DEFINE_int(log_level, 0, "Minimum level of logging to output."); DEFINE_int(seed, 0, "Seed for brute force fuzzing (uses time if not set)."); @@ -660,7 +661,7 @@ extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { DeepState_Begin(test); - enum DeepState_TestRunResult result = DeepState_RunTestLLVM(test); + enum DeepState_TestRunResult result = DeepState_RunTestNoFork(test); const char* abort_check = getenv("LIBFUZZER_ABORT_ON_FAIL"); if (abort_check != NULL) { From 950da4a78935b47d303d27df907641774d9fdeef Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 15 Dec 2018 13:40:17 -0700 Subject: [PATCH 121/228] fix various issues --- src/include/deepstate/DeepState.h | 20 ++++++++++++-------- src/lib/DeepState.c | 2 +- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 03b0438..51c3cee 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -578,16 +578,20 @@ static int DeepState_RunTestNoFork(struct DeepState_TestInfo *test) { /* Fork and run `test`. */ static enum DeepState_TestRunResult DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) { - if (FLAG_no_fork) { - return DeepState_RunTestNoFork(test); - } - pid_t test_pid = fork(); - if (!test_pid) { - DeepState_RunTest(test); + pid_t test_pid; + if (!FLAGS_no_fork) { + test_pid = fork(); + if (!test_pid) { + DeepState_RunTest(test); + } } int wstatus; - waitpid(test_pid, &wstatus, 0); - + if (!FLAGS_no_fork) { + waitpid(test_pid, &wstatus, 0); + } else { + wstatus = DeepState_RunTestNoFork(test); + } + /* If we exited normally, the status code tells us if the test passed. */ if (WIFEXITED(wstatus)) { uint8_t status = WEXITSTATUS(wstatus); diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 1e162ad..cfd1657 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -39,7 +39,7 @@ DEFINE_bool(abort_on_fail, false, "Abort on file replay failure (useful in file DEFINE_bool(verbose_reads, false, "Report on bytes being read during execution of test."); DEFINE_bool(fuzz, false, "Perform brute force unguided fuzzing."); DEFINE_bool(fuzz_save_passing, false, "Save passing tests during fuzzing."); -DEFINE_bool(no_fork, false, "Don't fork when running a test.") +DEFINE_bool(no_fork, false, "Don't fork when running a test."); DEFINE_int(log_level, 0, "Minimum level of logging to output."); DEFINE_int(seed, 0, "Seed for brute force fuzzing (uses time if not set)."); From 6e0c09f83539886d68f1b569e7c03bc611ee7e47 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 15 Dec 2018 13:46:53 -0700 Subject: [PATCH 122/228] Note fork issues in README --- README.md | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/README.md b/README.md index 6d8bdbe..cf5420c 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,15 @@ argument to see all DeepState options. DeepState consists of a static library, used to write test harnesses, and command-line _executors_ written in Python. At this time, the best documentation is in the [examples](/examples) and in our [paper](https://agroce.github.io/bar18.pdf). A more extensive example, using DeepState and libFuzzer to test a user-mode file system, is available [here](https://github.com/agroce/testfs); in particular the [Tests.cpp](https://github.com/agroce/testfs/blob/master/Tests.cpp) file and CMakeLists.txt show DeepState usage. +## A Note on Mac OS and Forking + +Normally, when running a test for replay or fuzzing, DeepState forks +in order to cleanly handle crashes of a test. Unfortunately, `fork()` +on mac OS is extremely slow. When using the built-in fuzzer or +replaying tests, it is highly recommended to add the `--no_fork` +option on mac OS, unless you need the added crash handling (that is, +things aren't working without that option). + ## Built-In Fuzzer Every DeepState executable provides a simple built-in fuzzer that From 10a664c9840f6333032d07de0c94fbeaf229bad4 Mon Sep 17 00:00:00 2001 From: Peter Goodman Date: Sat, 15 Dec 2018 16:10:30 -0500 Subject: [PATCH 123/228] Changed --no_fork to --fork as it implies the existence of --no_fork --- src/include/deepstate/DeepState.h | 8 ++++---- src/lib/DeepState.c | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 51c3cee..2de5644 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -66,7 +66,7 @@ DECLARE_bool(abort_on_fail); DECLARE_bool(verbose_reads); DECLARE_bool(fuzz); DECLARE_bool(fuzz_save_passing); -DECLARE_bool(no_fork); +DECLARE_bool(fork); DECLARE_int(log_level); DECLARE_int(seed); @@ -579,14 +579,14 @@ static int DeepState_RunTestNoFork(struct DeepState_TestInfo *test) { static enum DeepState_TestRunResult DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) { pid_t test_pid; - if (!FLAGS_no_fork) { + if (FLAGS_fork) { test_pid = fork(); if (!test_pid) { DeepState_RunTest(test); } } - int wstatus; - if (!FLAGS_no_fork) { + int wstatus = 0; + if (FLAGS_fork) { waitpid(test_pid, &wstatus, 0); } else { wstatus = DeepState_RunTestNoFork(test); diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index cfd1657..2871ecb 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -39,7 +39,7 @@ DEFINE_bool(abort_on_fail, false, "Abort on file replay failure (useful in file DEFINE_bool(verbose_reads, false, "Report on bytes being read during execution of test."); DEFINE_bool(fuzz, false, "Perform brute force unguided fuzzing."); DEFINE_bool(fuzz_save_passing, false, "Save passing tests during fuzzing."); -DEFINE_bool(no_fork, false, "Don't fork when running a test."); +DEFINE_bool(fork, true, "Fork when running a test."); DEFINE_int(log_level, 0, "Minimum level of logging to output."); DEFINE_int(seed, 0, "Seed for brute force fuzzing (uses time if not set)."); From 7756c80d63d3c21c4f4344e731d276d7df475152 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 13:44:43 -0700 Subject: [PATCH 124/228] try changing test output to TRACE --- examples/Fixture.cpp | 4 ++-- examples/StreamingAndFormatting.cpp | 15 ++++++++------- src/include/deepstate/Log.h | 11 ++++++----- src/lib/Log.c | 14 ++++++++------ 4 files changed, 24 insertions(+), 20 deletions(-) diff --git a/examples/Fixture.cpp b/examples/Fixture.cpp index ba288b5..1d64443 100644 --- a/examples/Fixture.cpp +++ b/examples/Fixture.cpp @@ -20,12 +20,12 @@ class MyTest : public deepstate::Test { public: void SetUp(void) { - LOG(INFO) + LOG(TRACE) << "Setting up!"; } void TearDown(void) { - LOG(INFO) + LOG(TRACE) << "Tearing down!"; } diff --git a/examples/StreamingAndFormatting.cpp b/examples/StreamingAndFormatting.cpp index 9c5ff3d..42fa2dd 100644 --- a/examples/StreamingAndFormatting.cpp +++ b/examples/StreamingAndFormatting.cpp @@ -18,19 +18,20 @@ TEST(Streaming, BasicLevels) { LOG(DEBUG) << "This is a debug message"; - LOG(INFO) << "This is an info message"; + LOG(TRACE) << "This is a trace 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"; + LOG(TRACE) << "This is a trace 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; + LOG(TRACE) << 'a'; + LOG(TRACE) << 1; + LOG(TRACE) << 1.0; + LOG(TRACE) << "string"; + LOG(TRACE) << nullptr; } TEST(Formatting, OverridePrintf) { diff --git a/src/include/deepstate/Log.h b/src/include/deepstate/Log.h index 7763c5d..5a05afb 100644 --- a/src/include/deepstate/Log.h +++ b/src/include/deepstate/Log.h @@ -34,12 +34,13 @@ struct DeepState_VarArgs { enum DeepState_LogLevel { DeepState_LogDebug = 0, - DeepState_LogInfo = 1, - DeepState_LogWarning = 2, + DeepState_LogTrace = 1, + DeepState_LogInfo = 2, + DeepState_LogWarning = 3, DeepState_LogWarn = DeepState_LogWarning, - DeepState_LogError = 3, - DeepState_LogExternal = 4, - DeepState_LogFatal = 5, + DeepState_LogError = 4, + DeepState_LogExternal = 5, + DeepState_LogFatal = 6, DeepState_LogCritical = DeepState_LogFatal, }; diff --git a/src/lib/Log.c b/src/lib/Log.c index cf31c04..b352df1 100644 --- a/src/lib/Log.c +++ b/src/lib/Log.c @@ -47,6 +47,8 @@ static const char *DeepState_LogLevelStr(enum DeepState_LogLevel level) { switch (level) { case DeepState_LogDebug: return "DEBUG"; + case DeepState_LogTrace: + return "TRACE"; case DeepState_LogInfo: return "INFO"; case DeepState_LogWarning: @@ -136,7 +138,7 @@ void DeepState_LogFormat(enum DeepState_LogLevel level, /* Override libc! */ DEEPSTATE_NOINLINE int puts(const char *str) { - DeepState_Log(DeepState_LogInfo, str); + DeepState_Log(DeepState_LogTrace, str); return 0; } @@ -144,7 +146,7 @@ DEEPSTATE_NOINLINE int printf(const char *format, ...) { va_list args; va_start(args, format); - DeepState_LogVFormat(DeepState_LogInfo, format, args); + DeepState_LogVFormat(DeepState_LogTrace, format, args); va_end(args); return 0; } @@ -153,20 +155,20 @@ DEEPSTATE_NOINLINE int __printf_chk(int flag, const char *format, ...) { va_list args; va_start(args, format); - DeepState_LogVFormat(DeepState_LogInfo, format, args); + DeepState_LogVFormat(DeepState_LogTrace, format, args); va_end(args); return 0; } DEEPSTATE_NOINLINE int vprintf(const char *format, va_list args) { - DeepState_LogVFormat(DeepState_LogInfo, format, args); + DeepState_LogVFormat(DeepState_LogTrace, format, args); return 0; } DEEPSTATE_NOINLINE int __vprintf_chk(int flag, const char *format, va_list args) { - DeepState_LogVFormat(DeepState_LogInfo, format, args); + DeepState_LogVFormat(DeepState_LogTrace, format, args); return 0; } @@ -175,7 +177,7 @@ 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); + DeepState_LogVFormat(DeepState_LogTrace, format, args); } else { DeepState_LogVFormat(DeepState_LogExternal, format, args); } From 7efe5f84ad8f7c0a0bed36c758fbcd185376bea8 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 13:52:18 -0700 Subject: [PATCH 125/228] Add macro for TRACE logging --- src/include/deepstate/DeepState.hpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index 2d8ca64..e4c0617 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -521,6 +521,9 @@ struct Comparer { #define LOG_DEBUG(cond) \ ::deepstate::Stream(DeepState_LogDebug, (cond), __FILE__, __LINE__) +#define LOG_TRACE(cond) \ + ::deepstate::Stream(DeepState_LogTrace, (cond), __FILE__, __LINE__) + #define LOG_INFO(cond) \ ::deepstate::Stream(DeepState_LogInfo, (cond), __FILE__, __LINE__) From 0f9fe27288d162b88492717f98b9861830b12dda Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 14:00:11 -0700 Subject: [PATCH 126/228] handle new logging in symex --- bin/deepstate/common.py | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 59828aa..0797e9d 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -32,11 +32,12 @@ class TestInfo(object): LOG_LEVEL_DEBUG = 0 -LOG_LEVEL_INFO = 1 -LOG_LEVEL_WARNING = 2 -LOG_LEVEL_ERROR = 3 -LOG_LEVEL_EXTERNAL = 4 -LOG_LEVEL_FATAL = 5 +LOG_LEVEL_TRACE = 1 +LOG_LEVEL_INFO = 2 +LOG_LEVEL_WARNING = 3 +LOG_LEVEL_ERROR = 4 +LOG_LEVEL_EXTERNAL = 5 +LOG_LEVEL_FATAL = 6 LOGGER = logging.getLogger("deepstate") @@ -45,6 +46,7 @@ LOGGER.setLevel(logging.DEBUG) LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, + LOG_LEVEL_TRACE: LOGGER.trace, LOG_LEVEL_INFO: LOGGER.info, LOG_LEVEL_WARNING: LOGGER.warning, LOG_LEVEL_ERROR: LOGGER.error, From 816ec7a27dc0c7044ce6198c0ad10e9d8829737e Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 14:12:17 -0700 Subject: [PATCH 127/228] try to add trace level --- bin/deepstate/common.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 0797e9d..633fd37 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -42,7 +42,8 @@ LOG_LEVEL_FATAL = 6 LOGGER = logging.getLogger("deepstate") LOGGER.setLevel(logging.DEBUG) - +LOGGER.addLevelName(15, "TRACE") +LOGGER.trace = 15 LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, From 6f168e8e1c64a99fa36cb0c6f91b436eea7636c0 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 14:16:16 -0700 Subject: [PATCH 128/228] add level name at right place --- bin/deepstate/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 633fd37..bed6e8f 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -14,6 +14,7 @@ import logging logging.basicConfig() +logging.addLevelName(15, "TRACE") import argparse import md5 @@ -42,7 +43,6 @@ LOG_LEVEL_FATAL = 6 LOGGER = logging.getLogger("deepstate") LOGGER.setLevel(logging.DEBUG) -LOGGER.addLevelName(15, "TRACE") LOGGER.trace = 15 LOG_LEVEL_TO_LOGGER = { From feec722f83feeb7d83ad2713b63c00d1224d8e2e Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 14:34:24 -0700 Subject: [PATCH 129/228] handled for TRACE --- bin/deepstate/common.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index bed6e8f..8a8cddc 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -43,7 +43,9 @@ LOG_LEVEL_FATAL = 6 LOGGER = logging.getLogger("deepstate") LOGGER.setLevel(logging.DEBUG) -LOGGER.trace = 15 +def logTrace(msg, *args, **kwargs): + logging.log(15, msg, args, kwargs) +LOGGER.trace = logTrace LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, From 7fb1a04a4aaa2635a47a6d80f064a1b1b68fe008 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 15:22:00 -0700 Subject: [PATCH 130/228] change name --- bin/deepstate/common.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 8a8cddc..a4af86b 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -43,9 +43,9 @@ LOG_LEVEL_FATAL = 6 LOGGER = logging.getLogger("deepstate") LOGGER.setLevel(logging.DEBUG) -def logTrace(msg, *args, **kwargs): +def log_trace(msg, *args, **kwargs): logging.log(15, msg, args, kwargs) -LOGGER.trace = logTrace +LOGGER.trace = log_trace LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, From 55644b534e1f0211ea5f6bbca700791f336ba227 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 19:53:02 -0700 Subject: [PATCH 131/228] set level --- bin/deepstate/main_angr.py | 2 +- bin/deepstate/main_manticore.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/bin/deepstate/main_angr.py b/bin/deepstate/main_angr.py index a35bd58..99891f9 100644 --- a/bin/deepstate/main_angr.py +++ b/bin/deepstate/main_angr.py @@ -20,7 +20,7 @@ import traceback from .common import DeepState, TestInfo L = logging.getLogger("deepstate.angr") -L.setLevel(logging.INFO) +L.setLevel(logging.TRACE) class DeepAngr(DeepState): diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index 26d6672..cd5b8e3 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -33,7 +33,7 @@ from manticore.core.state import TerminateState L = logging.getLogger("deepstate.mcore") -L.setLevel(logging.INFO) +L.setLevel(logging.TRACE) OUR_TERMINATION_REASON = "I DeepState'd it" From 3590a6025c74e41a40503cbd1fd96442f5d82d08 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 20:46:08 -0700 Subject: [PATCH 132/228] add trace to manticore/angr logging --- bin/deepstate/main_angr.py | 6 +++++- bin/deepstate/main_manticore.py | 9 ++++++--- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/bin/deepstate/main_angr.py b/bin/deepstate/main_angr.py index 99891f9..7659fb2 100644 --- a/bin/deepstate/main_angr.py +++ b/bin/deepstate/main_angr.py @@ -19,8 +19,12 @@ import multiprocessing import traceback from .common import DeepState, TestInfo +logging.addLevelName(15, "TRACE") L = logging.getLogger("deepstate.angr") -L.setLevel(logging.TRACE) +def log_trace(msg, *args, **kwargs): + logging.log(15, msg, args, kwargs) +L.TRACE = log_trace +L.setLevel(L.TRACE) class DeepAngr(DeepState): diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index cd5b8e3..e85fab6 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -31,9 +31,12 @@ from .common import DeepState, TestInfo from manticore.core.state import TerminateState - -L = logging.getLogger("deepstate.mcore") -L.setLevel(logging.TRACE) +logging.addLevelName(15, "TRACE") +L = logging.getLogger("deepstate.angr") +def log_trace(msg, *args, **kwargs): + logging.log(15, msg, args, kwargs) +L.TRACE = log_trace +L.setLevel(L.TRACE) OUR_TERMINATION_REASON = "I DeepState'd it" From 276b4936817168d2787af9da88f2c592c4145c30 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 20:49:10 -0700 Subject: [PATCH 133/228] log in manticore/angr --- bin/deepstate/main_angr.py | 2 +- bin/deepstate/main_manticore.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/deepstate/main_angr.py b/bin/deepstate/main_angr.py index 7659fb2..8a52e39 100644 --- a/bin/deepstate/main_angr.py +++ b/bin/deepstate/main_angr.py @@ -23,7 +23,7 @@ logging.addLevelName(15, "TRACE") L = logging.getLogger("deepstate.angr") def log_trace(msg, *args, **kwargs): logging.log(15, msg, args, kwargs) -L.TRACE = log_trace +L.TRACE = 15 L.setLevel(L.TRACE) diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index e85fab6..1aede3c 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -32,10 +32,10 @@ from .common import DeepState, TestInfo from manticore.core.state import TerminateState logging.addLevelName(15, "TRACE") -L = logging.getLogger("deepstate.angr") +L = logging.getLogger("deepstate.manticore") def log_trace(msg, *args, **kwargs): logging.log(15, msg, args, kwargs) -L.TRACE = log_trace +L.TRACE = 15 L.setLevel(L.TRACE) OUR_TERMINATION_REASON = "I DeepState'd it" From 0cb39f540cee763816412576a265e7784c9051ba Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sat, 22 Dec 2018 21:02:40 -0700 Subject: [PATCH 134/228] let people know the seed they used in fuzzing --- src/include/deepstate/DeepState.h | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 2de5644..b86b70c 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -764,7 +764,9 @@ static int DeepState_Fuzz(void) { if (HAS_FLAG_seed) { srand(FLAGS_seed); } else { - srand(time(NULL)); + unsigned int seed = time(NULL); + DeepState_LogFormat(DeepState_LogWarning, "No seed provided; using %u", seed); + srand(seed); } long start = (long)time(NULL); From ce343948e2abe29f06855d6975afc8f02e8fe0ae Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 23 Dec 2018 12:40:47 -0700 Subject: [PATCH 135/228] try different python approach --- bin/deepstate/common.py | 6 +++--- bin/deepstate/main_angr.py | 6 +----- bin/deepstate/main_manticore.py | 6 +----- 3 files changed, 5 insertions(+), 13 deletions(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index a4af86b..90fbc36 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -20,6 +20,7 @@ import argparse import md5 import os import struct +import functools class TestInfo(object): @@ -43,13 +44,12 @@ LOG_LEVEL_FATAL = 6 LOGGER = logging.getLogger("deepstate") LOGGER.setLevel(logging.DEBUG) -def log_trace(msg, *args, **kwargs): +def log_trace(msg, *args, **kwargs) logging.log(15, msg, args, kwargs) -LOGGER.trace = log_trace LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, - LOG_LEVEL_TRACE: LOGGER.trace, + LOG_LEVEL_TRACE: functools.partial(logging.log, 15), LOG_LEVEL_INFO: LOGGER.info, LOG_LEVEL_WARNING: LOGGER.warning, LOG_LEVEL_ERROR: LOGGER.error, diff --git a/bin/deepstate/main_angr.py b/bin/deepstate/main_angr.py index 8a52e39..cbe101a 100644 --- a/bin/deepstate/main_angr.py +++ b/bin/deepstate/main_angr.py @@ -19,12 +19,8 @@ import multiprocessing import traceback from .common import DeepState, TestInfo -logging.addLevelName(15, "TRACE") L = logging.getLogger("deepstate.angr") -def log_trace(msg, *args, **kwargs): - logging.log(15, msg, args, kwargs) -L.TRACE = 15 -L.setLevel(L.TRACE) +L.setLevel(logging.DEBUG) class DeepAngr(DeepState): diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index 1aede3c..b545385 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -31,12 +31,8 @@ from .common import DeepState, TestInfo from manticore.core.state import TerminateState -logging.addLevelName(15, "TRACE") L = logging.getLogger("deepstate.manticore") -def log_trace(msg, *args, **kwargs): - logging.log(15, msg, args, kwargs) -L.TRACE = 15 -L.setLevel(L.TRACE) +L.setLevel(logging.DEBUG) OUR_TERMINATION_REASON = "I DeepState'd it" From 43ddfa895cead4b847c8393a0bb7bb46539917d9 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 23 Dec 2018 12:44:20 -0700 Subject: [PATCH 136/228] oops, remove log_trace def --- bin/deepstate/common.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 90fbc36..741b210 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -44,8 +44,6 @@ LOG_LEVEL_FATAL = 6 LOGGER = logging.getLogger("deepstate") LOGGER.setLevel(logging.DEBUG) -def log_trace(msg, *args, **kwargs) - logging.log(15, msg, args, kwargs) LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, From 6daee3cfa0ce91665b7bc3e266f8f921234880c5 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 23 Dec 2018 12:53:16 -0700 Subject: [PATCH 137/228] try just using the info logger --- bin/deepstate/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 741b210..52599c5 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -47,7 +47,7 @@ LOGGER.setLevel(logging.DEBUG) LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, - LOG_LEVEL_TRACE: functools.partial(logging.log, 15), + LOG_LEVEL_TRACE: LOGGER.info, LOG_LEVEL_INFO: LOGGER.info, LOG_LEVEL_WARNING: LOGGER.warning, LOG_LEVEL_ERROR: LOGGER.error, From 4409762f24d12d3ed83bfc8bde2b14cb3416a84e Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 23 Dec 2018 13:00:25 -0700 Subject: [PATCH 138/228] functools annoys pyflakes --- bin/deepstate/common.py | 1 - 1 file changed, 1 deletion(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 52599c5..453d305 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -20,7 +20,6 @@ import argparse import md5 import os import struct -import functools class TestInfo(object): From 37d9d35d5aa8cf692f517b523e0294832aa81ece Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 23 Dec 2018 13:07:27 -0700 Subject: [PATCH 139/228] aha, used wrong logger --- bin/deepstate/common.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 453d305..c333d41 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -17,6 +17,7 @@ logging.basicConfig() logging.addLevelName(15, "TRACE") import argparse +import functools import md5 import os import struct @@ -46,7 +47,7 @@ LOGGER.setLevel(logging.DEBUG) LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, - LOG_LEVEL_TRACE: LOGGER.info, + LOG_LEVEL_TRACE: functools.partial(LOGGER.log, 15) LOG_LEVEL_INFO: LOGGER.info, LOG_LEVEL_WARNING: LOGGER.warning, LOG_LEVEL_ERROR: LOGGER.error, From fca5c8795b5268208278924369b52f66ff960235 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 23 Dec 2018 13:10:03 -0700 Subject: [PATCH 140/228] fix missing comma --- bin/deepstate/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index c333d41..1ee596b 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -47,7 +47,7 @@ LOGGER.setLevel(logging.DEBUG) LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, - LOG_LEVEL_TRACE: functools.partial(LOGGER.log, 15) + LOG_LEVEL_TRACE: functools.partial(LOGGER.log, 15), LOG_LEVEL_INFO: LOGGER.info, LOG_LEVEL_WARNING: LOGGER.warning, LOG_LEVEL_ERROR: LOGGER.error, From 12c23f78b9a24fb0a7b64c44f0b490c0aeb89bb4 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 23 Dec 2018 13:13:08 -0700 Subject: [PATCH 141/228] restore old manticore/angr code --- bin/deepstate/main_angr.py | 2 +- bin/deepstate/main_manticore.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/bin/deepstate/main_angr.py b/bin/deepstate/main_angr.py index cbe101a..a35bd58 100644 --- a/bin/deepstate/main_angr.py +++ b/bin/deepstate/main_angr.py @@ -20,7 +20,7 @@ import traceback from .common import DeepState, TestInfo L = logging.getLogger("deepstate.angr") -L.setLevel(logging.DEBUG) +L.setLevel(logging.INFO) class DeepAngr(DeepState): diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index b545385..0cf7dd5 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -31,8 +31,8 @@ from .common import DeepState, TestInfo from manticore.core.state import TerminateState -L = logging.getLogger("deepstate.manticore") -L.setLevel(logging.DEBUG) +L = logging.getLogger("deepstate.mcore") +L.setLevel(logging.INFO) OUR_TERMINATION_REASON = "I DeepState'd it" From c91853828dad15dac2f54f11df3cea7cf420f135 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 23 Dec 2018 13:13:59 -0700 Subject: [PATCH 142/228] restore spacing in manticore to avoid confusion --- bin/deepstate/main_manticore.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/deepstate/main_manticore.py b/bin/deepstate/main_manticore.py index 0cf7dd5..26d6672 100644 --- a/bin/deepstate/main_manticore.py +++ b/bin/deepstate/main_manticore.py @@ -31,6 +31,7 @@ from .common import DeepState, TestInfo from manticore.core.state import TerminateState + L = logging.getLogger("deepstate.mcore") L.setLevel(logging.INFO) From 30601a580aebe95f0232a5641145e2249d628de4 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 23 Dec 2018 13:22:48 -0700 Subject: [PATCH 143/228] fix streaming and formatting test --- tests/test_streamingandformatting.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tests/test_streamingandformatting.py b/tests/test_streamingandformatting.py index baca7d0..9c2d889 100644 --- a/tests/test_streamingandformatting.py +++ b/tests/test_streamingandformatting.py @@ -11,10 +11,11 @@ class StreamingAndFormattingTest(deepstate_base.DeepStateTestCase): self.assertTrue("Failed: Streaming_BasicLevels" in output) self.assertTrue("This is a debug message" in output) + self.assertTrue("This is a trace message" in output) self.assertTrue("This is an info message" in output) self.assertTrue("This is a warning message" in output) self.assertTrue("This is a error message" in output) - self.assertTrue("This is a info message again" in output) + self.assertTrue("This is a trace message again" in output) self.assertTrue(": 97" in output) self.assertTrue(": 1" in output) self.assertTrue(": 1.000000" in output) From 54c42c78c968f4416af57a6bda8e3eb2eaeeeec3 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 26 Dec 2018 12:02:59 -0700 Subject: [PATCH 144/228] fix check in reducer --- bin/deepstate/reducer.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/bin/deepstate/reducer.py b/bin/deepstate/reducer.py index 87aa4ae..d8843e6 100644 --- a/bin/deepstate/reducer.py +++ b/bin/deepstate/reducer.py @@ -99,8 +99,9 @@ def main(): currentOneOf.append(-1) elif "Reading byte at" in line: lastRead = int(line.split()[-1]) - if currentOneOf[-1] == -1: - currentOneOf[-1] = lastRead + if len(currentOneOf) > 0: + if currentOneOf[-1] == -1: + currentOneOf[-1] = lastRead elif "FINISHED OneOf CALL" in line: OneOfs.append((currentOneOf[-1], lastRead)) currentOneOf = currentOneOf[:-1] From 6f1f648cd2e0e8a1ee3aead3d305bba3925a226e Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 27 Dec 2018 17:13:53 -0700 Subject: [PATCH 145/228] we can take over rand now --- src/include/deepstate/DeepState.h | 33 +++---------------------------- src/lib/DeepState.c | 33 +++++++++++++++++++++++++++++++ 2 files changed, 36 insertions(+), 30 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index b86b70c..cd977ca 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -48,6 +48,8 @@ #define assume DeepState_Assume #define check DeepState_Check +#define rand DeepState_Int + #define MAYBE(...) \ if (DeepState_Bool()) { \ __VA_ARGS__ ; \ @@ -603,36 +605,7 @@ DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) { return DeepState_TestRunCrash; } -/* Run a test case with input initialized by fuzzing. */ -static enum DeepState_TestRunResult -DeepState_FuzzOneTestCase(struct DeepState_TestInfo *test) { - DeepState_InputIndex = 0; - - for (int i = 0; i < DeepState_InputSize; i++) { - DeepState_Input[i] = (char)rand(); - } - - DeepState_Begin(test); - - enum DeepState_TestRunResult result = DeepState_ForkAndRunTest(test); - - if (result == DeepState_TestRunCrash) { - DeepState_LogFormat(DeepState_LogError, "Crashed: %s", test->test_name); - - if (HAS_FLAG_output_test_dir) { - DeepState_SaveCrashingTest(); - } - - DeepState_Crash(); - } - - if (FLAGS_abort_on_fail && ((result == DeepState_TestRunCrash) || - (result == DeepState_TestRunFail))) { - abort(); - } - - return result; -} +enum DeepState_TestRunResult DeepState_FuzzOneTestCase(struct DeepState_TestInfo *test); /* Run a single saved test case with input initialized from the file * `name` in directory `dir`. */ diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 2871ecb..3c05a18 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -23,6 +23,8 @@ #include #include +#undef rand + DEEPSTATE_BEGIN_EXTERN_C DEFINE_uint(num_workers, 1, @@ -630,6 +632,37 @@ bool DeepState_CatchAbandoned(void) { return DeepState_CurrentTestRun->result == DeepState_TestRunAbandon; } +/* Run a test case with input initialized by fuzzing. + Has to be defined here since we redefine rand in the header. */ +enum DeepState_TestRunResult DeepState_FuzzOneTestCase(struct DeepState_TestInfo *test) { + DeepState_InputIndex = 0; + + for (int i = 0; i < DeepState_InputSize; i++) { + DeepState_Input[i] = (char)rand(); + } + + DeepState_Begin(test); + + enum DeepState_TestRunResult result = DeepState_ForkAndRunTest(test); + + if (result == DeepState_TestRunCrash) { + DeepState_LogFormat(DeepState_LogError, "Crashed: %s", test->test_name); + + if (HAS_FLAG_output_test_dir) { + DeepState_SaveCrashingTest(); + } + + DeepState_Crash(); + } + + if (FLAGS_abort_on_fail && ((result == DeepState_TestRunCrash) || + (result == DeepState_TestRunFail))) { + abort(); + } + + return result; +} + extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { if (Size > sizeof(DeepState_Input)) { return 0; // Just ignore any too-big inputs From ead8c5cb9647e666427061fcc1b6982150188002 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 28 Dec 2018 19:25:47 -0700 Subject: [PATCH 146/228] warn people using srand --- src/include/deepstate/DeepState.h | 61 +++-------------------------- src/lib/DeepState.c | 64 +++++++++++++++++++++++++++++++ 2 files changed, 69 insertions(+), 56 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index cd977ca..73a9166 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -49,6 +49,7 @@ #define check DeepState_Check #define rand DeepState_Int +#define srand DeepState_Warn_srand #define MAYBE(...) \ if (DeepState_Bool()) { \ @@ -447,6 +448,8 @@ static bool DeepState_IsTestCaseFile(const char *name) { return false; } +extern void DeepState_Warn_srand(unsigned int seed); + /* Resets the global `DeepState_Input` buffer, then fills it with the * data found in the file `path`. */ static void DeepState_InitInputFromFile(const char *path) { @@ -605,7 +608,7 @@ DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) { return DeepState_TestRunCrash; } -enum DeepState_TestRunResult DeepState_FuzzOneTestCase(struct DeepState_TestInfo *test); +extern enum DeepState_TestRunResult DeepState_FuzzOneTestCase(struct DeepState_TestInfo *test); /* Run a single saved test case with input initialized from the file * `name` in directory `dir`. */ @@ -730,61 +733,7 @@ static int DeepState_RunSingleSavedTestCase(void) { return num_failed_tests; } -/* Fuzz test `FLAGS_input_which_test` or first test, if not defined. */ -static int DeepState_Fuzz(void) { - DeepState_LogFormat(DeepState_LogInfo, "Starting fuzzing"); - - if (HAS_FLAG_seed) { - srand(FLAGS_seed); - } else { - unsigned int seed = time(NULL); - DeepState_LogFormat(DeepState_LogWarning, "No seed provided; using %u", seed); - srand(seed); - } - - long start = (long)time(NULL); - long current = (long)time(NULL); - long diff = 0; - unsigned i = 0; - - int num_failed_tests = 0; - - struct DeepState_TestInfo *test = NULL; - - DeepState_Setup(); - - for (test = DeepState_FirstTest(); test != NULL; test = test->prev) { - if (HAS_FLAG_input_which_test) { - if (strncmp(FLAGS_input_which_test, test->test_name, strlen(FLAGS_input_which_test)) == 0) { - break; - } - } else { - DeepState_LogFormat(DeepState_LogInfo, - "No test specified, defaulting to last test defined"); - break; - } - } - - if (test == NULL) { - DeepState_LogFormat(DeepState_LogInfo, - "Could not find matching test for %s", - FLAGS_input_which_test); - return 0; - } - - while (diff < FLAGS_timeout) { - i++; - num_failed_tests += DeepState_FuzzOneTestCase(test); - - current = (long)time(NULL); - diff = current-start; - } - - DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests. %d failed tests.", - i, num_failed_tests); - - return num_failed_tests; -} +extern int DeepState_Fuzz(void); /* Run tests from `FLAGS_input_test_files_dir`, under `FLAGS_input_which_test` * or first test, if not defined. */ diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 3c05a18..b8445c2 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -24,6 +24,7 @@ #include #undef rand +#undef srand DEEPSTATE_BEGIN_EXTERN_C @@ -456,6 +457,11 @@ void DrMemFuzzFunc(volatile uint8_t *buff, size_t size) { } } +void DeepState_Warn_srand(unsigned int seed) { + DeepState_LogFormat(DeepState_LogWarning, + "srand under DeepState has no effect: rand is re-defined as DeepState_Int"); +} + void DeepState_RunSavedTakeOverCases(jmp_buf env, struct DeepState_TestInfo *test) { int num_failed_tests = 0; @@ -632,6 +638,64 @@ bool DeepState_CatchAbandoned(void) { return DeepState_CurrentTestRun->result == DeepState_TestRunAbandon; } +/* Fuzz test `FLAGS_input_which_test` or first test, if not defined. + Has to be defined here since we redefine rand in the header. */ +int DeepState_Fuzz(void){ + DeepState_LogFormat(DeepState_LogInfo, "Starting fuzzing"); + + if (HAS_FLAG_seed) { + srand(FLAGS_seed); + } else { + unsigned int seed = time(NULL); + DeepState_LogFormat(DeepState_LogWarning, "No seed provided; using %u", seed); + srand(seed); + } + + long start = (long)time(NULL); + long current = (long)time(NULL); + long diff = 0; + unsigned i = 0; + + int num_failed_tests = 0; + + struct DeepState_TestInfo *test = NULL; + + DeepState_Setup(); + + for (test = DeepState_FirstTest(); test != NULL; test = test->prev) { + if (HAS_FLAG_input_which_test) { + if (strncmp(FLAGS_input_which_test, test->test_name, strlen(FLAGS_input_which_test)) == 0) { + break; + } + } else { + DeepState_LogFormat(DeepState_LogInfo, + "No test specified, defaulting to last test defined"); + break; + } + } + + if (test == NULL) { + DeepState_LogFormat(DeepState_LogInfo, + "Could not find matching test for %s", + FLAGS_input_which_test); + return 0; + } + + while (diff < FLAGS_timeout) { + i++; + num_failed_tests += DeepState_FuzzOneTestCase(test); + + current = (long)time(NULL); + diff = current-start; + } + + DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests. %d failed tests.", + i, num_failed_tests); + + return num_failed_tests; +} + + /* Run a test case with input initialized by fuzzing. Has to be defined here since we redefine rand in the header. */ enum DeepState_TestRunResult DeepState_FuzzOneTestCase(struct DeepState_TestInfo *test) { From 8a7b1c4faa8e9406983ae9355a440d3b2cefef0f Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 30 Dec 2018 12:26:43 -0700 Subject: [PATCH 147/228] stab at string generator --- src/include/deepstate/DeepState.h | 20 +++++++++++- src/lib/DeepState.c | 54 +++++++++++++++++++++++++++++++ 2 files changed, 73 insertions(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 73a9166..aa57282 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -139,9 +139,25 @@ DEEPSTATE_INLINE static int8_t DeepState_MaxChar(int8_t v) { return (int8_t) DeepState_MaxInt(v); } +/* Given a char pointer (assumed to have enough storage), places a string + * value in that location, with size characters (before null). If allowed is + * non-null, chooses characters from allowed char array. If null_terminated + * is true, the string will be null-terminated at size+1, and no prior character + * will be null. For null-terminated strings, storage must have space for the + * null terminator, so size should be 1 less than actual size. */ +extern void DeepState_AssignString(char *dest, size_t max_size, const char* allowed, + size_t allowed_size, int null_terminated); + +/* Returns a null-terminated string of size characters (before null), allocated on + * heap. DeepState will handle freeing these strings at termination of the test. */ +extern char* DeepState_String(size_t max_size); + +/* Function to clean up generated strings, and any other DeepState-managed data. */ +extern void DeepState_CleanUp(); + /* Returns `1` if `expr` is true, and `0` otherwise. This is kind of an indirect * way to take a symbolic value, introduce a fork, and on each size, replace its -* value with a concrete value. */ + * value with a concrete value. */ extern int DeepState_IsTrue(int expr); /* Always returns `1`. */ @@ -588,6 +604,7 @@ DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) { test_pid = fork(); if (!test_pid) { DeepState_RunTest(test); + /* No need to clean up in a fork; exit() is the ultimate garbage collector */ } } int wstatus = 0; @@ -595,6 +612,7 @@ DeepState_ForkAndRunTest(struct DeepState_TestInfo *test) { waitpid(test_pid, &wstatus, 0); } else { wstatus = DeepState_RunTestNoFork(test); + DeepState_CleanUp(); } /* If we exited normally, the status code tells us if the test passed. */ diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index b8445c2..425e80a 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -54,6 +54,11 @@ int DeepState_UsingSymExec = 0; /* Set to 1 when we're using libFuzzer. */ int DeepState_UsingLibFuzzer = 0; +/* Array of DeepState generated strings. Impossible for there to + * be more than there are input bytes. Index stores where we are. */ +char* DeepState_GeneratedStrings[DeepState_InputSize]; +uint32_t DeepState_GeneratedStringsIndex = 0; + /* Pointer to the last registers DeepState_TestInfo data structure */ struct DeepState_TestInfo *DeepState_LastTestInfo = NULL; @@ -311,6 +316,53 @@ int32_t DeepState_MaxInt(int32_t v) { 0x80000000U); } +/* Given a char pointer (assumed to have enough storage), places a string + * value in that location, with size characters (before null). If allowed is + * non-null, chooses characters from allowed char array. If null_terminated + * is true, the string will be null-terminated at size+1, and no prior character + * will be null. For null-terminated strings, storage must have space for the + * null terminator, so size should be 1 less than actual size. */ +void DeepState_AssignString(char *dest, size_t size, const char* allowed, + size_t allowed_size, int null_terminated) { + for(int i = 0; i < size; i++) { + if (allowed) { + size_t index = DeepState_UIntInRange(0, allowed_size); + dest[i] = allowed[index]; + } else if (null_terminated) { + dest[i] = DeepState_UCharInRange(1, UCHAR_MAX); /* Disallow null termination till end. */ + } else { + dest[i] = DeepState_UChar(); + } + } + if (null_terminated) { + dest[size] = 0; + } +} + +/* Returns a null-terminated string of size characters (before null), allocated on + * heap. DeepState will handle freeing these strings at termination of the test. */ +char* DeepState_String(size_t size) { + char* rstr = malloc(size+1); + if (rstr) { + DeepState_GeneratedStrings[DeepState_GeneratedStringsIndex++] = rstr; + for (int i = 0; i < size; i++) { + rstr[i] = DeepState_UCharInRange(1, UCHAR_MAX); /* Disallow null termination till end. */ + } + rstr[size] = 0; + } else { + DeepState_LogFormat(DeepState_LogFatal, "Unable to allocate to generate string!"); + } + return rstr; +} + +/* Function to clean up generated strings, and any other DeepState-managed data. */ +extern void DeepState_CleanUp() { + for (int i = 0; i < DeepState_GeneratedStringsIndex; i++) { + free(DeepState_GeneratedStrings[i]); + } + DeepState_GeneratedStringsIndex = 0; +} + void _DeepState_Assume(int expr, const char *expr_str, const char *file, unsigned line) { if (!expr) { @@ -429,6 +481,7 @@ void DrMemFuzzFunc(volatile uint8_t *buff, size_t size) { #endif /* __cplusplus */ test->test_func(); + DeepState_CleanUp(); DeepState_Pass(); #if defined(__cplusplus) && defined(__cpp_exceptions) @@ -759,6 +812,7 @@ extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { DeepState_Begin(test); enum DeepState_TestRunResult result = DeepState_RunTestNoFork(test); + DeepState_CleanUp(); const char* abort_check = getenv("LIBFUZZER_ABORT_ON_FAIL"); if (abort_check != NULL) { From dee5dd549cbf3e282e2603ca1d303759fff7f1df Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 30 Dec 2018 21:04:15 -0700 Subject: [PATCH 148/228] C++ functions that also vary string length, using Pump --- src/include/deepstate/DeepState.h | 4 ++-- src/include/deepstate/DeepState.hpp | 23 +++++++++++++++++++++-- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index aa57282..5a33970 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -145,12 +145,12 @@ DEEPSTATE_INLINE static int8_t DeepState_MaxChar(int8_t v) { * is true, the string will be null-terminated at size+1, and no prior character * will be null. For null-terminated strings, storage must have space for the * null terminator, so size should be 1 less than actual size. */ -extern void DeepState_AssignString(char *dest, size_t max_size, const char* allowed, +extern void DeepState_AssignString(char *dest, size_t size, const char* allowed, size_t allowed_size, int null_terminated); /* Returns a null-terminated string of size characters (before null), allocated on * heap. DeepState will handle freeing these strings at termination of the test. */ -extern char* DeepState_String(size_t max_size); +extern char* DeepState_String(size_t size); /* Function to clean up generated strings, and any other DeepState-managed data. */ extern void DeepState_CleanUp(); diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index e4c0617..03d14c2 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -314,7 +314,7 @@ static T Pump(T val, unsigned max=10) { } return Minimize(val); } - + template inline static void ForAll(void (*func)(Args...)) { func(Symbolic()...); @@ -345,7 +345,7 @@ inline static char OneOf(const char *str) { } return str[DeepState_IntInRange(0, strlen(str) - 1)]; } - + template inline static const T &OneOf(const std::vector &arr) { if (arr.empty()) { @@ -471,6 +471,25 @@ struct Comparer { } }; +/* Given a char pointer (assumed to have enough storage), places a C string + * value in that location, with up to max_size characters (strlen, not counting + * null). If allowed is non-null, chooses characters from allowed char array. + * If null_terminated is true, the string will be null-terminated at size+1, and + * no prior character will be null. For null-terminated strings, storage must have + * space for the null terminator, so max_size should be 1 less than actual size. */ +inline static void DeepState_AssignCString(char *dest, size_t max_size, const char* allowed, + size_t allowed_size, int null_terminated) { + uint32_t size = DeepState_UIntInRange(0, max_size); + DeepState_AssignString(dest, Pump(size, max_size), allowed, allowed_size, null_terminated); +} + +/* Returns a null-terminated C string of up to max_size characters (strlen), allocated on + * heap. DeepState will handle freeing these strings at termination of the test. */ +inline static char* DeepState_CString(size_t max_size) { + uint32_t size = DeepState_UIntInRange(0, max_size); + return DeepState_String(Pump(size, max_size)); +} + } // namespace deepstate #define ONE_OF ::deepstate::OneOf From 58a1d5120d6fb84bc18dea380cb77c670bb7fa06 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 08:02:09 -0700 Subject: [PATCH 149/228] new string functions --- src/include/deepstate/DeepState.h | 18 +++------- src/include/deepstate/DeepState.hpp | 24 +++++-------- src/lib/DeepState.c | 55 +++++++++-------------------- 3 files changed, 30 insertions(+), 67 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 5a33970..6838ac4 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -139,19 +139,6 @@ DEEPSTATE_INLINE static int8_t DeepState_MaxChar(int8_t v) { return (int8_t) DeepState_MaxInt(v); } -/* Given a char pointer (assumed to have enough storage), places a string - * value in that location, with size characters (before null). If allowed is - * non-null, chooses characters from allowed char array. If null_terminated - * is true, the string will be null-terminated at size+1, and no prior character - * will be null. For null-terminated strings, storage must have space for the - * null terminator, so size should be 1 less than actual size. */ -extern void DeepState_AssignString(char *dest, size_t size, const char* allowed, - size_t allowed_size, int null_terminated); - -/* Returns a null-terminated string of size characters (before null), allocated on - * heap. DeepState will handle freeing these strings at termination of the test. */ -extern char* DeepState_String(size_t size); - /* Function to clean up generated strings, and any other DeepState-managed data. */ extern void DeepState_CleanUp(); @@ -176,6 +163,11 @@ extern void DeepState_SymbolizeData(void *begin, void *end); * concrete pointer to the beginning of the concretized data. */ extern void *DeepState_ConcretizeData(void *begin, void *end); +/* Assign a symbolic C string of length `len` with only chars in allowed, + * if allowed is non-null */ +extern void DeepState_AssignCStr(char* str, size_t len, const char* allowed, + size_t allowed_size); + /* Return a symbolic C string of length `len`. */ extern char *DeepState_CStr(size_t len); diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index 03d14c2..d9f148d 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -471,23 +471,17 @@ struct Comparer { } }; -/* Given a char pointer (assumed to have enough storage), places a C string - * value in that location, with up to max_size characters (strlen, not counting - * null). If allowed is non-null, chooses characters from allowed char array. - * If null_terminated is true, the string will be null-terminated at size+1, and - * no prior character will be null. For null-terminated strings, storage must have - * space for the null terminator, so max_size should be 1 less than actual size. */ -inline static void DeepState_AssignCString(char *dest, size_t max_size, const char* allowed, - size_t allowed_size, int null_terminated) { - uint32_t size = DeepState_UIntInRange(0, max_size); - DeepState_AssignString(dest, Pump(size, max_size), allowed, allowed_size, null_terminated); +/* Like DeepState_AssignCStr, but Pumps through possible string sizes. */ +inline static void DeepState_AssignCStrMax(char* str, size_t max_len, const char* allowed, + size_t allowed_size) { + uint32_t size = DeepState_UIntInRange(0, max_len); + DeepState_AssignCStr(str, Pump(size, max_len), allowed, allowed_size); } -/* Returns a null-terminated C string of up to max_size characters (strlen), allocated on - * heap. DeepState will handle freeing these strings at termination of the test. */ -inline static char* DeepState_CString(size_t max_size) { - uint32_t size = DeepState_UIntInRange(0, max_size); - return DeepState_String(Pump(size, max_size)); +/* Like DeepState_CStr, but Pumps through possible string sizes. */ +inline static char* DeepState_CStrMax(size_t max_len) { + uint32_t size = DeepState_UIntInRange(0, max_len); + return DeepState_CStr(Pump(size, max_len)); } } // namespace deepstate diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 425e80a..6f2860a 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -175,6 +175,21 @@ void *DeepState_ConcretizeData(void *begin, void *end) { return begin; } +/* Assign a symbolic C string of length `len`. */ +void DeepState_AssignCStr(char* str, size_t len, const char* allowed, + size_t allowed_size) { + if (SIZE_MAX == len) { + DeepState_Abandon("Can't create an SIZE_MAX-length string."); + } + if (NULL == str) { + DeepState_Abandon("Attempted to populate null pointer."); + } + for (int i = 0; i < len; i++) { + str[i] = allowed[DeepState_UIntInRange(0, allowed_size)]; + } + str[len] = '\0'; +} + /* Return a symbolic C string of length `len`. */ char *DeepState_CStr(size_t len) { if (SIZE_MAX == len) { @@ -184,6 +199,7 @@ char *DeepState_CStr(size_t len) { if (NULL == str) { DeepState_Abandon("Can't allocate memory."); } + DeepState_GeneratedStrings[DeepState_GeneratedStringsIndex++] = str; if (len) { DeepState_SymbolizeData(str, &(str[len - 1])); } @@ -316,45 +332,6 @@ int32_t DeepState_MaxInt(int32_t v) { 0x80000000U); } -/* Given a char pointer (assumed to have enough storage), places a string - * value in that location, with size characters (before null). If allowed is - * non-null, chooses characters from allowed char array. If null_terminated - * is true, the string will be null-terminated at size+1, and no prior character - * will be null. For null-terminated strings, storage must have space for the - * null terminator, so size should be 1 less than actual size. */ -void DeepState_AssignString(char *dest, size_t size, const char* allowed, - size_t allowed_size, int null_terminated) { - for(int i = 0; i < size; i++) { - if (allowed) { - size_t index = DeepState_UIntInRange(0, allowed_size); - dest[i] = allowed[index]; - } else if (null_terminated) { - dest[i] = DeepState_UCharInRange(1, UCHAR_MAX); /* Disallow null termination till end. */ - } else { - dest[i] = DeepState_UChar(); - } - } - if (null_terminated) { - dest[size] = 0; - } -} - -/* Returns a null-terminated string of size characters (before null), allocated on - * heap. DeepState will handle freeing these strings at termination of the test. */ -char* DeepState_String(size_t size) { - char* rstr = malloc(size+1); - if (rstr) { - DeepState_GeneratedStrings[DeepState_GeneratedStringsIndex++] = rstr; - for (int i = 0; i < size; i++) { - rstr[i] = DeepState_UCharInRange(1, UCHAR_MAX); /* Disallow null termination till end. */ - } - rstr[size] = 0; - } else { - DeepState_LogFormat(DeepState_LogFatal, "Unable to allocate to generate string!"); - } - return rstr; -} - /* Function to clean up generated strings, and any other DeepState-managed data. */ extern void DeepState_CleanUp() { for (int i = 0; i < DeepState_GeneratedStringsIndex; i++) { From abba98ad2a0788d4903930f48c37ce14ebf00fde Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 08:12:03 -0700 Subject: [PATCH 150/228] no need for allowed length --- src/include/deepstate/DeepState.h | 3 +-- src/include/deepstate/DeepState.hpp | 6 +++--- src/lib/DeepState.c | 4 ++-- 3 files changed, 6 insertions(+), 7 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 6838ac4..834d5bb 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -165,8 +165,7 @@ extern void *DeepState_ConcretizeData(void *begin, void *end); /* Assign a symbolic C string of length `len` with only chars in allowed, * if allowed is non-null */ -extern void DeepState_AssignCStr(char* str, size_t len, const char* allowed, - size_t allowed_size); +extern void DeepState_AssignCStr(char* str, size_t len, const char* allowed); /* Return a symbolic C string of length `len`. */ extern char *DeepState_CStr(size_t len); diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index d9f148d..cb27062 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -472,10 +472,10 @@ struct Comparer { }; /* Like DeepState_AssignCStr, but Pumps through possible string sizes. */ -inline static void DeepState_AssignCStrMax(char* str, size_t max_len, const char* allowed, - size_t allowed_size) { +inline static void DeepState_AssignCStrMax(char* str, size_t max_len, + const char* allowed) { uint32_t size = DeepState_UIntInRange(0, max_len); - DeepState_AssignCStr(str, Pump(size, max_len), allowed, allowed_size); + DeepState_AssignCStr(str, Pump(size, max_len), allowed); } /* Like DeepState_CStr, but Pumps through possible string sizes. */ diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 6f2860a..5d81f2b 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -176,14 +176,14 @@ void *DeepState_ConcretizeData(void *begin, void *end) { } /* Assign a symbolic C string of length `len`. */ -void DeepState_AssignCStr(char* str, size_t len, const char* allowed, - size_t allowed_size) { +void DeepState_AssignCStr(char* str, size_t len, const char* allowed) { if (SIZE_MAX == len) { DeepState_Abandon("Can't create an SIZE_MAX-length string."); } if (NULL == str) { DeepState_Abandon("Attempted to populate null pointer."); } + uint32_t allowed_size = strlen(allowed); for (int i = 0; i < len; i++) { str[i] = allowed[DeepState_UIntInRange(0, allowed_size)]; } From efb3c07314d8db15510f8f5f2f2321967bc35f64 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 13:06:01 -0700 Subject: [PATCH 151/228] new interface --- src/include/deepstate/DeepState.h | 6 ++--- src/include/deepstate/DeepState.hpp | 29 +++++++++++++++------ src/lib/DeepState.c | 39 +++++++++++++++++++++++------ 3 files changed, 56 insertions(+), 18 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 834d5bb..82938fa 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -165,13 +165,13 @@ extern void *DeepState_ConcretizeData(void *begin, void *end); /* Assign a symbolic C string of length `len` with only chars in allowed, * if allowed is non-null */ -extern void DeepState_AssignCStr(char* str, size_t len, const char* allowed); +extern void DeepState_AssignCStr_C(char* str, size_t len, const char* allowed); /* Return a symbolic C string of length `len`. */ -extern char *DeepState_CStr(size_t len); +extern char *DeepState_CStr_C(size_t len, const char* allowed); /* Symbolize a C string */ -void DeepState_SymbolizeCStr(char *begin); +void DeepState_SymbolizeCStr_C(char *begin, const char* allowed); /* Concretize a C string. Returns a pointer to the beginning of the * concretized C string. */ diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index cb27062..17468ce 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -471,17 +471,32 @@ struct Comparer { } }; +/* Like DeepState_AssignCStr_C, but fills in a null allowed. */ +inline static void DeepState_AssignCStr(char* str, size_t len, + const char* allowed = 0) { + DeepState_AssignCStr_C(str, len, allowed); +} + /* Like DeepState_AssignCStr, but Pumps through possible string sizes. */ -inline static void DeepState_AssignCStrMax(char* str, size_t max_len, - const char* allowed) { - uint32_t size = DeepState_UIntInRange(0, max_len); - DeepState_AssignCStr(str, Pump(size, max_len), allowed); +inline static void DeepState_AssignCStrUpToLen(char* str, size_t max_len, + const char* allowed = 0) { + uint32_t len = DeepState_UIntInRange(0, max_len); + DeepState_AssignCStr_C(str, Pump(len, max_len), allowed); } +/* Like DeepState_CStr_C, but fills in a null allowed. */ +inline static char* DeepState_CStr(size_t len, char* allowed = 0) { + return DeepState_CStr_C(len, allowed); +} + /* Like DeepState_CStr, but Pumps through possible string sizes. */ -inline static char* DeepState_CStrMax(size_t max_len) { - uint32_t size = DeepState_UIntInRange(0, max_len); - return DeepState_CStr(Pump(size, max_len)); +inline static char* DeepState_CStrUpToLen(size_t max_len, char* allowed = 0) { + uint32_t len = DeepState_UIntInRange(0, max_len); + return DeepState_CStr_C(Pump(len, max_len), allowed); +} + +inline static void DeepState_SymbolizeCStr_C(char *begin, char* allowed = 0) { + DeepState_SymbolizeCStr_C(begin, allowed); } } // namespace deepstate diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 5d81f2b..036c843 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -176,22 +176,28 @@ void *DeepState_ConcretizeData(void *begin, void *end) { } /* Assign a symbolic C string of length `len`. */ -void DeepState_AssignCStr(char* str, size_t len, const char* allowed) { +void DeepState_AssignCStr_C(char* str, size_t len, const char* allowed) { if (SIZE_MAX == len) { DeepState_Abandon("Can't create an SIZE_MAX-length string."); } if (NULL == str) { DeepState_Abandon("Attempted to populate null pointer."); } - uint32_t allowed_size = strlen(allowed); - for (int i = 0; i < len; i++) { - str[i] = allowed[DeepState_UIntInRange(0, allowed_size)]; + if (len) { + if (!allowed) { + DeepState_SymbolizeData(str, &(str[len - 1])); + } else { + uint32_t allowed_size = strlen(allowed); + for (int i = 0; i < len; i++) { + str[i] = allowed[DeepState_UIntInRange(0, allowed_size)]; + } + } } str[len] = '\0'; } /* Return a symbolic C string of length `len`. */ -char *DeepState_CStr(size_t len) { +char *DeepState_CStr_C(size_t len, const char* allowed) { if (SIZE_MAX == len) { DeepState_Abandon("Can't create an SIZE_MAX-length string."); } @@ -201,16 +207,33 @@ char *DeepState_CStr(size_t len) { } DeepState_GeneratedStrings[DeepState_GeneratedStringsIndex++] = str; if (len) { - DeepState_SymbolizeData(str, &(str[len - 1])); + if (!allowed) { + DeepState_SymbolizeData(str, &(str[len - 1])); + } else { + uint32_t allowed_size = strlen(allowed); + for (int i = 0; i < len; i++) { + str[i] = allowed[DeepState_UIntInRange(0, allowed_size)]; + } + } } str[len] = '\0'; return str; } /* Symbolize a C string */ -void DeepState_SymbolizeCStr(char *begin) { +void DeepState_SymbolizeCStr_C(char *begin, const char* allowed) { if (begin && begin[0]) { - DeepState_SymbolizeData(begin, begin + strlen(begin)); + if (!allowed) { + DeepState_SymbolizeData(begin, begin + strlen(begin)); + } else { + uint32_t allowed_size = strlen(allowed); + uint8_t *bytes = (uint8_t *) begin; + uintptr_t begin_addr = (uintptr_t) begin; + uintptr_t end_addr = (uintptr_t) (begin + strlen(begin)); + for (uintptr_t i = 0, max_i = (end_addr - begin_addr); i < max_i; ++i) { + bytes[i] = allowed[DeepState_UIntInRange(0, allowed_size)]; + } + } } } From 943627819ddc4d24c711dd97f2fba21973ba6f8c Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 13:19:57 -0700 Subject: [PATCH 152/228] Fix for new C interface to string generation --- examples/Squares.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Squares.c b/examples/Squares.c index 466ba61..5483512 100644 --- a/examples/Squares.c +++ b/examples/Squares.c @@ -10,7 +10,7 @@ int square(int x) { DeepState_EntryPoint(test_main) { const char *new_args[2]; new_args[0] = "deepstate"; - new_args[1] = DeepState_CStr(8); + new_args[1] = DeepState_CStr_C(8, 0); DeepState_Assert(0 == old_main(2, new_args)); } From 2421a17f5e9b16a5f59f2807119da16492014771 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 13:49:53 -0700 Subject: [PATCH 153/228] add missing const qualifiers --- src/include/deepstate/DeepState.hpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index 17468ce..510cbdc 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -485,17 +485,17 @@ inline static void DeepState_AssignCStrUpToLen(char* str, size_t max_len, } /* Like DeepState_CStr_C, but fills in a null allowed. */ -inline static char* DeepState_CStr(size_t len, char* allowed = 0) { +inline static char* DeepState_CStr(size_t len, const char* allowed = 0) { return DeepState_CStr_C(len, allowed); } /* Like DeepState_CStr, but Pumps through possible string sizes. */ -inline static char* DeepState_CStrUpToLen(size_t max_len, char* allowed = 0) { +inline static char* DeepState_CStrUpToLen(size_t max_len, const char* allowed = 0) { uint32_t len = DeepState_UIntInRange(0, max_len); return DeepState_CStr_C(Pump(len, max_len), allowed); } -inline static void DeepState_SymbolizeCStr_C(char *begin, char* allowed = 0) { +inline static void DeepState_SymbolizeCStr_C(char *begin, const char* allowed = 0) { DeepState_SymbolizeCStr_C(begin, allowed); } From eb1133825a03f4f5fe0943ad002fb9319e082141 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 14:18:01 -0700 Subject: [PATCH 154/228] Add run length example --- examples/CMakeLists.txt | 10 +++++++ examples/Runlen.cpp | 62 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 examples/Runlen.cpp diff --git a/examples/CMakeLists.txt b/examples/CMakeLists.txt index f8e7a21..264bc36 100644 --- a/examples/CMakeLists.txt +++ b/examples/CMakeLists.txt @@ -102,6 +102,16 @@ if (BUILD_LIBFUZZER) set_target_properties(StreamingAndFormatting_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") endif() +add_executable(Runlen Runlen.cpp) +target_link_libraries(Runlen deepstate) + +if (BUILD_LIBFUZZER) + add_executable(Runlen_LF Runlen.cpp) + target_link_libraries(Runlen_LF deepstate_LF) + target_link_libraries (Runlen_LF "-fsanitize=fuzzer,undefined") + set_target_properties(Runlen_LF PROPERTIES COMPILE_DEFINITIONS "LIBFUZZER") +endif() + if (NOT APPLE) add_executable(Squares Squares.c) target_link_libraries(Squares deepstate) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp new file mode 100644 index 0000000..f0a75e1 --- /dev/null +++ b/examples/Runlen.cpp @@ -0,0 +1,62 @@ +#include + +using namespace deepstate; + +char* encode(const char* input) { + unsigned int l = strlen(input); + char* encoded = (char*)malloc((l*2)+1); + if (l == 0) { + encoded[0] = '\0'; + return encoded; + } + unsigned char last = input[0]; + unsigned char current; + int count = 1; + int pos = 0; + for (int i = 1; i < l; i++) { + current = input[i]; + if ((current == last) && (count < 26)) { + count++; + } else { + encoded[pos++] = last; + encoded[pos++] = 64 + count; + last = current; + count = 1; + } + } + encoded[pos++] = last; + encoded[pos++] = 64 + count; + encoded[pos] = '\0'; + return encoded; +} + +char* decode(const char* output) { + unsigned int l = strlen(output); + char* decoded = (char*)malloc(((l/2)*25)+1); + if (l == 0) { + decoded[0] = '\0'; + return decoded; + } + int pos = 0; + unsigned char current; + for (int i = 0; i < l; i++) { + current = output[i++]; + unsigned int count = output[i] - 64; + for (int j = 0; j < count; j++) { + decoded[pos++] = current; + } + } + decoded[pos] = '\0'; + return decoded; +} + +#define MAX_STR_LEN 100 + +TEST(Runlength, EncodeDecode) { + char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcde"); + LOG(TRACE) << "original = `" << original << "`"; + char* encoded = encode(original); + char* roundtrip = decode(encoded); + ASSERT (strncmp(roundtrip, original, MAX_STR_LEN) == 0) << + "encode = `" << encoded << "`, decode(encode) = `" << roundtrip << "`"; +} From 40eb4b011731ba5d4b80b18e4da34bd9fe27513d Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 14:20:15 -0700 Subject: [PATCH 155/228] add runlen test --- .travis.yml | 2 ++ tests/test_runlen.py | 18 ++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 tests/test_runlen.py diff --git a/.travis.yml b/.travis.yml index 2cc49e8..fb8741a 100644 --- a/.travis.yml +++ b/.travis.yml @@ -23,6 +23,7 @@ env: - TASK=ONEOF - TASK=OVERFLOW - TASK=PRIMES +- TASK=RUNLEN - TASK=STREAMINGANDFORMATTING - TASK=TAKEOVER script: @@ -34,6 +35,7 @@ script: - if [ $TASK = KLEE ]; then nosetests tests/test_klee.py ; fi - if [ $TASK = LISTS ]; then nosetests tests/test_lists.py ; fi - if [ $TASK = ONEOF ]; then nosetests tests/test_oneof.py ; fi +- if [ $TASK = RUNLEN ]; then nosetests tests/test_runlen.py ; fi - if [ $TASK = OVERFLOW ]; then nosetests tests/test_overflow.py ; fi - if [ $TASK = PRIMES ]; then nosetests tests/test_primes.py ; fi - if [ $TASK = STREAMINGANDFORMATTING ]; then nosetests tests/test_streamingandformatting.py ; fi diff --git a/tests/test_runlen.py b/tests/test_runlen.py new file mode 100644 index 0000000..a466f13 --- /dev/null +++ b/tests/test_runlen.py @@ -0,0 +1,18 @@ +from __future__ import print_function +import deepstate_base +import logrun + + +class RunlenTest(deepstate_base.DeepStateTestCase): + def run_deepstate(self, deepstate): + (r, output) = logrun.logrun([deepstate, "build/examples/Runlen"], + "deepstate.out", 1800) + self.assertEqual(r, 0) + + self.assertTrue("Passed: Runlength_EncodeDecode" in output) + foundCrashSave = False + for line in output.split("\n"): + if ("Saving input to" in line) and (".crash" in line): + foundCrashSave = True + self.assertTrue(foundCrashSave) + From cd7f6daaf9d3a9c2271b4fcabfe3247db0e9235b Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 14:39:10 -0700 Subject: [PATCH 156/228] change runlen example bug and test --- examples/Runlen.cpp | 8 ++++---- tests/test_runlen.py | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index f0a75e1..41cda29 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -10,7 +10,7 @@ char* encode(const char* input) { return encoded; } unsigned char last = input[0]; - unsigned char current; + unsigned char current = input[0]; int count = 1; int pos = 0; for (int i = 1; i < l; i++) { @@ -25,14 +25,14 @@ char* encode(const char* input) { } } encoded[pos++] = last; - encoded[pos++] = 64 + count; + encoded[pos++] = 65; encoded[pos] = '\0'; return encoded; } char* decode(const char* output) { unsigned int l = strlen(output); - char* decoded = (char*)malloc(((l/2)*25)+1); + char* decoded = (char*)malloc(((l/2)*26)+1); if (l == 0) { decoded[0] = '\0'; return decoded; @@ -50,7 +50,7 @@ char* decode(const char* output) { return decoded; } -#define MAX_STR_LEN 100 +#define MAX_STR_LEN 10 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcde"); diff --git a/tests/test_runlen.py b/tests/test_runlen.py index a466f13..4e7d8d4 100644 --- a/tests/test_runlen.py +++ b/tests/test_runlen.py @@ -10,9 +10,9 @@ class RunlenTest(deepstate_base.DeepStateTestCase): self.assertEqual(r, 0) self.assertTrue("Passed: Runlength_EncodeDecode" in output) - foundCrashSave = False + foundFailSave = False for line in output.split("\n"): - if ("Saving input to" in line) and (".crash" in line): - foundCrashSave = True - self.assertTrue(foundCrashSave) + if ("Saving input to" in line) and (".fail" in line): + foundFailSave = True + self.assertTrue(foundFailSave) From ec31d0b79948ee5fd13ad0436219c8d7ca2324be Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 15:11:10 -0700 Subject: [PATCH 157/228] change the code and input range --- examples/Runlen.cpp | 51 +++++++++++++++------------------------------ 1 file changed, 17 insertions(+), 34 deletions(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 41cda29..547090a 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -3,48 +3,31 @@ using namespace deepstate; char* encode(const char* input) { - unsigned int l = strlen(input); - char* encoded = (char*)malloc((l*2)+1); - if (l == 0) { - encoded[0] = '\0'; - return encoded; - } - unsigned char last = input[0]; - unsigned char current = input[0]; - int count = 1; + char* encoded = (char*)malloc((strlen(input)*2)+1); int pos = 0; - for (int i = 1; i < l; i++) { - current = input[i]; - if ((current == last) && (count < 26)) { - count++; - } else { - encoded[pos++] = last; - encoded[pos++] = 64 + count; - last = current; - count = 1; + if (strlen(input) > 0) { + unsigned char last = input[0]; int count = 1; + for (int i = 1; i < strlen(input); i++) { + if (((unsigned char)input[i] == last) && (count < 26)) + count++; + else { + encoded[pos++] = last; encoded[pos++] = 64 + count; + last = (unsigned char)input[i]; count = 1; + } } + encoded[pos++] = last; encoded[pos++] = 65; } - encoded[pos++] = last; - encoded[pos++] = 65; encoded[pos] = '\0'; return encoded; } char* decode(const char* output) { - unsigned int l = strlen(output); - char* decoded = (char*)malloc(((l/2)*26)+1); - if (l == 0) { - decoded[0] = '\0'; - return decoded; - } + char* decoded = (char*)malloc(((strlen(output))/2)*26); int pos = 0; - unsigned char current; - for (int i = 0; i < l; i++) { - current = output[i++]; - unsigned int count = output[i] - 64; - for (int j = 0; j < count; j++) { - decoded[pos++] = current; - } + if (strlen(output) > 0) { + for (int i = 0; i < strlen(output); i += 2) + for (int j = 0; j < (output[i+1] - 64); j++) + decoded[pos++] = output[i]; } decoded[pos] = '\0'; return decoded; @@ -53,7 +36,7 @@ char* decode(const char* output) { #define MAX_STR_LEN 10 TEST(Runlength, EncodeDecode) { - char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcde"); + char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); LOG(TRACE) << "original = `" << original << "`"; char* encoded = encode(original); char* roundtrip = decode(encoded); From a0ec145b6b33b342874ab63f094742bb39105ce2 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 15:25:43 -0700 Subject: [PATCH 158/228] shrink max string size --- examples/Runlen.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 547090a..049fcb4 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -33,7 +33,8 @@ char* decode(const char* output) { return decoded; } -#define MAX_STR_LEN 10 +// Can be higher if we're using fuzzing, not symbolic execution +#define MAX_STR_LEN 7 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); From 122f5a7b574571dc10788fae6ada5dc4e5aeedb2 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 15:43:18 -0700 Subject: [PATCH 159/228] smaller limit, concretize --- examples/Runlen.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 049fcb4..0c16def 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -34,10 +34,11 @@ char* decode(const char* output) { } // Can be higher if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 7 +#define MAX_STR_LEN 4 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); + DeepState_ConcretizeCStr(original); LOG(TRACE) << "original = `" << original << "`"; char* encoded = encode(original); char* roundtrip = decode(encoded); From 244c3ac3a8a76d3cf1334729f386f0a984af2890 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 15:52:55 -0700 Subject: [PATCH 160/228] Change size, output --- examples/Runlen.cpp | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 0c16def..7a22f0a 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -34,14 +34,12 @@ char* decode(const char* output) { } // Can be higher if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 4 +#define MAX_STR_LEN 5 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); - DeepState_ConcretizeCStr(original); - LOG(TRACE) << "original = `" << original << "`"; char* encoded = encode(original); char* roundtrip = decode(encoded); ASSERT (strncmp(roundtrip, original, MAX_STR_LEN) == 0) << - "encode = `" << encoded << "`, decode(encode) = `" << roundtrip << "`"; + "`" << original << "` ==> `" << encoded << "` ==> `" << roundtrip << "`"; } From 14863f074499150dc41bb304f04a8416fd6c6490 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 16:40:28 -0700 Subject: [PATCH 161/228] Smaller size for manticore --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 7a22f0a..f9bfc78 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -34,7 +34,7 @@ char* decode(const char* output) { } // Can be higher if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 5 +#define MAX_STR_LEN 4 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); From 9c224b4f7b078f9522346031b3ed53d8e8d250ca Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 17:21:19 -0700 Subject: [PATCH 162/228] lower length --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index f9bfc78..836a1e3 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -34,7 +34,7 @@ char* decode(const char* output) { } // Can be higher if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 4 +#define MAX_STR_LEN 3 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); From 1fb617fe616bc449f4558a62df10e659485a22a9 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 18:09:36 -0700 Subject: [PATCH 163/228] increase Pump len --- src/include/deepstate/DeepState.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index 510cbdc..7c6ac8d 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -481,7 +481,7 @@ inline static void DeepState_AssignCStr(char* str, size_t len, inline static void DeepState_AssignCStrUpToLen(char* str, size_t max_len, const char* allowed = 0) { uint32_t len = DeepState_UIntInRange(0, max_len); - DeepState_AssignCStr_C(str, Pump(len, max_len), allowed); + DeepState_AssignCStr_C(str, Pump(len, max_len+1), allowed); } /* Like DeepState_CStr_C, but fills in a null allowed. */ @@ -492,7 +492,7 @@ inline static char* DeepState_CStr(size_t len, const char* allowed = 0) { /* Like DeepState_CStr, but Pumps through possible string sizes. */ inline static char* DeepState_CStrUpToLen(size_t max_len, const char* allowed = 0) { uint32_t len = DeepState_UIntInRange(0, max_len); - return DeepState_CStr_C(Pump(len, max_len), allowed); + return DeepState_CStr_C(Pump(len, max_len+1), allowed); } inline static void DeepState_SymbolizeCStr_C(char *begin, const char* allowed = 0) { From 4d568398715e1dfb5e6ba94432df7e6bb490e27b Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 19:07:45 -0700 Subject: [PATCH 164/228] Shrink for manticore --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 836a1e3..9c4ed68 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -34,7 +34,7 @@ char* decode(const char* output) { } // Can be higher if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 3 +#define MAX_STR_LEN 2 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); From ecb0c8e5cc40a5a4135cc7a8d65f9e479563e82a Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 19:09:36 -0700 Subject: [PATCH 165/228] Increase timeout --- tests/test_runlen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_runlen.py b/tests/test_runlen.py index 4e7d8d4..58789f1 100644 --- a/tests/test_runlen.py +++ b/tests/test_runlen.py @@ -6,7 +6,7 @@ import logrun class RunlenTest(deepstate_base.DeepStateTestCase): def run_deepstate(self, deepstate): (r, output) = logrun.logrun([deepstate, "build/examples/Runlen"], - "deepstate.out", 1800) + "deepstate.out", 2700) self.assertEqual(r, 0) self.assertTrue("Passed: Runlength_EncodeDecode" in output) From c3136f77fd01ec12750f6bb4836b6429b2368e01 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 19:10:09 -0700 Subject: [PATCH 166/228] Back to length 3 --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 9c4ed68..836a1e3 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -34,7 +34,7 @@ char* decode(const char* output) { } // Can be higher if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 2 +#define MAX_STR_LEN 3 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); From d410c0df5ff8b9ab5c48812da0f245bb94c193f8 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 20:00:54 -0700 Subject: [PATCH 167/228] back to 2 for manticore --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 836a1e3..9c4ed68 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -34,7 +34,7 @@ char* decode(const char* output) { } // Can be higher if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 3 +#define MAX_STR_LEN 2 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); From da18a1ae0b3f7540423aabca4ddc6c3efaf36c17 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 22:59:41 -0700 Subject: [PATCH 168/228] more comments --- examples/Runlen.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 9c4ed68..7d92daa 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -2,6 +2,9 @@ using namespace deepstate; +/* Simple, buggy, run-length encoding that creates "human readable" + * encodings by adding 'A'-1 to the count, and splitting at 26 */ + char* encode(const char* input) { char* encoded = (char*)malloc((strlen(input)*2)+1); int pos = 0; @@ -15,7 +18,7 @@ char* encode(const char* input) { last = (unsigned char)input[i]; count = 1; } } - encoded[pos++] = last; encoded[pos++] = 65; + encoded[pos++] = last; encoded[pos++] = 65; // Should be count, not 65! } encoded[pos] = '\0'; return encoded; @@ -33,7 +36,7 @@ char* decode(const char* output) { return decoded; } -// Can be higher if we're using fuzzing, not symbolic execution +// Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution #define MAX_STR_LEN 2 TEST(Runlength, EncodeDecode) { From 00b77202e397f0eb7c2dc6c3c50bdb18f10a359b Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Mon, 31 Dec 2018 23:13:58 -0700 Subject: [PATCH 169/228] fix comment on bug --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 7d92daa..42b86ee 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -18,7 +18,7 @@ char* encode(const char* input) { last = (unsigned char)input[i]; count = 1; } } - encoded[pos++] = last; encoded[pos++] = 65; // Should be count, not 65! + encoded[pos++] = last; encoded[pos++] = 65; // Should be 64 + count } encoded[pos] = '\0'; return encoded; From 7431a9bd1bdf0c8299672750e40e05c877eb102c Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 01:20:09 -0700 Subject: [PATCH 170/228] fix OBOB, increase length since this may be what slowed manticore down --- examples/Runlen.cpp | 2 +- src/lib/DeepState.c | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 42b86ee..235930a 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -37,7 +37,7 @@ char* decode(const char* output) { } // Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 2 +#define MAX_STR_LEN 3 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 036c843..9e17175 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -189,7 +189,7 @@ void DeepState_AssignCStr_C(char* str, size_t len, const char* allowed) { } else { uint32_t allowed_size = strlen(allowed); for (int i = 0; i < len; i++) { - str[i] = allowed[DeepState_UIntInRange(0, allowed_size)]; + str[i] = allowed[DeepState_UIntInRange(0, allowed_size-1)]; } } } @@ -212,7 +212,7 @@ char *DeepState_CStr_C(size_t len, const char* allowed) { } else { uint32_t allowed_size = strlen(allowed); for (int i = 0; i < len; i++) { - str[i] = allowed[DeepState_UIntInRange(0, allowed_size)]; + str[i] = allowed[DeepState_UIntInRange(0, allowed_size-1)]; } } } @@ -231,7 +231,7 @@ void DeepState_SymbolizeCStr_C(char *begin, const char* allowed) { uintptr_t begin_addr = (uintptr_t) begin; uintptr_t end_addr = (uintptr_t) (begin + strlen(begin)); for (uintptr_t i = 0, max_i = (end_addr - begin_addr); i < max_i; ++i) { - bytes[i] = allowed[DeepState_UIntInRange(0, allowed_size)]; + bytes[i] = allowed[DeepState_UIntInRange(0, allowed_size-1)]; } } } From e3bba13fd2f7458cbef5f7f239cb16b2e61a819d Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 08:01:32 -0700 Subject: [PATCH 171/228] Increase timeout for manticore --- tests/test_runlen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_runlen.py b/tests/test_runlen.py index 58789f1..545129a 100644 --- a/tests/test_runlen.py +++ b/tests/test_runlen.py @@ -6,7 +6,7 @@ import logrun class RunlenTest(deepstate_base.DeepStateTestCase): def run_deepstate(self, deepstate): (r, output) = logrun.logrun([deepstate, "build/examples/Runlen"], - "deepstate.out", 2700) + "deepstate.out", 2900) self.assertEqual(r, 0) self.assertTrue("Passed: Runlength_EncodeDecode" in output) From bfa85a09c3009ab7769ba2ee0bbedc1fd68d2bb5 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 12:04:06 -0700 Subject: [PATCH 172/228] bigger alphabet --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 235930a..fe86d0e 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -40,7 +40,7 @@ char* decode(const char* output) { #define MAX_STR_LEN 3 TEST(Runlength, EncodeDecode) { - char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "ab"); + char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcdefghijklmnopqrstuvwxyz0123456789"); char* encoded = encode(original); char* roundtrip = decode(encoded); ASSERT (strncmp(roundtrip, original, MAX_STR_LEN) == 0) << From 46f0eeb4b4ce3c17ba88deb1834ea38bd71c0fa2 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 12:36:31 -0700 Subject: [PATCH 173/228] hex alphabet --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index fe86d0e..c979c05 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -40,7 +40,7 @@ char* decode(const char* output) { #define MAX_STR_LEN 3 TEST(Runlength, EncodeDecode) { - char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcdefghijklmnopqrstuvwxyz0123456789"); + char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcdef0123456789"); char* encoded = encode(original); char* roundtrip = decode(encoded); ASSERT (strncmp(roundtrip, original, MAX_STR_LEN) == 0) << From c67b0329b6e39f253c4e935db49b552e4a0f46b5 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 12:54:59 -0700 Subject: [PATCH 174/228] numeric alphabet --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index c979c05..24546c0 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -40,7 +40,7 @@ char* decode(const char* output) { #define MAX_STR_LEN 3 TEST(Runlength, EncodeDecode) { - char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcdef0123456789"); + char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "0123456789"); char* encoded = encode(original); char* roundtrip = decode(encoded); ASSERT (strncmp(roundtrip, original, MAX_STR_LEN) == 0) << From 71fbb7ac7df58b5ddcc768bf4a20d5ab5c4b8a8c Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 13:03:01 -0700 Subject: [PATCH 175/228] 3 char alphabet --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 24546c0..0d402a7 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -40,7 +40,7 @@ char* decode(const char* output) { #define MAX_STR_LEN 3 TEST(Runlength, EncodeDecode) { - char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "0123456789"); + char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abc"); char* encoded = encode(original); char* roundtrip = decode(encoded); ASSERT (strncmp(roundtrip, original, MAX_STR_LEN) == 0) << From 303159467e4b672c4cdf8a3c0b58b4a901f0b052 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 13:58:59 -0700 Subject: [PATCH 176/228] no alphabet at all --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 0d402a7..3b431ee 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -40,7 +40,7 @@ char* decode(const char* output) { #define MAX_STR_LEN 3 TEST(Runlength, EncodeDecode) { - char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abc"); + char* original = DeepState_CStrUpToLen(MAX_STR_LEN); char* encoded = encode(original); char* roundtrip = decode(encoded); ASSERT (strncmp(roundtrip, original, MAX_STR_LEN) == 0) << From 9ef6c5ea32e3f740c001486a3c34478d1ebb9983 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 14:38:48 -0700 Subject: [PATCH 177/228] different printout --- examples/Runlen.cpp | 27 +++++++++++++++++++++------ 1 file changed, 21 insertions(+), 6 deletions(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 3b431ee..70267b4 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -6,11 +6,12 @@ using namespace deepstate; * encodings by adding 'A'-1 to the count, and splitting at 26 */ char* encode(const char* input) { - char* encoded = (char*)malloc((strlen(input)*2)+1); + unsigned int len = strlen(input); + char* encoded = (char*)malloc((len*2)+1); int pos = 0; if (strlen(input) > 0) { unsigned char last = input[0]; int count = 1; - for (int i = 1; i < strlen(input); i++) { + for (int i = 1; i < len; i++) { if (((unsigned char)input[i] == last) && (count < 26)) count++; else { @@ -25,10 +26,11 @@ char* encode(const char* input) { } char* decode(const char* output) { - char* decoded = (char*)malloc(((strlen(output))/2)*26); + unsigned int len = strlen(output); + char* decoded = (char*)malloc((len/2)*26); int pos = 0; if (strlen(output) > 0) { - for (int i = 0; i < strlen(output); i += 2) + for (int i = 0; i < len; i += 2) for (int j = 0; j < (output[i+1] - 64); j++) decoded[pos++] = output[i]; } @@ -36,6 +38,12 @@ char* decode(const char* output) { return decoded; } +void printBytes(const char* bytes) { + unsigned int len = strlen(bytes); + for (int i = 0; i < len; i++) + LOG(ERROR) << "[" << i << "] = " << (unsigned int)(unsigned char)bytes[i]; +} + // Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution #define MAX_STR_LEN 3 @@ -43,6 +51,13 @@ TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN); char* encoded = encode(original); char* roundtrip = decode(encoded); - ASSERT (strncmp(roundtrip, original, MAX_STR_LEN) == 0) << - "`" << original << "` ==> `" << encoded << "` ==> `" << roundtrip << "`"; + if (!(strncmp(roundtrip, original, MAX_STR_LEN) == 0)) { + LOG(ERROR) << "ORIGINAL:"; + printBytes(original); + LOG(ERROR) << "ENCODED:"; + printBytes(encoded); + LOG(ERROR) << "ROUNDTRIP:"; + printBytes(roundtrip); + ASSERT (0) << "Round trip check failed"; + } } From 31460e7f0d81e5e0e59972da4008464c89cce9b9 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 16:58:31 -0700 Subject: [PATCH 178/228] Don't Pump through sizes, since the functions allow null terminators anyway --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 70267b4..dcfe123 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -48,7 +48,7 @@ void printBytes(const char* bytes) { #define MAX_STR_LEN 3 TEST(Runlength, EncodeDecode) { - char* original = DeepState_CStrUpToLen(MAX_STR_LEN); + char* original = DeepState_CStr(MAX_STR_LEN); char* encoded = encode(original); char* roundtrip = decode(encoded); if (!(strncmp(roundtrip, original, MAX_STR_LEN) == 0)) { From cc2925ffd2cfd001d4faa5196f5a288ab59c7374 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 18:59:25 -0700 Subject: [PATCH 179/228] fix off by one in call to symbolize, and avoid nulls --- examples/Runlen.cpp | 2 +- src/include/deepstate/DeepState.h | 3 +++ src/lib/DeepState.c | 32 ++++++++++++++++++++++++++++--- 3 files changed, 33 insertions(+), 4 deletions(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index dcfe123..70267b4 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -48,7 +48,7 @@ void printBytes(const char* bytes) { #define MAX_STR_LEN 3 TEST(Runlength, EncodeDecode) { - char* original = DeepState_CStr(MAX_STR_LEN); + char* original = DeepState_CStrUpToLen(MAX_STR_LEN); char* encoded = encode(original); char* roundtrip = decode(encoded); if (!(strncmp(roundtrip, original, MAX_STR_LEN) == 0)) { diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 82938fa..b6c102c 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -159,6 +159,9 @@ extern int DeepState_ZeroSink(int); /* Symbolize the data in the exclusive range `[begin, end)`. */ extern void DeepState_SymbolizeData(void *begin, void *end); +/* Symbolize the data in the exclusive range `[begin, end)` with no nulls. */ +extern void DeepState_SymbolizeDataNoNull(void *begin, void *end); + /* Concretize some data in exclusive the range `[begin, end)`. Returns a * concrete pointer to the beginning of the concretized data. */ extern void *DeepState_ConcretizeData(void *begin, void *end); diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 9e17175..38d743a 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -170,6 +170,32 @@ void DeepState_SymbolizeData(void *begin, void *end) { } } +/* Symbolize the data in the exclusive range `[begin, end)`. */ +void DeepState_SymbolizeDataNoNull(void *begin, void *end) { + uintptr_t begin_addr = (uintptr_t) begin; + uintptr_t end_addr = (uintptr_t) end; + + if (begin_addr > end_addr) { + DeepState_Abandon("Invalid data bounds for DeepState_SymbolizeData"); + } else if (begin_addr == end_addr) { + return; + } else { + uint8_t *bytes = (uint8_t *) begin; + for (uintptr_t i = 0, max_i = (end_addr - begin_addr); i < max_i; ++i) { + if (DeepState_InputIndex >= DeepState_InputSize) { + DeepState_Abandon("Read too many symbols"); + } + if (FLAGS_verbose_reads) { + printf("Reading byte at %u\n", DeepState_InputIndex); + } + bytes[i] = DeepState_Input[DeepState_InputIndex++]; + if (bytes[i] == 0) { + bytes[i] = 1; + } + } + } +} + /* Concretize some data in exclusive the range `[begin, end)`. */ void *DeepState_ConcretizeData(void *begin, void *end) { return begin; @@ -185,7 +211,7 @@ void DeepState_AssignCStr_C(char* str, size_t len, const char* allowed) { } if (len) { if (!allowed) { - DeepState_SymbolizeData(str, &(str[len - 1])); + DeepState_SymbolizeDataNoNull(str, &(str[len])); } else { uint32_t allowed_size = strlen(allowed); for (int i = 0; i < len; i++) { @@ -208,7 +234,7 @@ char *DeepState_CStr_C(size_t len, const char* allowed) { DeepState_GeneratedStrings[DeepState_GeneratedStringsIndex++] = str; if (len) { if (!allowed) { - DeepState_SymbolizeData(str, &(str[len - 1])); + DeepState_SymbolizeDataNoNull(str, &(str[len])); } else { uint32_t allowed_size = strlen(allowed); for (int i = 0; i < len; i++) { @@ -224,7 +250,7 @@ char *DeepState_CStr_C(size_t len, const char* allowed) { void DeepState_SymbolizeCStr_C(char *begin, const char* allowed) { if (begin && begin[0]) { if (!allowed) { - DeepState_SymbolizeData(begin, begin + strlen(begin)); + DeepState_SymbolizeDataNoNull(begin, begin + strlen(begin)); } else { uint32_t allowed_size = strlen(allowed); uint8_t *bytes = (uint8_t *) begin; From a6db7fb09700c5677b0a2ed8b58247a79170f655 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 19:52:48 -0700 Subject: [PATCH 180/228] drop manticore for runlen, longer limit --- examples/Runlen.cpp | 2 +- tests/test_runlen.py | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 70267b4..e3957f5 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -45,7 +45,7 @@ void printBytes(const char* bytes) { } // Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 3 +#define MAX_STR_LEN 4 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN); diff --git a/tests/test_runlen.py b/tests/test_runlen.py index 545129a..a378329 100644 --- a/tests/test_runlen.py +++ b/tests/test_runlen.py @@ -5,6 +5,8 @@ import logrun class RunlenTest(deepstate_base.DeepStateTestCase): def run_deepstate(self, deepstate): + if deepstate == "deepstate-manticore": + return # Just skip for now, we know it's too slow (r, output) = logrun.logrun([deepstate, "build/examples/Runlen"], "deepstate.out", 2900) self.assertEqual(r, 0) From 483e827c64f7e40ae7fa23693ca816152114659f Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 21:31:47 -0700 Subject: [PATCH 181/228] up to 6 since only angr --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index e3957f5..b7d12aa 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -45,7 +45,7 @@ void printBytes(const char* bytes) { } // Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 4 +#define MAX_STR_LEN 6 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN); From 6cbb4f479ab09d150dc6b1497085336f05fa518c Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Tue, 1 Jan 2019 22:43:57 -0700 Subject: [PATCH 182/228] note it's STRLEN not length including null, expand Runlen size --- examples/Runlen.cpp | 2 +- src/include/deepstate/DeepState.h | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index b7d12aa..5f9144b 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -45,7 +45,7 @@ void printBytes(const char* bytes) { } // Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 6 +#define MAX_STR_LEN 8 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN); diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index b6c102c..5d29160 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -166,11 +166,11 @@ extern void DeepState_SymbolizeDataNoNull(void *begin, void *end); * concrete pointer to the beginning of the concretized data. */ extern void *DeepState_ConcretizeData(void *begin, void *end); -/* Assign a symbolic C string of length `len` with only chars in allowed, - * if allowed is non-null */ +/* Assign a symbolic C string of _strlen_ `len` -- with only chars in allowed, + * if allowed is non-null; needs space for null + len bytes */ extern void DeepState_AssignCStr_C(char* str, size_t len, const char* allowed); -/* Return a symbolic C string of length `len`. */ +/* Return a symbolic C string of strlen `len`. */ extern char *DeepState_CStr_C(size_t len, const char* allowed); /* Symbolize a C string */ From d40c48efa590367947c4f9d84311ae8e825179b0 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 00:27:52 -0700 Subject: [PATCH 183/228] Shrink size --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 5f9144b..60f3fcb 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -45,7 +45,7 @@ void printBytes(const char* bytes) { } // Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 8 +#define MAX_STR_LEN 7 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN); From 87fcbf3481d36d8d8339b54211418b7668b0714f Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 01:09:13 -0700 Subject: [PATCH 184/228] back to 6 --- examples/Runlen.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 60f3fcb..b7d12aa 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -45,7 +45,7 @@ void printBytes(const char* bytes) { } // Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution -#define MAX_STR_LEN 7 +#define MAX_STR_LEN 6 TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN); From 240eb9f813de925770f7787ea5975bc6ce665d31 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 13:53:15 -0700 Subject: [PATCH 185/228] improve comments --- src/include/deepstate/DeepState.h | 2 +- src/include/deepstate/DeepState.hpp | 7 ++++--- src/lib/DeepState.c | 11 +++++++---- 3 files changed, 12 insertions(+), 8 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 5d29160..8827276 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -167,7 +167,7 @@ extern void DeepState_SymbolizeDataNoNull(void *begin, void *end); extern void *DeepState_ConcretizeData(void *begin, void *end); /* Assign a symbolic C string of _strlen_ `len` -- with only chars in allowed, - * if allowed is non-null; needs space for null + len bytes */ + * if `allowed` is non-null; needs space for null + len bytes */ extern void DeepState_AssignCStr_C(char* str, size_t len, const char* allowed); /* Return a symbolic C string of strlen `len`. */ diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index 7c6ac8d..00bb1d9 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -471,7 +471,7 @@ struct Comparer { } }; -/* Like DeepState_AssignCStr_C, but fills in a null allowed. */ +/* Like DeepState_AssignCStr_C, but fills in a null `allowed` value. */ inline static void DeepState_AssignCStr(char* str, size_t len, const char* allowed = 0) { DeepState_AssignCStr_C(str, len, allowed); @@ -484,7 +484,7 @@ inline static void DeepState_AssignCStrUpToLen(char* str, size_t max_len, DeepState_AssignCStr_C(str, Pump(len, max_len+1), allowed); } -/* Like DeepState_CStr_C, but fills in a null allowed. */ +/* Like DeepState_CStr_C, but fills in a null `allowed` value. */ inline static char* DeepState_CStr(size_t len, const char* allowed = 0) { return DeepState_CStr_C(len, allowed); } @@ -495,7 +495,8 @@ inline static char* DeepState_CStrUpToLen(size_t max_len, const char* allowed = return DeepState_CStr_C(Pump(len, max_len+1), allowed); } -inline static void DeepState_SymbolizeCStr_C(char *begin, const char* allowed = 0) { +/* Like DeepState_Symbolize_CStr, but fills in null `allowed` value. */ +inline static void DeepState_SymbolizeCStr(char *begin, const char* allowed = 0) { DeepState_SymbolizeCStr_C(begin, allowed); } diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 38d743a..794a3c9 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -170,7 +170,8 @@ void DeepState_SymbolizeData(void *begin, void *end) { } } -/* Symbolize the data in the exclusive range `[begin, end)`. */ +/* Symbolize the data in the exclusive range `[begin, end)` without null + * characters included. Primarily useful for C strings. */ void DeepState_SymbolizeDataNoNull(void *begin, void *end) { uintptr_t begin_addr = (uintptr_t) begin; uintptr_t end_addr = (uintptr_t) end; @@ -201,7 +202,9 @@ void *DeepState_ConcretizeData(void *begin, void *end) { return begin; } -/* Assign a symbolic C string of length `len`. */ +/* Assign a symbolic C string of strlen length `len`. str should include + * storage for both `len` characters AND the null terminator. Allowed + * is a set of chars that are allowed (ignored if null). */ void DeepState_AssignCStr_C(char* str, size_t len, const char* allowed) { if (SIZE_MAX == len) { DeepState_Abandon("Can't create an SIZE_MAX-length string."); @@ -222,7 +225,7 @@ void DeepState_AssignCStr_C(char* str, size_t len, const char* allowed) { str[len] = '\0'; } -/* Return a symbolic C string of length `len`. */ +/* Return a symbolic C string of strlen `len`. */ char *DeepState_CStr_C(size_t len, const char* allowed) { if (SIZE_MAX == len) { DeepState_Abandon("Can't create an SIZE_MAX-length string."); @@ -246,7 +249,7 @@ char *DeepState_CStr_C(size_t len, const char* allowed) { return str; } -/* Symbolize a C string */ +/* Symbolize a C string; keeps the null terminator where it was. */ void DeepState_SymbolizeCStr_C(char *begin, const char* allowed) { if (begin && begin[0]) { if (!allowed) { From db8559fe7bedca4cc464f24a9d63e5c3f7d53165 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 14:19:38 -0700 Subject: [PATCH 186/228] fuzzing now defaults to log level INFO, and demotes some messages --- src/include/deepstate/DeepState.h | 4 ++-- src/lib/DeepState.c | 10 +++++----- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 73a9166..ef57123 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -528,7 +528,7 @@ static void DeepState_RunTest(struct DeepState_TestInfo *test) { /* The test passed. */ } else { - DeepState_LogFormat(DeepState_LogInfo, "Passed: %s", test->test_name); + DeepState_LogFormat(DeepState_LogTrace, "Passed: %s", test->test_name); if (HAS_FLAG_output_test_dir) { if (!FLAGS_fuzz || FLAGS_fuzz_save_passing) { DeepState_SavePassingTest(); @@ -572,7 +572,7 @@ static int DeepState_RunTestNoFork(struct DeepState_TestInfo *test) { /* The test passed. */ } else { - DeepState_LogFormat(DeepState_LogInfo, "Passed: %s", test->test_name); + DeepState_LogFormat(DeepState_LogTrace, "Passed: %s", test->test_name); if (HAS_FLAG_output_test_dir) { DeepState_SavePassingTest(); } diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index b8445c2..45b147b 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -44,7 +44,7 @@ DEFINE_bool(fuzz, false, "Perform brute force unguided fuzzing."); DEFINE_bool(fuzz_save_passing, false, "Save passing tests during fuzzing."); DEFINE_bool(fork, true, "Fork when running a test."); -DEFINE_int(log_level, 0, "Minimum level of logging to output."); +DEFINE_int(log_level, 2, "Minimum level of logging to output."); DEFINE_int(seed, 0, "Seed for brute force fuzzing (uses time if not set)."); DEFINE_int(timeout, 120, "Timeout for brute force fuzzing."); @@ -408,7 +408,7 @@ void DeepState_Teardown(void) { /* Notify that we're about to begin a test. */ void DeepState_Begin(struct DeepState_TestInfo *test) { DeepState_InitCurrentTestRun(test); - DeepState_LogFormat(DeepState_LogInfo, "Running: %s from %s(%u)", + DeepState_LogFormat(DeepState_LogTrace, "Running: %s from %s(%u)", test->test_name, test->file_name, test->line_number); } @@ -419,7 +419,7 @@ void DrMemFuzzFunc(volatile uint8_t *buff, size_t size) { struct DeepState_TestInfo *test = DeepState_DrFuzzTest; DeepState_InputIndex = 0; DeepState_InitCurrentTestRun(test); - DeepState_LogFormat(DeepState_LogInfo, "Running: %s from %s(%u)", + DeepState_LogFormat(DeepState_LogTrace, "Running: %s from %s(%u)", test->test_name, test->file_name, test->line_number); if (!setjmp(DeepState_ReturnToRun)) { @@ -450,7 +450,7 @@ void DrMemFuzzFunc(volatile uint8_t *buff, size_t size) { /* The test passed. */ } else { - DeepState_LogFormat(DeepState_LogInfo, "Passed: %s", test->test_name); + DeepState_LogFormat(DeepState_LogTrace, "Passed: %s", test->test_name); if (HAS_FLAG_output_test_dir) { DeepState_SavePassingTest(); } @@ -506,7 +506,7 @@ void DeepState_RunSavedTakeOverCases(jmp_buf env, if (WIFEXITED(wstatus)) { switch (DeepState_CurrentTestRun->result) { case DeepState_TestRunPass: - DeepState_LogFormat(DeepState_LogInfo, + DeepState_LogFormat(DeepState_LogTrace, "Passed: TakeOver test with data from `%s`", dp->d_name); break; From 51d8518c51210ceeb34573b31cfc869a7f37e8af Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 14:59:49 -0700 Subject: [PATCH 187/228] log level should default 0, but be raised for fuzzing unless specified --- src/lib/DeepState.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 45b147b..bdd06de 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -44,7 +44,7 @@ DEFINE_bool(fuzz, false, "Perform brute force unguided fuzzing."); DEFINE_bool(fuzz_save_passing, false, "Save passing tests during fuzzing."); DEFINE_bool(fork, true, "Fork when running a test."); -DEFINE_int(log_level, 2, "Minimum level of logging to output."); +DEFINE_int(log_level, 0, "Minimum level of logging to output."); DEFINE_int(seed, 0, "Seed for brute force fuzzing (uses time if not set)."); DEFINE_int(timeout, 120, "Timeout for brute force fuzzing."); From c9f4d1b9b807676310e7ae9179af99e726c0ee02 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 15:23:23 -0700 Subject: [PATCH 188/228] change log level when fuzzing if not specified --- src/lib/DeepState.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index b8445c2..fafeb3c 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -642,6 +642,10 @@ bool DeepState_CatchAbandoned(void) { Has to be defined here since we redefine rand in the header. */ int DeepState_Fuzz(void){ DeepState_LogFormat(DeepState_LogInfo, "Starting fuzzing"); + + if (!HAS_FLAG_log_level) { + FLAGS_log_level = 2; + } if (HAS_FLAG_seed) { srand(FLAGS_seed); From 8171e3c4604abd4104117cb7905cfd900ac55ddf Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 15:37:19 -0700 Subject: [PATCH 189/228] start on symex logging changes --- bin/deepstate/common.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 1ee596b..c649249 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -137,8 +137,12 @@ class DeepState(object): parser.add_argument( "--verbosity", default=1, type=int, - help="Verbosity level.") + help="Verbosity level for symbolic execution tool.") + parser.add_argument( + "--log_level", default=2, type=int, + help="Log level (DeepState logging).") + parser.add_argument( "binary", type=str, help="Path to the test binary to run.") @@ -240,7 +244,7 @@ class DeepState(object): self.context['stream_{}'.format(level)] = [] self.context['info'] = info - self.log_message(LOG_LEVEL_INFO, "Running {} from {}({})".format( + self.log_message(LOG_LEVEL_TRACE, "Running {} from {}({})".format( info.name, info.file_name, info.line_number)) apis = self.context['apis'] @@ -385,7 +389,7 @@ class DeepState(object): # Print out the first few input bytes to be helpful. lots_of_bytes = len(input_bytes) > 20 and " ..." or "" bytes_to_show = min(20, len(input_bytes)) - LOGGER.info("Input: {}{}".format( + LOGGER.trace("Input: {}{}".format( " ".join("{:02x}".format(b) for b in input_bytes[:bytes_to_show]), lots_of_bytes)) @@ -494,7 +498,7 @@ class DeepState(object): self.api_fail() else: info = self.context['info'] - self.log_message(LOG_LEVEL_INFO, "Passed: {}".format(info.name)) + self.log_message(LOG_LEVEL_TRACE, "Passed: {}".format(info.name)) self.pass_test() def api_crash(self): From b449111ecfec6a619f49cf3576e132146dc79a7c Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 16:08:48 -0700 Subject: [PATCH 190/228] set default log level in symex --- bin/deepstate/common.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index c649249..9eefc6f 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -260,6 +260,17 @@ class DeepState(object): # Create the output directory for this test case. args = self.parse_args() + + logging_levels = { + LOG_LEVEL_DEBUG: logging.DEBUG, + LOG_LEVEL_TRACE: logging.TRACE, + LOG_LEVEL_INFO: logging.INFO, + LOG_LEVEL_WARNING: logging.WARNING, + LOG_LEVEL_ERROR: logging.ERROR, + LOG_LEVEL_FATAL: logging.CRITICAL + } + LOGGER.setLevel(logging_levels[args.log_level]) + if args.output_test_dir is not None: test_dir = os.path.join(args.output_test_dir, os.path.basename(info.file_name), From 1bfaeaac68b0bc9e97060bdfb1f67a806cb07a23 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 16:13:19 -0700 Subject: [PATCH 191/228] assign LOGGING.trace --- bin/deepstate/common.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 9eefc6f..cef7216 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -45,9 +45,11 @@ LOG_LEVEL_FATAL = 6 LOGGER = logging.getLogger("deepstate") LOGGER.setLevel(logging.DEBUG) +LOGGER.trace = functools.partial(LOGGER.log, 15) + LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, - LOG_LEVEL_TRACE: functools.partial(LOGGER.log, 15), + LOG_LEVEL_TRACE: LOGGER.trace, LOG_LEVEL_INFO: LOGGER.info, LOG_LEVEL_WARNING: LOGGER.warning, LOG_LEVEL_ERROR: LOGGER.error, From 16de1bc68cd5e4000a22d11bedf692ba8ffbb730 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 16:15:08 -0700 Subject: [PATCH 192/228] assign logging.TRACE --- bin/deepstate/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index cef7216..9b71f70 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -46,6 +46,7 @@ LOGGER = logging.getLogger("deepstate") LOGGER.setLevel(logging.DEBUG) LOGGER.trace = functools.partial(LOGGER.log, 15) +logging.TRACE = 15 LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, From caa3d33429932ff93632c6ead9f100fc6fbcf564 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 15:23:23 -0700 Subject: [PATCH 193/228] change log level when fuzzing if not specified --- src/lib/DeepState.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index bdd06de..ecd3b98 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -642,6 +642,10 @@ bool DeepState_CatchAbandoned(void) { Has to be defined here since we redefine rand in the header. */ int DeepState_Fuzz(void){ DeepState_LogFormat(DeepState_LogInfo, "Starting fuzzing"); + + if (!HAS_FLAG_log_level) { + FLAGS_log_level = 2; + } if (HAS_FLAG_seed) { srand(FLAGS_seed); From 4bc1a3c00decb4fb889f2e4bc8ba19527836728e Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 15:37:19 -0700 Subject: [PATCH 194/228] start on symex logging changes --- bin/deepstate/common.py | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 1ee596b..c649249 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -137,8 +137,12 @@ class DeepState(object): parser.add_argument( "--verbosity", default=1, type=int, - help="Verbosity level.") + help="Verbosity level for symbolic execution tool.") + parser.add_argument( + "--log_level", default=2, type=int, + help="Log level (DeepState logging).") + parser.add_argument( "binary", type=str, help="Path to the test binary to run.") @@ -240,7 +244,7 @@ class DeepState(object): self.context['stream_{}'.format(level)] = [] self.context['info'] = info - self.log_message(LOG_LEVEL_INFO, "Running {} from {}({})".format( + self.log_message(LOG_LEVEL_TRACE, "Running {} from {}({})".format( info.name, info.file_name, info.line_number)) apis = self.context['apis'] @@ -385,7 +389,7 @@ class DeepState(object): # Print out the first few input bytes to be helpful. lots_of_bytes = len(input_bytes) > 20 and " ..." or "" bytes_to_show = min(20, len(input_bytes)) - LOGGER.info("Input: {}{}".format( + LOGGER.trace("Input: {}{}".format( " ".join("{:02x}".format(b) for b in input_bytes[:bytes_to_show]), lots_of_bytes)) @@ -494,7 +498,7 @@ class DeepState(object): self.api_fail() else: info = self.context['info'] - self.log_message(LOG_LEVEL_INFO, "Passed: {}".format(info.name)) + self.log_message(LOG_LEVEL_TRACE, "Passed: {}".format(info.name)) self.pass_test() def api_crash(self): From 9f8f0f0a418470a0e5adb22d7e3acbc8a7cf9088 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 16:08:48 -0700 Subject: [PATCH 195/228] set default log level in symex --- bin/deepstate/common.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index c649249..9eefc6f 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -260,6 +260,17 @@ class DeepState(object): # Create the output directory for this test case. args = self.parse_args() + + logging_levels = { + LOG_LEVEL_DEBUG: logging.DEBUG, + LOG_LEVEL_TRACE: logging.TRACE, + LOG_LEVEL_INFO: logging.INFO, + LOG_LEVEL_WARNING: logging.WARNING, + LOG_LEVEL_ERROR: logging.ERROR, + LOG_LEVEL_FATAL: logging.CRITICAL + } + LOGGER.setLevel(logging_levels[args.log_level]) + if args.output_test_dir is not None: test_dir = os.path.join(args.output_test_dir, os.path.basename(info.file_name), From 8ef1bd6af8b95f6fc860400db5debde3ff79fcb8 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 16:13:19 -0700 Subject: [PATCH 196/228] assign LOGGING.trace --- bin/deepstate/common.py | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 9eefc6f..cef7216 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -45,9 +45,11 @@ LOG_LEVEL_FATAL = 6 LOGGER = logging.getLogger("deepstate") LOGGER.setLevel(logging.DEBUG) +LOGGER.trace = functools.partial(LOGGER.log, 15) + LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, - LOG_LEVEL_TRACE: functools.partial(LOGGER.log, 15), + LOG_LEVEL_TRACE: LOGGER.trace, LOG_LEVEL_INFO: LOGGER.info, LOG_LEVEL_WARNING: LOGGER.warning, LOG_LEVEL_ERROR: LOGGER.error, From e65adca27b9ce07da1892732dfc3e0f45f8cf392 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 16:15:08 -0700 Subject: [PATCH 197/228] assign logging.TRACE --- bin/deepstate/common.py | 1 + 1 file changed, 1 insertion(+) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index cef7216..9b71f70 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -46,6 +46,7 @@ LOGGER = logging.getLogger("deepstate") LOGGER.setLevel(logging.DEBUG) LOGGER.trace = functools.partial(LOGGER.log, 15) +logging.TRACE = 15 LOG_LEVEL_TO_LOGGER = { LOG_LEVEL_DEBUG: LOGGER.debug, From 9e99978043899dda119ce68c8f58f5891aab7271 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 18:17:15 -0700 Subject: [PATCH 198/228] tests are verbose for debugging and checking output --- tests/logrun.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/logrun.py b/tests/logrun.py index 3c9c5c4..23be692 100644 --- a/tests/logrun.py +++ b/tests/logrun.py @@ -9,7 +9,7 @@ def logrun(cmd, file, timeout): sys.stderr.write(" ".join(cmd) + "\n\n") sys.stderr.flush() with open(file, 'w') as outf: - p = subprocess.Popen(cmd, stdout=outf, stderr=outf) + p = subprocess.Popen(cmd + ["--log_level", "1"], stdout=outf, stderr=outf) start = time.time() oldContents = "" lastOutput = time.time() From fec2849bfbecabde315c5a3bef8b2971d02cc51e Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 20:16:09 -0700 Subject: [PATCH 199/228] Fix logging level in logrun, demote assumption checks --- src/include/deepstate/DeepState.h | 2 +- src/include/deepstate/DeepState.hpp | 4 ++-- tests/logrun.py | 3 ++- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index ef57123..3364433 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -486,7 +486,7 @@ static void DeepState_InitInputFromFile(const char *path) { DeepState_Abandon("Error reading file"); } - DeepState_LogFormat(DeepState_LogInfo, + DeepState_LogFormat(DeepState_LogTrace, "Initialized test input buffer with data from `%s`", path); } diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index e4c0617..f895550 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -584,11 +584,11 @@ struct Comparer { #define ASSUME(expr) \ DeepState_Assume(expr), ::deepstate::Stream( \ - DeepState_LogInfo, true, __FILE__, __LINE__) + DeepState_LogTrace, true, __FILE__, __LINE__) #define DEEPSTATE_ASSUME_BINOP(a, b, op) \ DeepState_Assume((a op b)), ::deepstate::Stream( \ - DeepState_LogInfo, true, __FILE__, __LINE__) + DeepState_LogTrace, true, __FILE__, __LINE__) #define ASSUME_EQ(a, b) DEEPSTATE_ASSUME_BINOP(a, b, ==) #define ASSUME_NE(a, b) DEEPSTATE_ASSUME_BINOP(a, b, !=) diff --git a/tests/logrun.py b/tests/logrun.py index 23be692..cd5926f 100644 --- a/tests/logrun.py +++ b/tests/logrun.py @@ -9,7 +9,8 @@ def logrun(cmd, file, timeout): sys.stderr.write(" ".join(cmd) + "\n\n") sys.stderr.flush() with open(file, 'w') as outf: - p = subprocess.Popen(cmd + ["--log_level", "1"], stdout=outf, stderr=outf) + # We need to set log_level so we see ALL messages, for testing + p = subprocess.Popen(cmd + ["--log_level", "0"], stdout=outf, stderr=outf) start = time.time() oldContents = "" lastOutput = time.time() From 8a5d681c16ef700b5948dc5b00e2807ac67f1434 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Wed, 2 Jan 2019 20:50:53 -0700 Subject: [PATCH 200/228] temp fix --- src/include/deepstate/DeepState.h | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index ef57123..8bc925e 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -48,8 +48,10 @@ #define assume DeepState_Assume #define check DeepState_Check +#ifdef DEEPSTATE_TAKEOVER_RAND #define rand DeepState_Int #define srand DeepState_Warn_srand +#endif #define MAYBE(...) \ if (DeepState_Bool()) { \ From 1247ac64a26137f86efd48ee776d51278bab2c86 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 00:30:28 -0700 Subject: [PATCH 201/228] fix random range issue --- src/include/deepstate/DeepState.h | 3 ++- src/lib/DeepState.c | 6 ++++++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 8bc925e..183d323 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -49,7 +49,7 @@ #define check DeepState_Check #ifdef DEEPSTATE_TAKEOVER_RAND -#define rand DeepState_Int +#define rand DeepState_RandInt #define srand DeepState_Warn_srand #endif @@ -96,6 +96,7 @@ extern uint64_t DeepState_UInt64(void); extern int64_t DeepState_Int64(void); extern uint32_t DeepState_UInt(void); extern int32_t DeepState_Int(void); +extern int32_t DeepState_RandInt(void); extern uint16_t DeepState_UShort(void); extern int16_t DeepState_Short(void); extern uint8_t DeepState_UChar(void); diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index bdd06de..411583a 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -23,8 +23,10 @@ #include #include +#ifdef DEEPSTATE_TAKEOVER_RAND #undef rand #undef srand +#endif DEEPSTATE_BEGIN_EXTERN_C @@ -289,6 +291,10 @@ int8_t DeepState_Char(void) { #undef MAKE_SYMBOL_FUNC +int32_t DeepState_RandInt() { + return DeepState_IntInRange(0, RAND_MAX); +} + /* Returns the minimum satisfiable value for a given symbolic value, given * the constraints present on that value. */ uint32_t DeepState_MinUInt(uint32_t v) { From 652d6355b2a2a6362cd9979f852ab651273c5814 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 11:59:55 -0700 Subject: [PATCH 202/228] More silent: nothing about test failures --- bin/deepstate/common.py | 8 +++++++- src/lib/DeepState.c | 14 +++++++++----- 2 files changed, 16 insertions(+), 6 deletions(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index 9b71f70..bdb3c5e 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -359,21 +359,27 @@ class DeepState(object): test_dir = self.context['test_dir'] test_name = md5.new(input_bytes).hexdigest() + passing = False if self.context['failed']: test_name += ".fail" elif self.context['crashed']: test_name += ".crash" else: test_name += ".pass" + passing = True test_file = os.path.join(test_dir, test_name) - LOGGER.info("Saving input to {}".format(test_file)) try: with open(test_file, "wb") as f: f.write(input_bytes) except: LOGGER.critical("Error saving input to {}".format(test_file)) + if not passing: + LOGGER.info("Saved test case in file {}".format(test_file)) + else: + LOGGER.trace("Saved test case in file {}}".format(test_file)) + def report(self): """Report on the pass/fail status of a test case, and dump its log.""" info = self.context['info'] diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index ecd3b98..3807fd3 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -576,7 +576,7 @@ void makeFilename(char *name, size_t size) { } } -void writeInputData(char* name) { +void writeInputData(char* name, int important) { size_t path_len = 2 + sizeof(char) * (strlen(FLAGS_output_test_dir) + strlen(name)); char *path = (char *) malloc(path_len); snprintf(path, path_len, "%s/%s", FLAGS_output_test_dir, name); @@ -590,7 +590,11 @@ void writeInputData(char* name) { if (written != DeepState_InputSize) { DeepState_LogFormat(DeepState_LogError, "Failed to write to file `%s`", path); } else { - DeepState_LogFormat(DeepState_LogInfo, "Saved test case to file `%s`", path); + if (important) { + DeepState_LogFormat(DeepState_LogInfo, "Saved test case in file `%s`", path); + } else { + DeepState_LogFormat(DeepState_LogTrace, "Saved test case in file `%s`", path); + } } free(path); fclose(fp); @@ -602,7 +606,7 @@ void DeepState_SavePassingTest(void) { makeFilename(name, 40); name[40] = 0; strncat(name, ".pass", 48); - writeInputData(name); + writeInputData(name, 0); } /* Save a failing test to the output test directory. */ @@ -611,7 +615,7 @@ void DeepState_SaveFailingTest(void) { makeFilename(name, 40); name[40] = 0; strncat(name, ".fail", 48); - writeInputData(name); + writeInputData(name, 1); } /* Save a crashing test to the output test directory. */ @@ -620,7 +624,7 @@ void DeepState_SaveCrashingTest(void) { makeFilename(name, 40); name[40] = 0; strncat(name, ".crash", 48); - writeInputData(name); + writeInputData(name, 1); } /* Return the first test case to run. */ From dec77fd926f12ed9e489c7c771afb9b517676351 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 12:03:25 -0700 Subject: [PATCH 203/228] more quiet --- bin/deepstate/common.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/bin/deepstate/common.py b/bin/deepstate/common.py index bdb3c5e..0004514 100644 --- a/bin/deepstate/common.py +++ b/bin/deepstate/common.py @@ -378,7 +378,7 @@ class DeepState(object): if not passing: LOGGER.info("Saved test case in file {}".format(test_file)) else: - LOGGER.trace("Saved test case in file {}}".format(test_file)) + LOGGER.trace("Saved test case in file {}".format(test_file)) def report(self): """Report on the pass/fail status of a test case, and dump its log.""" From 2b6e57b1e121e3fa97960cf5fd64086fa6726391 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 12:11:30 -0700 Subject: [PATCH 204/228] change FATAL to CRITICAL to match Python --- src/lib/Log.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/Log.c b/src/lib/Log.c index b352df1..78fe32f 100644 --- a/src/lib/Log.c +++ b/src/lib/Log.c @@ -58,7 +58,7 @@ static const char *DeepState_LogLevelStr(enum DeepState_LogLevel level) { case DeepState_LogExternal: return "EXTERNAL"; case DeepState_LogFatal: - return "FATAL"; + return "CRITICAL"; default: return "UNKNOWN"; } From 3133540027cec436ebfd30cea4928e6fda19d799 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 12:56:35 -0700 Subject: [PATCH 205/228] fix various messages in DeepState to be more helpful and consistent --- src/include/deepstate/DeepState.h | 11 +++++++---- src/lib/DeepState.c | 23 ++++++++++++++++++----- 2 files changed, 25 insertions(+), 9 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 3364433..cbac2a2 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -705,8 +705,9 @@ static int DeepState_RunSingleSavedTestCase(void) { break; } } else { - DeepState_LogFormat(DeepState_LogInfo, - "No test specified, defaulting to first test"); + DeepState_LogFormat(DeepState_LogWarning, + "No test specified, defaulting to last test defined (%s)", + test->test_name); break; } } @@ -749,8 +750,10 @@ static int DeepState_RunSingleSavedTestDir(void) { break; } } else { - DeepState_LogFormat(DeepState_LogInfo, - "No test specified, defaulting to last test defined"); + DeepState_LogFormat(DeepState_LogWarning, + "No test specified, defaulting to last test defined (%s)", + test->test_name); + ; break; } } diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 3807fd3..90740de 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -661,8 +661,8 @@ int DeepState_Fuzz(void){ long start = (long)time(NULL); long current = (long)time(NULL); - long diff = 0; - unsigned i = 0; + unsigned diff = 0; + unsigned int i = 0; int num_failed_tests = 0; @@ -676,8 +676,9 @@ int DeepState_Fuzz(void){ break; } } else { - DeepState_LogFormat(DeepState_LogInfo, - "No test specified, defaulting to last test defined"); + DeepState_LogFormat(DeepState_LogWarning, + "No test specified, defaulting to last test defined (%s)", + test->test_name); break; } } @@ -691,13 +692,25 @@ int DeepState_Fuzz(void){ while (diff < FLAGS_timeout) { i++; + if ((i > 1) && ((i & (i - 1)) == 0)) { + if (diff > 1) { + DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests in %u seconds. %d failed tests so far.", + i, diff, num_failed_tests); + } else if (diff == 1) { + DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests in %u second. %d failed tests so far.", + i, diff, num_failed_tests); + } else { + DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests in < 1 second. %d failed tests so far.", + i, diff, num_failed_tests); + } + } num_failed_tests += DeepState_FuzzOneTestCase(test); current = (long)time(NULL); diff = current-start; } - DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests. %d failed tests.", + DeepState_LogFormat(DeepState_LogInfo, "Done fuzzing! Ran %u tests. %d failed tests.", i, num_failed_tests); return num_failed_tests; From 63952ff0679444012122fc7cf2b91201279d5d4d Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 12:58:42 -0700 Subject: [PATCH 206/228] fix output check in tests --- tests/test_crash.py | 2 +- tests/test_takeover.py | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/test_crash.py b/tests/test_crash.py index 5b53f83..f00b5e4 100644 --- a/tests/test_crash.py +++ b/tests/test_crash.py @@ -12,7 +12,7 @@ class CrashTest(deepstate_base.DeepStateTestCase): self.assertTrue("Passed: Crash_SegFault" in output) foundCrashSave = False for line in output.split("\n"): - if ("Saving input to" in line) and (".crash" in line): + if ("Saved test case" in line) and (".crash" in line): foundCrashSave = True self.assertTrue(foundCrashSave) diff --git a/tests/test_takeover.py b/tests/test_takeover.py index 94e39f0..e824f54 100644 --- a/tests/test_takeover.py +++ b/tests/test_takeover.py @@ -15,6 +15,6 @@ class TakeOverTest(deepstate_base.DeepStateTestCase): foundPassSave = False for line in output.split("\n"): - if ("Saving input to" in line) and (".pass" in line): + if ("Saved test case" in line) and (".pass" in line): foundPassSave = True self.assertTrue(foundPassSave) From 68307c11113d2a28238d60f4497c85c6be40e2f5 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 13:23:30 -0700 Subject: [PATCH 207/228] Much nicer fuzzer output with status updates --- src/lib/DeepState.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 90740de..0ef3291 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -689,20 +689,15 @@ int DeepState_Fuzz(void){ FLAGS_input_which_test); return 0; } + + unsigned int last_status = 0; while (diff < FLAGS_timeout) { i++; - if ((i > 1) && ((i & (i - 1)) == 0)) { - if (diff > 1) { - DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests in %u seconds. %d failed tests so far.", - i, diff, num_failed_tests); - } else if (diff == 1) { - DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests in %u second. %d failed tests so far.", - i, diff, num_failed_tests); - } else { - DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests in < 1 second. %d failed tests so far.", - i, diff, num_failed_tests); - } + if ((diff != last_status) && ((diff % 30) == 0) ) { + DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests in %u seconds (%u tests/second). %d failed tests so far.", + i, diff, i/diff, num_failed_tests); + last_status = diff; } num_failed_tests += DeepState_FuzzOneTestCase(test); @@ -710,8 +705,8 @@ int DeepState_Fuzz(void){ diff = current-start; } - DeepState_LogFormat(DeepState_LogInfo, "Done fuzzing! Ran %u tests. %d failed tests.", - i, num_failed_tests); + DeepState_LogFormat(DeepState_LogInfo, "Done fuzzing! Ran %u tests (%u tests/second). %d failed tests.", + i, i/diff, num_failed_tests); return num_failed_tests; } From 80e285a3bc13b14a1bfbbf278881520e62074f2c Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 14:29:55 -0700 Subject: [PATCH 208/228] Change fuzzing status to timestamped speed and failure count --- src/include/deepstate/DeepState.h | 4 ++-- src/include/deepstate/DeepState.hpp | 8 ++++---- src/lib/DeepState.c | 16 +++++++++------- 3 files changed, 15 insertions(+), 13 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index cbac2a2..af2ef28 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -773,7 +773,7 @@ static int DeepState_RunSingleSavedTestDir(void) { dir_fd = opendir(FLAGS_input_test_files_dir); if (dir_fd == NULL) { DeepState_LogFormat(DeepState_LogInfo, - "No tests to run."); + "No tests to run"); return 0; } @@ -825,7 +825,7 @@ static int DeepState_RunSavedTestCases(void) { /* Start DeepState and run the tests. Returns the number of failed tests. */ static int DeepState_Run(void) { if (!DeepState_OptionsAreInitialized) { - DeepState_Abandon("Please call DeepState_InitOptions(argc, argv) in main."); + DeepState_Abandon("Please call DeepState_InitOptions(argc, argv) in main"); } if (HAS_FLAG_input_test_dir) { diff --git a/src/include/deepstate/DeepState.hpp b/src/include/deepstate/DeepState.hpp index f895550..fc8ae98 100644 --- a/src/include/deepstate/DeepState.hpp +++ b/src/include/deepstate/DeepState.hpp @@ -301,7 +301,7 @@ static T Pump(T val, unsigned max=10) { return val; } if (!max) { - DeepState_Abandon("Must have a positive maximum number of values to pump."); + DeepState_Abandon("Must have a positive maximum number of values to Pump"); } for (auto i = 0U; i < max - 1; ++i) { T min_val = Minimize(val); @@ -341,7 +341,7 @@ inline static void OneOf(FuncTys&&... funcs) { inline static char OneOf(const char *str) { if (!str || !str[0]) { - DeepState_Abandon("NULL or empty string passed to OneOf."); + DeepState_Abandon("NULL or empty string passed to OneOf"); } return str[DeepState_IntInRange(0, strlen(str) - 1)]; } @@ -349,7 +349,7 @@ inline static char OneOf(const char *str) { template inline static const T &OneOf(const std::vector &arr) { if (arr.empty()) { - DeepState_Abandon("Empty vector passed to OneOf."); + DeepState_Abandon("Empty vector passed to OneOf"); } return arr[DeepState_IntInRange(0, arr.size() - 1)]; } @@ -358,7 +358,7 @@ inline static const T &OneOf(const std::vector &arr) { template inline static const T &OneOf(T (&arr)[len]) { if (!len) { - DeepState_Abandon("Empty array passed to OneOf."); + DeepState_Abandon("Empty array passed to OneOf"); } return arr[DeepState_IntInRange(0, len - 1)]; } diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 0ef3291..81ca6c0 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -90,7 +90,7 @@ void DeepState_AllocCurrentTestRun(void) { mem_vis, 0, 0); if (shared_mem == MAP_FAILED) { - DeepState_Log(DeepState_LogError, "Unable to map shared memory."); + DeepState_Log(DeepState_LogError, "Unable to map shared memory"); exit(1); } @@ -173,11 +173,11 @@ void *DeepState_ConcretizeData(void *begin, void *end) { /* Return a symbolic C string of length `len`. */ char *DeepState_CStr(size_t len) { if (SIZE_MAX == len) { - DeepState_Abandon("Can't create an SIZE_MAX-length string."); + DeepState_Abandon("Can't create an SIZE_MAX-length string"); } char *str = (char *) malloc(sizeof(char) * (len + 1)); if (NULL == str) { - DeepState_Abandon("Can't allocate memory."); + DeepState_Abandon("Can't allocate memory"); } if (len) { DeepState_SymbolizeData(str, &(str[len - 1])); @@ -695,8 +695,10 @@ int DeepState_Fuzz(void){ while (diff < FLAGS_timeout) { i++; if ((diff != last_status) && ((diff % 30) == 0) ) { - DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests in %u seconds (%u tests/second). %d failed tests so far.", - i, diff, i/diff, num_failed_tests); + time_t t = time(NULL); + struct tm tm = *localtime(&t); + DeepState_LogFormat(DeepState_LogInfo, "%d-%02d-%02d %02d:%02d:%02d: %u tests/second / %d failed tests so far", + tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, i/diff, num_failed_tests); last_status = diff; } num_failed_tests += DeepState_FuzzOneTestCase(test); @@ -705,7 +707,7 @@ int DeepState_Fuzz(void){ diff = current-start; } - DeepState_LogFormat(DeepState_LogInfo, "Done fuzzing! Ran %u tests (%u tests/second). %d failed tests.", + DeepState_LogFormat(DeepState_LogInfo, "Done fuzzing! Ran %u tests (%u tests/second) with %d failed tests", i, i/diff, num_failed_tests); return num_failed_tests; @@ -804,7 +806,7 @@ void __assert_fail(const char * assertion, const char * file, } void __stack_chk_fail(void) { - DeepState_Log(DeepState_LogFatal, "Stack smash detected."); + DeepState_Log(DeepState_LogFatal, "Stack smash detected"); __builtin_unreachable(); } From ca400bc2a0777ba60996df9e479d9d48bf9cff8d Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 14:52:46 -0700 Subject: [PATCH 209/228] fix so count of failed tests is correct --- src/include/deepstate/DeepState.h | 5 +++-- src/lib/DeepState.c | 4 +++- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index af2ef28..c6d5d83 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -860,8 +860,9 @@ static int DeepState_Run(void) { } else { DeepState_Begin(test); } - - num_failed_tests += DeepState_ForkAndRunTest(test); + if (DeepState_ForkAndRunTest(test) != 0) { + num_failed_tests++; + } } if (use_drfuzz) { diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 81ca6c0..48c0c3d 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -701,7 +701,9 @@ int DeepState_Fuzz(void){ tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday, tm.tm_hour, tm.tm_min, tm.tm_sec, i/diff, num_failed_tests); last_status = diff; } - num_failed_tests += DeepState_FuzzOneTestCase(test); + if (DeepState_FuzzOneTestCase(test) != 0) { + num_failed_tests ++; + } current = (long)time(NULL); diff = current-start; From 91b8b5b8d149a19e17e450531db158361394c472 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 15:02:59 -0700 Subject: [PATCH 210/228] Fix the mac OS abort problem with libFuzzer --- src/include/deepstate/DeepState.h | 4 ++-- src/lib/DeepState.c | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index c6d5d83..227cb17 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -724,7 +724,7 @@ static int DeepState_RunSingleSavedTestCase(void) { if ((result == DeepState_TestRunFail) || (result == DeepState_TestRunCrash)) { if (FLAGS_abort_on_fail) { - abort(); + assert(0); // Terminate in a way AFL/etc. can see as a crash } num_failed_tests++; } @@ -790,7 +790,7 @@ static int DeepState_RunSingleSavedTestDir(void) { if ((result == DeepState_TestRunFail) || (result == DeepState_TestRunCrash)) { if (FLAGS_abort_on_fail) { - abort(); + assert(0); // Terminate in a way AFL/etc. can see as a crash } num_failed_tests++; diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 48c0c3d..a62395a 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -741,7 +741,7 @@ enum DeepState_TestRunResult DeepState_FuzzOneTestCase(struct DeepState_TestInfo if (FLAGS_abort_on_fail && ((result == DeepState_TestRunCrash) || (result == DeepState_TestRunFail))) { - abort(); + assert(0); // Terminate the testing in a way AFL/etc. can see as a crash } return result; @@ -783,7 +783,7 @@ extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { const char* abort_check = getenv("LIBFUZZER_ABORT_ON_FAIL"); if (abort_check != NULL) { if ((result == DeepState_TestRunFail) || (result == DeepState_TestRunCrash)) { - abort(); + assert(0); // Terminate the testing more permanently } } From d2b632ef25291edc98edf5cdd867c8782efb2c98 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 15:28:26 -0700 Subject: [PATCH 211/228] default replay of multiple tests to a quiet mode --- src/include/deepstate/DeepState.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 227cb17..436f9a2 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -742,6 +742,10 @@ static int DeepState_RunSingleSavedTestDir(void) { int num_failed_tests = 0; struct DeepState_TestInfo *test = NULL; + if (!HAS_FLAG_log_level) { + FLAGS_log_level = 2; + } + DeepState_Setup(); for (test = DeepState_FirstTest(); test != NULL; test = test->prev) { @@ -811,6 +815,10 @@ static int DeepState_RunSavedTestCases(void) { int num_failed_tests = 0; struct DeepState_TestInfo *test = NULL; + if (!HAS_FLAG_log_level) { + FLAGS_log_level = 2; + } + DeepState_Setup(); for (test = DeepState_FirstTest(); test != NULL; test = test->prev) { @@ -828,14 +836,14 @@ static int DeepState_Run(void) { DeepState_Abandon("Please call DeepState_InitOptions(argc, argv) in main"); } - if (HAS_FLAG_input_test_dir) { - return DeepState_RunSavedTestCases(); - } - if (HAS_FLAG_input_test_file) { return DeepState_RunSingleSavedTestCase(); } + if (HAS_FLAG_input_test_dir) { + return DeepState_RunSavedTestCases(); + } + if (HAS_FLAG_input_test_files_dir) { return DeepState_RunSingleSavedTestDir(); } From fadd43ce7165635341633183d60ec6c3c9fefb3f Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 15:48:11 -0700 Subject: [PATCH 212/228] test replay is quiet but reports numbers --- src/include/deepstate/DeepState.h | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 436f9a2..1f06847 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -674,9 +674,12 @@ static int DeepState_RunSavedCasesForTest(struct DeepState_TestInfo *test) { return 0; } + unsigned int i = 0; + /* Read generated test cases and run a test for each file found. */ while ((dp = readdir(dir_fd)) != NULL) { if (DeepState_IsTestCaseFile(dp->d_name)) { + i++; enum DeepState_TestRunResult result = DeepState_RunSavedTestCase(test, test_case_dir, dp->d_name); @@ -688,6 +691,9 @@ static int DeepState_RunSavedCasesForTest(struct DeepState_TestInfo *test) { closedir(dir_fd); free(test_case_dir); + DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests; %d tests failed", + i, num_failed_tests); + return num_failed_tests; } @@ -781,6 +787,8 @@ static int DeepState_RunSingleSavedTestDir(void) { return 0; } + unsigned int i = 0; + /* Read generated test cases and run a test for each file found. */ while ((dp = readdir(dir_fd)) != NULL) { size_t path_len = 2 + sizeof(char) * (strlen(FLAGS_input_test_files_dir) + strlen(dp->d_name)); @@ -789,6 +797,7 @@ static int DeepState_RunSingleSavedTestDir(void) { stat(path, &path_stat); if (S_ISREG(path_stat.st_mode)) { + i++; enum DeepState_TestRunResult result = DeepState_RunSavedTestCase(test, FLAGS_input_test_files_dir, dp->d_name); @@ -803,6 +812,9 @@ static int DeepState_RunSingleSavedTestDir(void) { } closedir(dir_fd); + DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests; %d tests failed", + i, num_failed_tests); + return num_failed_tests; } From c58ca9b11622885041c1c198d0f91d5f00917c46 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 18:32:47 -0700 Subject: [PATCH 213/228] Fix check --- tests/test_runlen.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_runlen.py b/tests/test_runlen.py index a378329..7a7e3e9 100644 --- a/tests/test_runlen.py +++ b/tests/test_runlen.py @@ -14,7 +14,7 @@ class RunlenTest(deepstate_base.DeepStateTestCase): self.assertTrue("Passed: Runlength_EncodeDecode" in output) foundFailSave = False for line in output.split("\n"): - if ("Saving input to" in line) and (".fail" in line): + if ("Saved test case" in line) and (".fail" in line): foundFailSave = True self.assertTrue(foundFailSave) From 2fbfa652b4fdd7b094e1aad5e07e0f287efc53e0 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 19:22:14 -0700 Subject: [PATCH 214/228] minor fixes to output improvements, correct README --- README.md | 16 ++++++++++------ src/include/deepstate/DeepState.h | 4 ++-- 2 files changed, 12 insertions(+), 8 deletions(-) diff --git a/README.md b/README.md index cf5420c..82d41a2 100644 --- a/README.md +++ b/README.md @@ -115,6 +115,15 @@ argument to see all DeepState options. DeepState consists of a static library, used to write test harnesses, and command-line _executors_ written in Python. At this time, the best documentation is in the [examples](/examples) and in our [paper](https://agroce.github.io/bar18.pdf). A more extensive example, using DeepState and libFuzzer to test a user-mode file system, is available [here](https://github.com/agroce/testfs); in particular the [Tests.cpp](https://github.com/agroce/testfs/blob/master/Tests.cpp) file and CMakeLists.txt show DeepState usage. +## Log Levels + +By default, DeepState is not very verbose about testing activity, +other than failing tests. The `--log-level` argument lowers the +threshold for output, with 0 = `DEBUG`, 1 = `TRACE` (output from the +tests, including `printf`s), and 2 = INFO (DeepState messages, the default), 3 = `WARNING`, +4 = `ERROR`, and 5 = `EXTERNAL` (output from other programs such as +libFuzzer), and 6 = `CRITICAL`/`FATAL` messages. + ## A Note on Mac OS and Forking Normally, when running a test for replay or fuzzing, DeepState forks @@ -133,12 +142,7 @@ The fuzzer also takes a `seed` and `timeout` (default of two minutes) to control the fuzzing. If you want to actually save the test cases generated, you need to add a `--output_test_dir` arument to tell DeepState where to put the generated tests. By default fuzzing saves -only failing and crashing tests. One more command line argument that -is particularly useful for fuzzing is the `--log_level` argument, -which controls how much output each test produces. By default, this -is set to show all the logging from your tests, which slows fuzzing, -but setting it to 2 or higher will only show messages produced by -tests failing or crashing. +only failing and crashing tests and only when given an output directory. Note that while symbolic execution only works on Linux, without a fairly complex cross-compliation process, the brute force fuzzer works diff --git a/src/include/deepstate/DeepState.h b/src/include/deepstate/DeepState.h index 1f9f1a7..e10f630 100644 --- a/src/include/deepstate/DeepState.h +++ b/src/include/deepstate/DeepState.h @@ -706,8 +706,8 @@ static int DeepState_RunSavedCasesForTest(struct DeepState_TestInfo *test) { closedir(dir_fd); free(test_case_dir); - DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests; %d tests failed", - i, num_failed_tests); + DeepState_LogFormat(DeepState_LogInfo, "Ran %u tests for %s; %d tests failed", + i, test->test_name, num_failed_tests); return num_failed_tests; } From c5479ba663ac88b0e78cc144b6f272553c107cf2 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Thu, 3 Jan 2019 20:19:06 -0700 Subject: [PATCH 215/228] Typos --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 82d41a2..980681b 100644 --- a/README.md +++ b/README.md @@ -120,9 +120,9 @@ DeepState consists of a static library, used to write test harnesses, and comman By default, DeepState is not very verbose about testing activity, other than failing tests. The `--log-level` argument lowers the threshold for output, with 0 = `DEBUG`, 1 = `TRACE` (output from the -tests, including `printf`s), and 2 = INFO (DeepState messages, the default), 3 = `WARNING`, -4 = `ERROR`, and 5 = `EXTERNAL` (output from other programs such as -libFuzzer), and 6 = `CRITICAL`/`FATAL` messages. +tests, including from `printf`), 2 = INFO (DeepState messages, the default), 3 = `WARNING`, +4 = `ERROR`, 5 = `EXTERNAL` (output from other programs such as +libFuzzer), and 6 = `CRITICAL` messages. ## A Note on Mac OS and Forking @@ -140,7 +140,7 @@ generates tests using completely random data. Using this fuzzer is as simple as calling the native executable with the `--fuzz` argument. The fuzzer also takes a `seed` and `timeout` (default of two minutes) to control the fuzzing. If you want to actually save the test cases -generated, you need to add a `--output_test_dir` arument to tell +generated, you need to add a `--output_test_dir` argument to tell DeepState where to put the generated tests. By default fuzzing saves only failing and crashing tests and only when given an output directory. From 59a3b51f9f2f3bba31d201304298c1535bd18f17 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 4 Jan 2019 11:44:33 -0700 Subject: [PATCH 216/228] Tidy up the example --- examples/Runlen.cpp | 21 +++++---------------- 1 file changed, 5 insertions(+), 16 deletions(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index b7d12aa..9ec722e 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -38,26 +38,15 @@ char* decode(const char* output) { return decoded; } -void printBytes(const char* bytes) { - unsigned int len = strlen(bytes); - for (int i = 0; i < len; i++) - LOG(ERROR) << "[" << i << "] = " << (unsigned int)(unsigned char)bytes[i]; -} - // Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution #define MAX_STR_LEN 6 TEST(Runlength, EncodeDecode) { - char* original = DeepState_CStrUpToLen(MAX_STR_LEN); + char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcdef0123456789"); char* encoded = encode(original); + ASSERT_LE(strlen(encoded), strlen(original)*2) << "Encoding is > length*2!"; char* roundtrip = decode(encoded); - if (!(strncmp(roundtrip, original, MAX_STR_LEN) == 0)) { - LOG(ERROR) << "ORIGINAL:"; - printBytes(original); - LOG(ERROR) << "ENCODED:"; - printBytes(encoded); - LOG(ERROR) << "ROUNDTRIP:"; - printBytes(roundtrip); - ASSERT (0) << "Round trip check failed"; - } + ASSERT_EQ(strncmp(roundtrip, original, MAX_STR_LEN), 0) << + "ORIGINAL: '" << original << "', ENCODED: '" << encoded << + "', ROUNDTRIP: '" << roundtrip << "'"; } From 276ce6cb3f1fd8768c9446e21f511ac50f2008aa Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 4 Jan 2019 12:00:57 -0700 Subject: [PATCH 217/228] clean up formatting --- examples/Runlen.cpp | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 9ec722e..10264b2 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -9,17 +9,21 @@ char* encode(const char* input) { unsigned int len = strlen(input); char* encoded = (char*)malloc((len*2)+1); int pos = 0; - if (strlen(input) > 0) { - unsigned char last = input[0]; int count = 1; + if (len > 0) { + unsigned char last = input[0]; + int count = 1; for (int i = 1; i < len; i++) { if (((unsigned char)input[i] == last) && (count < 26)) count++; else { - encoded[pos++] = last; encoded[pos++] = 64 + count; - last = (unsigned char)input[i]; count = 1; + encoded[pos++] = last; + encoded[pos++] = 64 + count; + last = (unsigned char)input[i]; + count = 1; } } - encoded[pos++] = last; encoded[pos++] = 65; // Should be 64 + count + encoded[pos++] = last; + encoded[pos++] = 65; // Should be 64 + count } encoded[pos] = '\0'; return encoded; @@ -29,10 +33,10 @@ char* decode(const char* output) { unsigned int len = strlen(output); char* decoded = (char*)malloc((len/2)*26); int pos = 0; - if (strlen(output) > 0) { - for (int i = 0; i < len; i += 2) - for (int j = 0; j < (output[i+1] - 64); j++) - decoded[pos++] = output[i]; + for (int i = 0; i < len; i += 2) { + for (int j = 0; j < (output[i+1] - 64); j++) { + decoded[pos++] = output[i]; + } } decoded[pos] = '\0'; return decoded; From 65e86bcc8200f5e3327a53e5ea5817b93a34b2f9 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 4 Jan 2019 12:19:27 -0700 Subject: [PATCH 218/228] add code in README --- README.md | 61 +++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 61 insertions(+) diff --git a/README.md b/README.md index 82d41a2..b202f85 100644 --- a/README.md +++ b/README.md @@ -133,6 +133,67 @@ replaying tests, it is highly recommended to add the `--no_fork` option on mac OS, unless you need the added crash handling (that is, things aren't working without that option). +## Example Code + +``` +#include + +using namespace deepstate; + +/* Simple, buggy, run-length encoding that creates "human readable" + * encodings by adding 'A'-1 to the count, and splitting at 26 */ + +char* encode(const char* input) { + unsigned int len = strlen(input); + char* encoded = (char*)malloc((len*2)+1); + int pos = 0; + if (len > 0) { + unsigned char last = input[0]; + int count = 1; + for (int i = 1; i < len; i++) { + if (((unsigned char)input[i] == last) && (count < 26)) + count++; + else { + encoded[pos++] = last; + encoded[pos++] = 64 + count; + last = (unsigned char)input[i]; + count = 1; + } + } + encoded[pos++] = last; + encoded[pos++] = 65; // Should be 64 + count + } + encoded[pos] = '\0'; + return encoded; +} + +char* decode(const char* output) { + unsigned int len = strlen(output); + char* decoded = (char*)malloc((len/2)*26); + int pos = 0; + for (int i = 0; i < len; i += 2) { + for (int j = 0; j < (output[i+1] - 64); j++) { + decoded[pos++] = output[i]; + } + } + decoded[pos] = '\0'; + return decoded; +} + +// Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution +#define MAX_STR_LEN 6 + +TEST(Runlength, EncodeDecode) { + char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcdef0123456789"); + char* encoded = encode(original); + ASSERT_LE(strlen(encoded), strlen(original)*2) << "Encoding is > length*2!"; + char* roundtrip = decode(encoded); + ASSERT_EQ(strncmp(roundtrip, original, MAX_STR_LEN), 0) << + "ORIGINAL: '" << original << "', ENCODED: '" << encoded << + "', ROUNDTRIP: '" << roundtrip << "'"; +} +``` + ## Built-In Fuzzer Every DeepState executable provides a simple built-in fuzzer that From f55bad722a8c0a4c9d504d9f95da3236b09d2b12 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 4 Jan 2019 12:25:31 -0700 Subject: [PATCH 219/228] comment on the code --- README.md | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/README.md b/README.md index b202f85..0323f60 100644 --- a/README.md +++ b/README.md @@ -194,6 +194,27 @@ TEST(Runlength, EncodeDecode) { } ``` +The code above (which can be found +[here](https://github.com/trailofbits/deepstate/blob/master/examples/Runlen.cpp) +shows an example of a DeepState test harness. Most of the code is +just the functions to be tested. Using DeepState to test them requires: + +- including the DeepState C++ header and using the DeepState namespace + +- defining at least one TEST, with names + +- calling some DeepState APIs that produce data + - in this example, we see the `DeepState_CStrUpToLen` call tells + DeepState to produce a string that has up the `MAX_STR_LEN` + characters, chosen from those present in hex strings. + +- optionally making some assertions about the correctness of the +results + - in this example, the `ASSERT_LE` and `ASSERT_EQ` checks + - in the absence of any properties to check, DeepState can still + look for memory safety violations, crashes, and other general + categories of undesireable behavior, like any fuzzer + ## Built-In Fuzzer Every DeepState executable provides a simple built-in fuzzer that From 0c8185567d8f0c9353687496224a5f6d8ea0b2b7 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 4 Jan 2019 12:35:06 -0700 Subject: [PATCH 220/228] comment clarifying example --- README.md | 3 ++- examples/Runlen.cpp | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 0323f60..f55104a 100644 --- a/README.md +++ b/README.md @@ -141,7 +141,8 @@ things aren't working without that option). using namespace deepstate; /* Simple, buggy, run-length encoding that creates "human readable" - * encodings by adding 'A'-1 to the count, and splitting at 26 */ + * encodings by adding 'A'-1 to the count, and splitting at 26. + * e.g., encode("aaabbbbbc") = "aCbEcA" since C=3 and E=5 */ char* encode(const char* input) { unsigned int len = strlen(input); diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 10264b2..2b2396c 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -3,7 +3,8 @@ using namespace deepstate; /* Simple, buggy, run-length encoding that creates "human readable" - * encodings by adding 'A'-1 to the count, and splitting at 26 */ + * encodings by adding 'A'-1 to the count, and splitting at 26. + * e.g., encode("aaabbbbbc") = "aCbEcA" since C=3 and E=5 */ char* encode(const char* input) { unsigned int len = strlen(input); From 878528e672466202ff5453b6e659f82ff270d8fe Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 4 Jan 2019 12:49:43 -0700 Subject: [PATCH 221/228] add boring unit test --- README.md | 32 ++++++++++++++++++++++++++++++++ examples/Runlen.cpp | 6 ++++++ 2 files changed, 38 insertions(+) diff --git a/README.md b/README.md index f55104a..ff775b1 100644 --- a/README.md +++ b/README.md @@ -184,6 +184,12 @@ char* decode(const char* output) { // Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution #define MAX_STR_LEN 6 +TEST(Runlength, BoringUnitTest) { + ASSERT_EQ(strcmp(encode(""), ""), 0); + ASSERT_EQ(strcmp(encode("a"), "aA"), 0); + ASSERT_EQ(strcmp(encode("aaabbbbbc"), "aCbEcA"), 0); +} + TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcdef0123456789"); char* encoded = encode(original); @@ -216,6 +222,32 @@ results look for memory safety violations, crashes, and other general categories of undesireable behavior, like any fuzzer +DeepState will also run the "BoringUnitTest," but it (like a +traditional hand-written unit test) is simply a test of fixed inputs +devised by a programmer. These inputs do not expose the bug in +`encode`. Using DeepState, however, it is easy to find the bug. Just +go into the `$DEEPSTATE/build/examples` directory and try: + +```shell +deepstate-angr ./Runlen +``` + +or + +```shell +./Runlen --fuzz --abort_on_fail +``` + +The fuzzer will output something like: + +``` +INFO: Starting fuzzing +WARNING: No seed provided; using 1546631311 +WARNING: No test specified, defaulting to last test defined (Runlength_EncodeDecode) +CRITICAL: /Users/alex/deepstate/examples/Runlen.cpp(60): ORIGINAL: '91c499', ENCODED: '9A1AcA4A9A', ROUNDTRIP: '91c49' +ERROR: Failed: Runlength_EncodeDecode +``` + ## Built-In Fuzzer Every DeepState executable provides a simple built-in fuzzer that diff --git a/examples/Runlen.cpp b/examples/Runlen.cpp index 2b2396c..b1d8332 100644 --- a/examples/Runlen.cpp +++ b/examples/Runlen.cpp @@ -46,6 +46,12 @@ char* decode(const char* output) { // Can be (much) higher (e.g., > 1024) if we're using fuzzing, not symbolic execution #define MAX_STR_LEN 6 +TEST(Runlength, BoringUnitTest) { + ASSERT_EQ(strcmp(encode(""), ""), 0); + ASSERT_EQ(strcmp(encode("a"), "aA"), 0); + ASSERT_EQ(strcmp(encode("aaabbbbbc"), "aCbEcA"), 0); +} + TEST(Runlength, EncodeDecode) { char* original = DeepState_CStrUpToLen(MAX_STR_LEN, "abcdef0123456789"); char* encoded = encode(original); From a30234fc7ca8030092ef467211e3d82603fb5ff7 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 4 Jan 2019 13:00:31 -0700 Subject: [PATCH 222/228] fix log level arg --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index ff775b1..994854c 100644 --- a/README.md +++ b/README.md @@ -118,7 +118,7 @@ DeepState consists of a static library, used to write test harnesses, and comman ## Log Levels By default, DeepState is not very verbose about testing activity, -other than failing tests. The `--log-level` argument lowers the +other than failing tests. The `--log_level` argument lowers the threshold for output, with 0 = `DEBUG`, 1 = `TRACE` (output from the tests, including `printf`s), and 2 = INFO (DeepState messages, the default), 3 = `WARNING`, 4 = `ERROR`, and 5 = `EXTERNAL` (output from other programs such as From cbdda8bdea8a3e98ca8304ee70463a84f2b29431 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 4 Jan 2019 13:02:34 -0700 Subject: [PATCH 223/228] reorg of README --- README.md | 39 +++++++++++++++++++++------------------ 1 file changed, 21 insertions(+), 18 deletions(-) diff --git a/README.md b/README.md index 994854c..b778322 100644 --- a/README.md +++ b/README.md @@ -115,24 +115,6 @@ argument to see all DeepState options. DeepState consists of a static library, used to write test harnesses, and command-line _executors_ written in Python. At this time, the best documentation is in the [examples](/examples) and in our [paper](https://agroce.github.io/bar18.pdf). A more extensive example, using DeepState and libFuzzer to test a user-mode file system, is available [here](https://github.com/agroce/testfs); in particular the [Tests.cpp](https://github.com/agroce/testfs/blob/master/Tests.cpp) file and CMakeLists.txt show DeepState usage. -## Log Levels - -By default, DeepState is not very verbose about testing activity, -other than failing tests. The `--log_level` argument lowers the -threshold for output, with 0 = `DEBUG`, 1 = `TRACE` (output from the -tests, including `printf`s), and 2 = INFO (DeepState messages, the default), 3 = `WARNING`, -4 = `ERROR`, and 5 = `EXTERNAL` (output from other programs such as -libFuzzer), and 6 = `CRITICAL`/`FATAL` messages. - -## A Note on Mac OS and Forking - -Normally, when running a test for replay or fuzzing, DeepState forks -in order to cleanly handle crashes of a test. Unfortunately, `fork()` -on mac OS is extremely slow. When using the built-in fuzzer or -replaying tests, it is highly recommended to add the `--no_fork` -option on mac OS, unless you need the added crash handling (that is, -things aren't working without that option). - ## Example Code ``` @@ -248,6 +230,18 @@ CRITICAL: /Users/alex/deepstate/examples/Runlen.cpp(60): ORIGINAL: '91c499', ENC ERROR: Failed: Runlength_EncodeDecode ``` +## Log Levels + +By default, DeepState is not very verbose about testing activity, +other than failing tests. The `--log_level` argument lowers the +threshold for output, with 0 = `DEBUG`, 1 = `TRACE` (output from the +tests, including `printf`s), and 2 = INFO (DeepState messages, the default), 3 = `WARNING`, +4 = `ERROR`, and 5 = `EXTERNAL` (output from other programs such as +libFuzzer), and 6 = `CRITICAL`/`FATAL` messages. This can be very +useful when understanding what a DeepState harness is actually doing; +usually, setting `--log_level 1` in either fuzzing or symbolic +execution will give sufficient information to debug your test harness. + ## Built-In Fuzzer Every DeepState executable provides a simple built-in fuzzer that @@ -263,6 +257,15 @@ Note that while symbolic execution only works on Linux, without a fairly complex cross-compliation process, the brute force fuzzer works on macOS or (as far as we know) any Unix-like system. +## A Note on Mac OS and Forking + +Normally, when running a test for replay or fuzzing, DeepState forks +in order to cleanly handle crashes of a test. Unfortunately, `fork()` +on mac OS is extremely slow. When using the built-in fuzzer or +replaying tests, it is highly recommended to add the `--no_fork` +option on mac OS, unless you need the added crash handling (that is, +things aren't working without that option). + ## Fuzzing with libFuzzer If you install clang 6.0 or later, and run `cmake` when you install From 58df6801a146ce9fe833fd48576ce9de7bca1db5 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 4 Jan 2019 13:13:57 -0700 Subject: [PATCH 224/228] more readme edits, typo fixes, etc. --- README.md | 47 ++++++++++++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 17 deletions(-) diff --git a/README.md b/README.md index b778322..2246f9b 100644 --- a/README.md +++ b/README.md @@ -184,30 +184,40 @@ TEST(Runlength, EncodeDecode) { ``` The code above (which can be found -[here](https://github.com/trailofbits/deepstate/blob/master/examples/Runlen.cpp) +[here](https://github.com/trailofbits/deepstate/blob/master/examples/Runlen.cpp)) shows an example of a DeepState test harness. Most of the code is just the functions to be tested. Using DeepState to test them requires: -- including the DeepState C++ header and using the DeepState namespace +- Including the DeepState C++ header and using the DeepState namespace -- defining at least one TEST, with names +- Defining at least one TEST, with names -- calling some DeepState APIs that produce data - - in this example, we see the `DeepState_CStrUpToLen` call tells +- Calling some DeepState APIs that produce data + - In this example, we see the `DeepState_CStrUpToLen` call tells DeepState to produce a string that has up the `MAX_STR_LEN` characters, chosen from those present in hex strings. -- optionally making some assertions about the correctness of the +- Optionally making some assertions about the correctness of the results - - in this example, the `ASSERT_LE` and `ASSERT_EQ` checks - - in the absence of any properties to check, DeepState can still + - In `Runlen.cpp` this is the `ASSERT_LE` and `ASSERT_EQ` checks. + - In the absence of any properties to check, DeepState can still look for memory safety violations, crashes, and other general - categories of undesireable behavior, like any fuzzer + categories of undesireable behavior, like any fuzzer. DeepState will also run the "BoringUnitTest," but it (like a traditional hand-written unit test) is simply a test of fixed inputs devised by a programmer. These inputs do not expose the bug in -`encode`. Using DeepState, however, it is easy to find the bug. Just +`encode`. Nor do the default values for the DeepState test: + +``` +~/deepstate/build/examples$ ./Runlen +TRACE: Running: Runlength_EncodeDecode from /Users/alex/deepstate/examples/Runlen.cpp(55) +TRACE: Passed: Runlength_EncodeDecode +TRACE: Running: Runlength_BoringUnitTest from /Users/alex/deepstate/examples/Runlen.cpp(49) +TRACE: Passed: Runlength_BoringUnitTest +``` + +Using DeepState, however, it is easy to find the bug. Just go into the `$DEEPSTATE/build/examples` directory and try: ```shell @@ -248,10 +258,13 @@ Every DeepState executable provides a simple built-in fuzzer that generates tests using completely random data. Using this fuzzer is as simple as calling the native executable with the `--fuzz` argument. The fuzzer also takes a `seed` and `timeout` (default of two minutes) -to control the fuzzing. If you want to actually save the test cases -generated, you need to add a `--output_test_dir` arument to tell -DeepState where to put the generated tests. By default fuzzing saves -only failing and crashing tests and only when given an output directory. +to control the fuzzing. By default fuzzing saves +only failing and crashing tests, and these only when given an output +directory. If you want to actually save the test cases +generated, you need to add a `--output_test_dir` argument to tell +DeepState where to put the generated tests, and if you want the +(totally random and unlikely to be high-quality) passing tests, you +need to add `--fuzz_save_passing`. Note that while symbolic execution only works on Linux, without a fairly complex cross-compliation process, the brute force fuzzer works @@ -261,10 +274,10 @@ on macOS or (as far as we know) any Unix-like system. Normally, when running a test for replay or fuzzing, DeepState forks in order to cleanly handle crashes of a test. Unfortunately, `fork()` -on mac OS is extremely slow. When using the built-in fuzzer or -replaying tests, it is highly recommended to add the `--no_fork` +on mac OS is _extremely_ slow. When using the built-in fuzzer or +replaying more than a few tests, it is highly recommended to add the `--no_fork` option on mac OS, unless you need the added crash handling (that is, -things aren't working without that option). +only when things aren't working without that option). ## Fuzzing with libFuzzer From 0ef1e9b4c2882f7419000cf01df4c0b9113748e1 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Fri, 4 Jan 2019 13:17:44 -0700 Subject: [PATCH 225/228] Multiple spelling error and readability fixes --- README.md | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/README.md b/README.md index 2246f9b..1096e81 100644 --- a/README.md +++ b/README.md @@ -202,7 +202,7 @@ results - In `Runlen.cpp` this is the `ASSERT_LE` and `ASSERT_EQ` checks. - In the absence of any properties to check, DeepState can still look for memory safety violations, crashes, and other general - categories of undesireable behavior, like any fuzzer. + categories of undesirable behavior, like any fuzzer. DeepState will also run the "BoringUnitTest," but it (like a traditional hand-written unit test) is simply a test of fixed inputs @@ -245,11 +245,11 @@ ERROR: Failed: Runlength_EncodeDecode By default, DeepState is not very verbose about testing activity, other than failing tests. The `--log_level` argument lowers the threshold for output, with 0 = `DEBUG`, 1 = `TRACE` (output from the -tests, including `printf`s), and 2 = INFO (DeepState messages, the default), 3 = `WARNING`, -4 = `ERROR`, and 5 = `EXTERNAL` (output from other programs such as -libFuzzer), and 6 = `CRITICAL`/`FATAL` messages. This can be very -useful when understanding what a DeepState harness is actually doing; -usually, setting `--log_level 1` in either fuzzing or symbolic +tests, including `printf`), 2 = `INFO` (DeepState messages; this is the default), 3 = `WARNING`, +4 = `ERROR`, 5 = `EXTERNAL` (output from other programs such as +libFuzzer), and 6 = `CRITICAL`/`FATAL` messages. Lowering the `log_level` can be very +useful for understanding what a DeepState harness is actually doing; +often, setting `--log_level 1` in either fuzzing or symbolic execution will give sufficient information to debug your test harness. ## Built-In Fuzzer @@ -267,7 +267,7 @@ DeepState where to put the generated tests, and if you want the need to add `--fuzz_save_passing`. Note that while symbolic execution only works on Linux, without a -fairly complex cross-compliation process, the brute force fuzzer works +fairly complex cross-compilation process, the brute force fuzzer works on macOS or (as far as we know) any Unix-like system. ## A Note on Mac OS and Forking From af4a0a2007a735733ca4de06eb29b46ac37130fc Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 6 Jan 2019 14:56:20 -0700 Subject: [PATCH 226/228] Add a loud mode for debugging libFuzzer on mac OS --- src/lib/DeepState.c | 9 +++++++++ src/lib/Log.c | 3 ++- 2 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 751ef11..8bc23fe 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -56,6 +56,9 @@ int DeepState_UsingSymExec = 0; /* Set to 1 when we're using libFuzzer. */ int DeepState_UsingLibFuzzer = 0; +/* To make libFuzzer louder on mac OS. */ +int DeepState_LibFuzzerLoud = 1; + /* Array of DeepState generated strings. Impossible for there to * be more than there are input bytes. Index stores where we are. */ char* DeepState_GeneratedStrings[DeepState_InputSize]; @@ -841,6 +844,12 @@ extern int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { } DeepState_UsingLibFuzzer = 1; + + const char* loud = getenv("LIBFUZZER_LOUD"); + if (loud != NULL) { + FLAGS_log_level = 0; + DeepState_LibFuzzerLoud = 1; + } struct DeepState_TestInfo *test = NULL; diff --git a/src/lib/Log.c b/src/lib/Log.c index 78fe32f..b6d7016 100644 --- a/src/lib/Log.c +++ b/src/lib/Log.c @@ -69,13 +69,14 @@ enum { }; extern int DeepState_UsingLibFuzzer; +extern int DeepState_LibFuzzerLoud; char DeepState_LogBuf[DeepState_LogBufSize + 1] = {}; /* Log a C string. */ DEEPSTATE_NOINLINE void DeepState_Log(enum DeepState_LogLevel level, const char *str) { - if ((DeepState_UsingLibFuzzer && (level < DeepState_LogExternal)) || + if ((DeepState_UsingLibFuzzer && !DeepState_LibFuzzerLoud && (level < DeepState_LogExternal)) || (level < FLAGS_log_level)) { return; } From b7e44b511e391399aa2aeb7a0937d3efd27755de Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 6 Jan 2019 14:58:29 -0700 Subject: [PATCH 227/228] proper default --- src/lib/DeepState.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/lib/DeepState.c b/src/lib/DeepState.c index 8bc23fe..085deb8 100644 --- a/src/lib/DeepState.c +++ b/src/lib/DeepState.c @@ -57,7 +57,7 @@ int DeepState_UsingSymExec = 0; int DeepState_UsingLibFuzzer = 0; /* To make libFuzzer louder on mac OS. */ -int DeepState_LibFuzzerLoud = 1; +int DeepState_LibFuzzerLoud = 0; /* Array of DeepState generated strings. Impossible for there to * be more than there are input bytes. Index stores where we are. */ From 8ced6628729c5ba041f3394fe7ae86c080f4d9a8 Mon Sep 17 00:00:00 2001 From: Alex Groce Date: Sun, 6 Jan 2019 16:35:06 -0700 Subject: [PATCH 228/228] mention loud option --- README.md | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/README.md b/README.md index 5d11805..f80361e 100644 --- a/README.md +++ b/README.md @@ -328,6 +328,10 @@ CC=/usr/local/opt/llvm\@6/bin/clang CXX=/usr/local/opt/llvm\@6/bin/clang++ BUILD make install ``` +On mac OS, libFuzzer's normal output is not visible. On any platform, +you can see more about what DeepState under libFuzzer is doing by +setting the `LIBFUZZER_LOUD` environment variable. + Other ways of getting an appropriate LLVM may also work. ## Test case reduction