aboutsummaryrefslogtreecommitdiffhomepage
path: root/infra
diff options
context:
space:
mode:
authorGravatar Oliver Chang <oliverchang@users.noreply.github.com>2017-02-16 15:09:37 -0800
committerGravatar GitHub <noreply@github.com>2017-02-16 15:09:37 -0800
commit2e00fe90d193f7cb8ab82ec27e9b37a3ad02956c (patch)
tree3a735af9d9c61d905d5ed0ef94ca21fd8fb8bf0c /infra
parent810b7fe47bf9e54a54ff36944f8860879af9dff2 (diff)
[infra] (experimental) Support building with AFL (#396)
Diffstat (limited to 'infra')
-rw-r--r--infra/base-images/base-builder/Dockerfile2
-rw-r--r--infra/base-images/base-builder/compile_afl5
-rw-r--r--infra/base-images/base-runner/Dockerfile1
-rwxr-xr-xinfra/base-images/base-runner/run_fuzzer33
-rwxr-xr-xinfra/base-images/base-runner/test_all11
-rwxr-xr-xinfra/helper.py28
-rw-r--r--infra/libfuzzer-pipeline.groovy60
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/"
+ }
+ }
}
}
}