diff options
-rw-r--r-- | infra/base-images/base-builder/Dockerfile | 2 | ||||
-rw-r--r-- | infra/base-images/base-builder/compile_afl | 5 | ||||
-rw-r--r-- | infra/base-images/base-runner/Dockerfile | 1 | ||||
-rwxr-xr-x | infra/base-images/base-runner/run_fuzzer | 33 | ||||
-rwxr-xr-x | infra/base-images/base-runner/test_all | 11 | ||||
-rwxr-xr-x | infra/helper.py | 28 | ||||
-rw-r--r-- | infra/libfuzzer-pipeline.groovy | 60 |
7 files changed, 109 insertions, 31 deletions
diff --git a/infra/base-images/base-builder/Dockerfile b/infra/base-images/base-builder/Dockerfile index b9ad03c9..629132df 100644 --- a/infra/base-images/base-builder/Dockerfile +++ b/infra/base-images/base-builder/Dockerfile @@ -16,7 +16,7 @@ FROM ossfuzz/base-clang MAINTAINER mike.aizatsky@gmail.com -RUN apt-get install -y git subversion jq python3 zip +RUN apt-get install -y git subversion jq python3 zip make # Default build flags for various sanitizers. ENV SANITIZER_FLAGS_address "-fsanitize=address" diff --git a/infra/base-images/base-builder/compile_afl b/infra/base-images/base-builder/compile_afl index 27a8d55d..fae25410 100644 --- a/infra/base-images/base-builder/compile_afl +++ b/infra/base-images/base-builder/compile_afl @@ -29,5 +29,10 @@ ar r $LIB_FUZZING_ENGINE $WORK/afl/*.o popd > /dev/null rm -rf $WORK/afl +# Copy afl tools necessary for fuzzing. +pushd $SRC/afl > /dev/null +make clean && make +find . -name 'afl-*' -executable -type f | xargs cp -t $OUT +popd > /dev/null echo " done." diff --git a/infra/base-images/base-runner/Dockerfile b/infra/base-images/base-runner/Dockerfile index 07c0f89f..2a07c279 100644 --- a/infra/base-images/base-runner/Dockerfile +++ b/infra/base-images/base-runner/Dockerfile @@ -28,3 +28,4 @@ ENV ASAN_OPTIONS="alloc_dealloc_mismatch=0:allocator_may_return_null=1:allocator ENV MSAN_OPTIONS="print_stats=1:strip_path_prefix=/workspace/:symbolize=1" ENV UBSAN_OPTIONS="halt_on_error=1:print_stacktrace=1:print_summary=1:strip_path_prefix=/workspace/:symbolize=1" ENV FUZZER_ARGS="-rss_limit_mb=2048 -timeout=25" +ENV AFL_FUZZER_ARGS="-m 2048" diff --git a/infra/base-images/base-runner/run_fuzzer b/infra/base-images/base-runner/run_fuzzer index 308afb26..9bce71a3 100755 --- a/infra/base-images/base-runner/run_fuzzer +++ b/infra/base-images/base-runner/run_fuzzer @@ -23,20 +23,35 @@ cd $OUT FUZZER=$1 shift -CMD_LINE="$OUT/$FUZZER $FUZZER_ARGS $@" -OPTIONS_FILE="${FUZZER}.options" -if [ -f $OPTIONS_FILE ]; then - OPTIONS_ARGS=$(grep "=" $OPTIONS_FILE | sed 's/\(\w*\)\W*=\W*\(.*\)/-\1=\2 /g' | tr '\n' ' ') - CMD_LINE="$CMD_LINE $OPTIONS_ARGS" -fi +rm -rf /tmp/input/ && mkdir /tmp/input/ SEED_CORPUS="${FUZZER}_seed_corpus.zip" if [ -f $SEED_CORPUS ]; then echo "Using seed corpus: $SEED_CORPUS" - rm -rf /tmp/seed_corpus/ && mkdir /tmp/seed_corpus/ - unzip -d /tmp/seed_corpus/ $SEED_CORPUS > /dev/null - CMD_LINE="$CMD_LINE /tmp/seed_corpus/" + unzip -d /tmp/input/ $SEED_CORPUS > /dev/null + CORPUS=/tmp/input +fi + +if [[ "$FUZZING_ENGINE" = afl ]]; then + # https://chromium.googlesource.com/chromium/src/+/master/third_party/afl/src/docs/env_variables.txt + export ASAN_OPTIONS="$ASAN_OPTIONS:abort_on_error=1:symbolize=0" + export MSAN_OPTIONS="$MSAN_OPTIONS:exit_code=86:symbolize=0" + export UBSAN_OPTIONS="$UBSAN_OPTIONS:symbolize=0" + export AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 + export AFL_SKIP_CPUFREQ=1 + rm -rf /tmp/afl_output && mkdir /tmp/afl_output + # AFL expects at least 1 file in the input dir. + echo input > /tmp/input/input + CMD_LINE="$OUT/afl-fuzz $AFL_FUZZER_ARGS -i /tmp/input -o /tmp/afl_output $@ $OUT/$FUZZER" +else + CMD_LINE="$OUT/$FUZZER $FUZZER_ARGS $@ $CORPUS" + + OPTIONS_FILE="${FUZZER}.options" + if [ -f $OPTIONS_FILE ]; then + OPTIONS_ARGS=$(grep "=" $OPTIONS_FILE | sed 's/\(\w*\)\W*=\W*\(.*\)/-\1=\2 /g' | tr '\n' ' ') + CMD_LINE="$CMD_LINE $OPTIONS_ARGS" + fi fi echo $CMD_LINE diff --git a/infra/base-images/base-runner/test_all b/infra/base-images/base-runner/test_all index 388b3928..b7285e61 100755 --- a/infra/base-images/base-runner/test_all +++ b/infra/base-images/base-runner/test_all @@ -24,8 +24,17 @@ for FUZZER_BINARY in $(find $OUT/ -executable -type f); do fi FUZZER=$(basename $FUZZER_BINARY) + if echo "$FUZZER" | grep "^afl-" > /dev/null 2>&1; then + continue + fi + echo "testing $FUZZER" - run_fuzzer $FUZZER -max_total_time=20 + if [[ "$FUZZING_ENGINE" = libfuzzer ]]; then + run_fuzzer $FUZZER -max_total_time=20 + else + export AFL_NO_UI=1 + timeout --preserve-status -s INT 20s run_fuzzer $FUZZER + fi N=$[$N+1] done diff --git a/infra/helper.py b/infra/helper.py index 62789c39..3d3b6094 100755 --- a/infra/helper.py +++ b/infra/helper.py @@ -118,6 +118,18 @@ def _get_command_string(command): return ' '.join(pipes.quote(part) for part in command) +def _add_engine_args(parser): + """Add common engine args.""" + parser.add_argument('--engine', default='libfuzzer', + choices=['libfuzzer', 'afl']) + + +def _add_sanitizer_args(parser): + """Add common sanitizer args.""" + parser.add_argument('--sanitizer', default='address', + choices=['address', 'memory', 'undefined']) + + def _build_image(image_name): """Build image.""" @@ -162,7 +174,9 @@ def build_image(build_args): def build_fuzzers(build_args): """Build fuzzers.""" parser = argparse.ArgumentParser('helper.py build_fuzzers') - parser.add_argument('-e', action='append', help="set environment variable e.g. SANITIZER=address") + _add_engine_args(parser) + _add_sanitizer_args(parser) + parser.add_argument('-e', action='append', help="set environment variable e.g. VAR=value") parser.add_argument('project_name') parser.add_argument('source_path', help='path of local source', nargs='?') @@ -172,7 +186,12 @@ def build_fuzzers(build_args): if not _build_image(args.project_name): return 1 - env = ['BUILD_UID=%d' % os.getuid()] + env = [ + 'BUILD_UID=%d' % os.getuid(), + 'FUZZING_ENGINE=' + args.engine, + 'SANITIZER=' + args.sanitizer + ] + if args.e: env += args.e @@ -205,6 +224,8 @@ def build_fuzzers(build_args): def run_fuzzer(run_args): """Runs a fuzzer in the container.""" parser = argparse.ArgumentParser('helper.py run_fuzzer') + _add_engine_args(parser) + parser.add_argument('project_name', help='name of the project') parser.add_argument('fuzzer_name', help='name of the fuzzer') parser.add_argument('fuzzer_args', help='arguments to pass to the fuzzer', @@ -220,8 +241,11 @@ def run_fuzzer(run_args): if not _build_image('base-runner'): return 1 + env = ['FUZZING_ENGINE=' + args.engine] + command = [ 'docker', 'run', '--rm', '-i', '--cap-add', 'SYS_PTRACE', + ] + sum([['-e', v] for v in env], []) + [ '-v', '%s:/out' % os.path.join(BUILD_DIR, 'out', args.project_name), '-t', 'ossfuzz/base-runner', 'run_fuzzer', diff --git a/infra/libfuzzer-pipeline.groovy b/infra/libfuzzer-pipeline.groovy index e8b4ee75..9c17c83e 100644 --- a/infra/libfuzzer-pipeline.groovy +++ b/infra/libfuzzer-pipeline.groovy @@ -27,6 +27,7 @@ def call(body) { def projectName = project["name"] ?: env.JOB_BASE_NAME def sanitizers = project["sanitizers"] ?: ["address", "undefined"] def coverageFlags = project["coverage_flags"] + def fuzzingEngines = project["fuzzing_engines"] ?: ["libfuzzer"] // Dockerfile config def dockerfileConfig = project["dockerfile"] ?: [ @@ -42,6 +43,11 @@ def call(body) { def date = java.time.format.DateTimeFormatter.ofPattern("yyyyMMddHHmm") .format(java.time.ZonedDateTime.now(java.time.ZoneOffset.UTC)) + def supportedSanitizers = [ + libfuzzer: ["address", "memory", "undefined"], + afl: ["address"] + ] + timeout(time: 6, unit: 'HOURS') { node { def workspace = pwd() @@ -80,19 +86,27 @@ def call(body) { for (int i = 0; i < sanitizers.size(); i++) { def sanitizer = sanitizers[i] dir(sanitizer) { - def out = "$workspace/out/$sanitizer" - def junit_reports = "$workspace/junit_reports/$sanitizer" - sh "mkdir -p $out" - sh "mkdir -p $junit_reports" - stage("$sanitizer sanitizer") { - // Run image to produce fuzzers - def env = "-e SANITIZER=\"${sanitizer}\" " - if (coverageFlags != null) { - env += "-e COVERAGE_FLAGS=\"${coverageFlags}\" " + for (int j = 0; j < fuzzingEngines.size(); j++) { + def engine = fuzzingEngines[j] + if (!supportedSanitizers[engine].contains(sanitizer)) { + continue + } + dir (engine) { + def out = "$workspace/out/$sanitizer/$engine" + def junit_reports = "$workspace/junit_reports/$sanitizer/$engine" + sh "mkdir -p $out" + sh "mkdir -p $junit_reports" + stage("$sanitizer sanitizer ($engine)") { + // Run image to produce fuzzers + def env = "-e SANITIZER=\"${sanitizer}\" -e FUZZING_ENGINE=\"${engine}\" " + if (coverageFlags != null) { + env += "-e COVERAGE_FLAGS=\"${coverageFlags}\" " + } + sh "docker run --rm $dockerRunOptions -v $out:/out $env -t $dockerTag compile" + // Test all fuzzers + sh "docker run --rm $dockerRunOptions -v $out:/out -v $junit_reports:/junit_reports -e TEST_SUITE=\"${projectName}.${sanitizer}.${engine}\" -t ossfuzz/base-runner test_report" + } } - sh "docker run --rm $dockerRunOptions -v $out:/out $env -t $dockerTag compile" - // Test all fuzzers - sh "docker run --rm $dockerRunOptions -v $out:/out -v $junit_reports:/junit_reports -e TEST_SUITE=\"${projectName}.${sanitizer}.\" -t ossfuzz/base-runner test_report" } } } @@ -103,12 +117,22 @@ def call(body) { for (int i = 0; i < sanitizers.size(); i++) { def sanitizer = sanitizers[i] dir (sanitizer) { - def zipFile = "$projectName-$sanitizer-${date}.zip" - sh "zip -r $zipFile *" - sh "gsutil cp $zipFile gs://clusterfuzz-builds/$projectName/" - def stampedSrcmap = "$projectName-$sanitizer-${date}.srcmap.json" - sh "cp $srcmapFile $stampedSrcmap" - sh "gsutil cp $stampedSrcmap gs://clusterfuzz-builds/$projectName/" + for (int j = 0; j < fuzzingEngines.size(); j++) { + def engine = fuzzingEngines[j] + if (!supportedSanitizers[engine].contains(sanitizer)) { + continue + } + + def upload_bucket = engine == "libfuzzer" ? "clusterfuzz-builds" : "clusterfuzz-builds-afl" + dir(engine) { + def zipFile = "$projectName-$sanitizer-${date}.zip" + sh "zip -r $zipFile *" + sh "gsutil cp $zipFile gs://$upload_bucket/$projectName/" + def stampedSrcmap = "$projectName-$sanitizer-${date}.srcmap.json" + sh "cp $srcmapFile $stampedSrcmap" + sh "gsutil cp $stampedSrcmap gs://$upload_bucket/$projectName/" + } + } } } } |