diff options
author | Jack Lloyd <[email protected]> | 2017-07-31 15:13:15 -0400 |
---|---|---|
committer | Jack Lloyd <[email protected]> | 2017-08-25 17:36:51 -0400 |
commit | 3baa546d70bcd078b23be07069d755a5f130fb0f (patch) | |
tree | d626d73fdf845987e2d1783e8493593501378a07 /src/scripts | |
parent | 41e1e7cbc1e4e864ad5d15dd0c09227b04940a91 (diff) |
Create new fuzzer build mode
Diffstat (limited to 'src/scripts')
-rwxr-xr-x | src/scripts/ci/travis/build.sh | 13 | ||||
-rwxr-xr-x | src/scripts/create_corpus_zip.py | 48 | ||||
-rwxr-xr-x | src/scripts/test_fuzzers.py | 78 |
3 files changed, 138 insertions, 1 deletions
diff --git a/src/scripts/ci/travis/build.sh b/src/scripts/ci/travis/build.sh index 36517738b..d2e35112e 100755 --- a/src/scripts/ci/travis/build.sh +++ b/src/scripts/ci/travis/build.sh @@ -23,6 +23,8 @@ elif [ "$BUILD_MODE" = "nist" ]; then elif [ "$BUILD_MODE" = "sonarqube" ]; then # No special flags required CFG_FLAGS+=() +elif [ "$BUILD_MODE" = "fuzzers" ]; then + CFG_FLAGS+=(--build-fuzzers=test --with-sanitizers --with-debug-info --disable-shared) elif [ "$BUILD_MODE" = "parallel" ]; then if [ "$CC" = "gcc" ]; then @@ -137,6 +139,11 @@ else time "${MAKE_CMD[@]}" fi +if [ "$BUILD_MODE" = "fuzzers" ]; then + make fuzzers + make fuzzer_corpus_zip +fi + # post-build ccache stats ccache --show-stats @@ -171,9 +178,13 @@ if [ "$BUILD_MODE" = "sonarqube" ]; then # When neither on master branch nor on a non-external pull request => nothing to do fi -if [ "$BUILD_MODE" = "sonarqube" ] || [ "$BUILD_MODE" = "docs" ] || \ +if [ "$BUILD_MODE" = "sonarqube" ] || [ "$BUILD_MODE" = "docs" ] || ( [ "${BUILD_MODE:0:5}" = "cross" ] && [ "$TRAVIS_OS_NAME" = "osx" ] ); then echo "Running tests disabled on this build type" + +elif [ "$BUILD_MODE" = "fuzzers" ]; then + # Test each fuzzer against its corpus + ./src/scripts/test_fuzzers.py fuzzer_corpus build/fuzzer else TEST_CMD=("${TEST_PREFIX[@]}" $TEST_EXE "${TEST_FLAGS[@]}") echo "Running" "${TEST_CMD[@]}" diff --git a/src/scripts/create_corpus_zip.py b/src/scripts/create_corpus_zip.py new file mode 100755 index 000000000..5faee3b52 --- /dev/null +++ b/src/scripts/create_corpus_zip.py @@ -0,0 +1,48 @@ +#!/usr/bin/python + +# These is used to create fuzzer corpus zip files + +# This is primarily used by OSS-Fuzz but might be useful if you were +# deploying the binaries in a custom fuzzer deployment system. + +import sys +import os +import zipfile +import stat + +def main(args=None): + if args is None: + args = sys.argv + + if len(args) != 2 and len(args) != 3: + print("Usage: %s corpus_dir <output_dir>" % (args[0])) + return 1 + + root_dir = args[1] + + if len(args) == 3: + output_dir = args[2] + else: + output_dir = '' + + if not os.access(root_dir, os.R_OK): + print("Error could not access directory '%s'" % (root_dir)) + return 1 + + for corpus_dir in os.listdir(root_dir): + if corpus_dir == '.git': + continue + subdir = os.path.join(root_dir, corpus_dir) + if not stat.S_ISDIR(os.stat(subdir).st_mode): + continue + + zipfile_path = os.path.join(output_dir, '%s.zip' % (corpus_dir)) + zf = zipfile.ZipFile(zipfile_path, 'w', zipfile.ZIP_DEFLATED) + for f in os.listdir(subdir): + zf.write(os.path.join(subdir, f), f) + zf.close() + + return 0 + +if __name__ == '__main__': + sys.exit(main()) diff --git a/src/scripts/test_fuzzers.py b/src/scripts/test_fuzzers.py new file mode 100755 index 000000000..0d473e00c --- /dev/null +++ b/src/scripts/test_fuzzers.py @@ -0,0 +1,78 @@ +#!/usr/bin/python + +import sys +import os +import subprocess + +def main(args=None): + if args is None: + args = sys.argv + + if len(args) != 3: + print("Usage: %s <corpus_dir> <fuzzers_dir>" % (args[0])) + return 1 + + corpus_dir = args[1] + fuzzer_dir = args[2] + + if not os.access(corpus_dir, os.R_OK): + print("Error could not access corpus directory '%s'" % (corpus_dir)) + return 1 + + if not os.access(fuzzer_dir, os.R_OK): + print("Error could not access fuzzers directory '%s'" % (fuzzer_dir)) + return 1 + + fuzzers = set([]) + for fuzzer in os.listdir(fuzzer_dir): + if fuzzer.endswith('.zip'): + continue + fuzzers.add(fuzzer) + + corpii = set([]) + for corpus in os.listdir(corpus_dir): + if corpus in ['.git', 'readme.txt']: + continue + corpii.add(corpus) + + fuzzers_without_corpus = fuzzers - corpii + corpus_without_fuzzers = corpii - fuzzers + + for f in sorted(list(fuzzers_without_corpus)): + print("Warning: Fuzzer %s has no corpus" % (f)) + for c in sorted(list(corpus_without_fuzzers)): + print("Warning: Corpus %s has no fuzzer" % (c)) + + fuzzers_with_corpus = fuzzers & corpii + + any_crashes = False + + for f in sorted(list(fuzzers_with_corpus)): + fuzzer_bin = os.path.join(fuzzer_dir, f) + corpus_files = os.path.join(corpus_dir, f) + for corpus_file in sorted(list(os.listdir(corpus_files))): + corpus_fd = open(os.path.join(corpus_files, corpus_file), 'r') + fuzzer_proc = subprocess.Popen([fuzzer_bin], stdin=corpus_fd, + stdout=subprocess.PIPE, stderr=subprocess.PIPE, close_fds=True) + (stdout, stderr) = fuzzer_proc.communicate() + corpus_fd.close() + + if fuzzer_proc.returncode != 0: + print("Fuzzer %s crashed with input %s returncode %d" % (f, corpus_file, fuzzer_proc.returncode)) + any_crashes = True + + if len(stdout) != 0: + stdout = stdout.decode('ascii') + print("Fuzzer %s produced stdout on input %s:\n%s" % (f, corpus_file, stdout)) + + if len(stderr) != 0: + stderr = stderr.decode('ascii') + print("Fuzzer %s produced stderr on input %s:\n%s" % (f, corpus_file, stderr)) + + if any_crashes: + return 2 + return 0 + + +if __name__ == '__main__': + sys.exit(main()) |