From e953a6a5bd566acfb7390f531605025ca05d690a Mon Sep 17 00:00:00 2001 From: gutaotao <1271159369@qq.com> Date: Tue, 26 Sep 2023 01:31:56 +0800 Subject: [PATCH] Orchesctra: A Collaborative Fuzzer Framework --- fuzzers/orchestra_116/builder.Dockerfile | 79 ++++ fuzzers/orchestra_116/fuzzer.py | 425 ++++++++++++++++++ fuzzers/orchestra_116/runner.Dockerfile | 39 ++ fuzzers/orchestra_216/builder.Dockerfile | 79 ++++ fuzzers/orchestra_216/fuzzer.py | 425 ++++++++++++++++++ fuzzers/orchestra_216/runner.Dockerfile | 39 ++ fuzzers/orchestra_236/builder.Dockerfile | 79 ++++ fuzzers/orchestra_236/fuzzer.py | 425 ++++++++++++++++++ fuzzers/orchestra_236/runner.Dockerfile | 39 ++ fuzzers/orchestra_339/builder.Dockerfile | 79 ++++ fuzzers/orchestra_339/fuzzer.py | 425 ++++++++++++++++++ fuzzers/orchestra_339/runner.Dockerfile | 39 ++ fuzzers/orchestra_4310/builder.Dockerfile | 79 ++++ fuzzers/orchestra_4310/fuzzer.py | 425 ++++++++++++++++++ fuzzers/orchestra_4310/runner.Dockerfile | 39 ++ .../orchestra_aflplusplus/builder.Dockerfile | 48 ++ fuzzers/orchestra_aflplusplus/fuzzer.py | 344 ++++++++++++++ .../orchestra_aflplusplus/runner.Dockerfile | 34 ++ .../orchestra_honggfuzz/builder.Dockerfile | 57 +++ fuzzers/orchestra_honggfuzz/fuzzer.py | 146 ++++++ fuzzers/orchestra_honggfuzz/runner.Dockerfile | 9 + .../orchestra_libfuzzer/builder.Dockerfile | 34 ++ fuzzers/orchestra_libfuzzer/fuzzer.py | 149 ++++++ fuzzers/orchestra_libfuzzer/runner.Dockerfile | 1 + service/experiment-requests.yaml | 13 + service/gcbrun_experiment.py | 1 + 26 files changed, 3551 insertions(+) create mode 100644 fuzzers/orchestra_116/builder.Dockerfile create mode 100644 fuzzers/orchestra_116/fuzzer.py create mode 100644 fuzzers/orchestra_116/runner.Dockerfile create mode 100644 fuzzers/orchestra_216/builder.Dockerfile create mode 100644 fuzzers/orchestra_216/fuzzer.py create mode 100644 fuzzers/orchestra_216/runner.Dockerfile create mode 100644 fuzzers/orchestra_236/builder.Dockerfile create mode 100644 fuzzers/orchestra_236/fuzzer.py create mode 100644 fuzzers/orchestra_236/runner.Dockerfile create mode 100644 fuzzers/orchestra_339/builder.Dockerfile create mode 100644 fuzzers/orchestra_339/fuzzer.py create mode 100644 fuzzers/orchestra_339/runner.Dockerfile create mode 100644 fuzzers/orchestra_4310/builder.Dockerfile create mode 100644 fuzzers/orchestra_4310/fuzzer.py create mode 100644 fuzzers/orchestra_4310/runner.Dockerfile create mode 100644 fuzzers/orchestra_aflplusplus/builder.Dockerfile create mode 100644 fuzzers/orchestra_aflplusplus/fuzzer.py create mode 100644 fuzzers/orchestra_aflplusplus/runner.Dockerfile create mode 100644 fuzzers/orchestra_honggfuzz/builder.Dockerfile create mode 100644 fuzzers/orchestra_honggfuzz/fuzzer.py create mode 100644 fuzzers/orchestra_honggfuzz/runner.Dockerfile create mode 100644 fuzzers/orchestra_libfuzzer/builder.Dockerfile create mode 100644 fuzzers/orchestra_libfuzzer/fuzzer.py create mode 100644 fuzzers/orchestra_libfuzzer/runner.Dockerfile diff --git a/fuzzers/orchestra_116/builder.Dockerfile b/fuzzers/orchestra_116/builder.Dockerfile new file mode 100644 index 000000000..77c035a0e --- /dev/null +++ b/fuzzers/orchestra_116/builder.Dockerfile @@ -0,0 +1,79 @@ +ARG parent_image +FROM $parent_image + +# +# AFLplusplus +# + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + python3-dev \ + python3-setuptools \ + automake \ + cmake \ + git \ + flex \ + bison \ + libglib2.0-dev \ + libpixman-1-dev \ + cargo \ + libgtk-3-dev \ + # for QEMU mode + ninja-build \ + gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev \ + libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev + +RUN git clone -b master https://github.com/gtt1995/GMFuzzer.git /gmfuzzer +RUN git clone -b fuzzers https://github.com/gtt1995/GMFuzzer.git /fuzzers +#COPY AFLplusplus /aflplusplus + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cp -r /fuzzers/AFLplusplus /aflplusplus && \ + cd /aflplusplus && \ + unset CFLAGS CXXFLAGS && \ + export CC=clang AFL_NO_X86=1 && \ + PYTHON_INCLUDE=/ make && \ + make install && \ + cp utils/aflpp_driver/libAFLDriver.a / && \ + make -C custom_mutators/autotokens && \ + cp -f custom_mutators/autotokens/autotokens.so . + + +#COPY wingfuzz wingfuzz + +RUN cp -r /fuzzers/wingfuzz /wingfuzz && \ + cd /wingfuzz && \ + ./build.sh && cd instrument && ./build.sh && clang -c WeakSym.c && \ + cp ../libFuzzer.a /libWingfuzz.a && cp WeakSym.o / && cp LoadCmpTracer.so / + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid. +RUN apt-get install -y \ + libbfd-dev \ + libunwind-dev \ + libblocksruntime-dev \ + liblzma-dev + +#COPY honggfuzz /honggfuzz + +# Set CFLAGS use honggfuzz's defaults except for -mnative which can build CPU +# dependent code that may not work on the machines we actually fuzz on. +# Create an empty object file which will become the FUZZER_LIB lib (since +# honggfuzz doesn't need this when hfuzz-clang(++) is used). +RUN cp -r /fuzzers/honggfuzz /honggfuzz && \ + cd /honggfuzz && \ + CFLAGS="-O3 -funroll-loops" make && \ + touch empty_lib.c && \ + cc -c -o empty_lib.o empty_lib.c + + +RUN cd /gmfuzzer &&\ + (for f in *.cpp; do \ + clang++ -stdlib=libc++ -fPIC -O2 -std=c++11 $f -c & \ + done && wait) && \ + ar r /usr/lib/libHCFUZZER.a *.o diff --git a/fuzzers/orchestra_116/fuzzer.py b/fuzzers/orchestra_116/fuzzer.py new file mode 100644 index 000000000..28b5132c7 --- /dev/null +++ b/fuzzers/orchestra_116/fuzzer.py @@ -0,0 +1,425 @@ +# Copyright 2020 Google LLC +# +# 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. +# +"""Integration code for Collabtive Fuzzer Framework.""" + +import os +import shutil +import subprocess + +from fuzzers import utils +from fuzzers.afl import fuzzer as afl_fuzzer +def get_cmplog_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'cmplog') + + +def get_uninstrumented_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'uninstrumented') + + +def get_aflpp_target_dir(output_directory): + """Return path to AFL++'s target directory.""" + return os.path.join(output_directory, 'aflplusplus') + + +def get_wingfuzz_target_dir(output_directory): + """Return path to wingfuzz's target directory.""" + return os.path.join(output_directory, 'wingfuzz') + +def get_honggfuzz_target_dir(output_directory): + """Return path to Honggfuzz's target directory.""" + return os.path.join(output_directory, 'honggfuzz') + + +def honggfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + + new_env['CC'] = '/honggfuzz/hfuzz_cc/hfuzz-clang' + new_env['CXX'] = '/honggfuzz/hfuzz_cc/hfuzz-clang++' + new_env['FUZZER_LIB'] = '/honggfuzz/empty_lib.o' + + utils.build_benchmark(env=new_env) + + print('[post_build] Copying honggfuzz to $OUT directory') + # Copy over honggfuzz's main fuzzing binary. + shutil.copy('/honggfuzz/honggfuzz', os.environ['OUT']) + + +def wingfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + cflags = [ + '-fsanitize=fuzzer-no-link', + '-fno-sanitize-coverage=trace-cmp', + '-fno-legacy-pass-manager', + '-fpass-plugin=/LoadCmpTracer.so', + '-w', + '-Wl,/WeakSym.o' + ] + utils.append_flags('CFLAGS', cflags, new_env) + utils.append_flags('CXXFLAGS', cflags, new_env) + + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/libWingfuzz.a' + utils.build_benchmark(env=new_env) + +def aflplusplus_build(*args): # pylint: disable=too-many-branches,too-many-statements + """Build benchmark.""" + # BUILD_MODES is not already supported by fuzzbench, meanwhile we provide + # a default configuration. + + build_modes = list(args) + if 'BUILD_MODES' in os.environ: + build_modes = os.environ['BUILD_MODES'].split(',') + + # Placeholder comment. + build_directory = os.environ['OUT'] + + # If nothing was set this is the default: + if not build_modes: + build_modes = ['tracepc', 'cmplog', 'dict2file'] + + # For bug type benchmarks we have to instrument via native clang pcguard :( + build_flags = os.environ['CFLAGS'] + + if build_flags.find( + 'array-bounds' + ) != -1 and 'qemu' not in build_modes and 'classic' not in build_modes: + if 'gcc' not in build_modes: + build_modes[0] = 'native' + + # Instrumentation coverage modes: + if 'lto' in build_modes: + os.environ['CC'] = '/aflplusplus/afl-clang-lto' + os.environ['CXX'] = '/aflplusplus/afl-clang-lto++' + edge_file = build_directory + '/aflpp_edges.txt' + os.environ['AFL_LLVM_DOCUMENT_IDS'] = edge_file + if os.path.isfile('/usr/local/bin/llvm-ranlib-13'): + os.environ['RANLIB'] = 'llvm-ranlib-13' + os.environ['AR'] = 'llvm-ar-13' + os.environ['AS'] = 'llvm-as-13' + elif os.path.isfile('/usr/local/bin/llvm-ranlib-12'): + os.environ['RANLIB'] = 'llvm-ranlib-12' + os.environ['AR'] = 'llvm-ar-12' + os.environ['AS'] = 'llvm-as-12' + else: + os.environ['RANLIB'] = 'llvm-ranlib' + os.environ['AR'] = 'llvm-ar' + os.environ['AS'] = 'llvm-as' + elif 'qemu' in build_modes: + os.environ['CC'] = 'clang' + os.environ['CXX'] = 'clang++' + elif 'gcc' in build_modes: + os.environ['CC'] = 'afl-gcc-fast' + os.environ['CXX'] = 'afl-g++-fast' + if build_flags.find('array-bounds') != -1: + os.environ['CFLAGS'] = '-fsanitize=address -O1' + os.environ['CXXFLAGS'] = '-fsanitize=address -O1' + else: + os.environ['CFLAGS'] = '' + os.environ['CXXFLAGS'] = '' + os.environ['CPPFLAGS'] = '' + else: + os.environ['CC'] = '/aflplusplus/afl-clang-fast' + os.environ['CXX'] = '/aflplusplus/afl-clang-fast++' + + print('AFL++ build: ') + print(build_modes) + + if 'qemu' in build_modes or 'symcc' in build_modes: + os.environ['CFLAGS'] = ' '.join(utils.NO_SANITIZER_COMPAT_CFLAGS) + cxxflags = [utils.LIBCPLUSPLUS_FLAG] + utils.NO_SANITIZER_COMPAT_CFLAGS + os.environ['CXXFLAGS'] = ' '.join(cxxflags) + + if 'tracepc' in build_modes or 'pcguard' in build_modes: + os.environ['AFL_LLVM_USE_TRACE_PC'] = '1' + elif 'classic' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'CLASSIC' + elif 'native' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'LLVMNATIVE' + + # Instrumentation coverage options: + # Do not use a fixed map location (LTO only) + if 'dynamic' in build_modes: + os.environ['AFL_LLVM_MAP_DYNAMIC'] = '1' + # Use a fixed map location (LTO only) + if 'fixed' in build_modes: + os.environ['AFL_LLVM_MAP_ADDR'] = '0x10000' + # Generate an extra dictionary. + if 'dict2file' in build_modes or 'native' in build_modes: + os.environ['AFL_LLVM_DICT2FILE'] = build_directory + '/afl++.dict' + os.environ['AFL_LLVM_DICT2FILE_NO_MAIN'] = '1' + # Enable context sentitivity for LLVM mode (non LTO only) + if 'ctx' in build_modes: + os.environ['AFL_LLVM_CTX'] = '1' + # Enable N-gram coverage for LLVM mode (non LTO only) + if 'ngram2' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '2' + elif 'ngram3' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '3' + elif 'ngram4' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '4' + elif 'ngram5' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '5' + elif 'ngram6' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '6' + elif 'ngram7' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '7' + elif 'ngram8' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '8' + elif 'ngram16' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '16' + if 'ctx1' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '1' + elif 'ctx2' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '2' + elif 'ctx3' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '3' + elif 'ctx4' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '4' + + # Only one of the following OR cmplog + # enable laf-intel compare splitting + if 'laf' in build_modes: + os.environ['AFL_LLVM_LAF_SPLIT_SWITCHES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_COMPARES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_FLOATS'] = '1' + if 'autodict' not in build_modes: + os.environ['AFL_LLVM_LAF_TRANSFORM_COMPARES'] = '1' + + if 'eclipser' in build_modes: + os.environ['FUZZER_LIB'] = '/libStandaloneFuzzTarget.a' + else: + os.environ['FUZZER_LIB'] = '/libAFLDriver.a' + + # Some benchmarks like lcms. (see: + # https://github.com/mm2/Little-CMS/commit/ab1093539b4287c233aca6a3cf53b234faceb792#diff-f0e6d05e72548974e852e8e55dffc4ccR212) + # fail to compile if the compiler outputs things to stderr in unexpected + # cases. Prevent these failures by using AFL_QUIET to stop afl-clang-fast + # from writing AFL specific messages to stderr. + os.environ['AFL_QUIET'] = '1' + os.environ['AFL_MAP_SIZE'] = '2621440' + + src = os.getenv('SRC') + work = os.getenv('WORK') + + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + utils.build_benchmark() + + if 'cmplog' in build_modes and 'qemu' not in build_modes: + + # CmpLog requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['AFL_LLVM_CMPLOG'] = '1' + + # For CmpLog build, set the OUT and FUZZ_TARGET environment + # variable to point to the new CmpLog build directory. + cmplog_build_directory = get_cmplog_build_directory(build_directory) + os.mkdir(cmplog_build_directory) + new_env['OUT'] = cmplog_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(cmplog_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for CmpLog fuzzing target') + utils.build_benchmark(env=new_env) + + if 'symcc' in build_modes: + + symcc_build_directory = get_uninstrumented_build_directory( + build_directory) + os.mkdir(symcc_build_directory) + + # symcc requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['CC'] = '/symcc/build/symcc' + new_env['CXX'] = '/symcc/build/sym++' + new_env['SYMCC_OUTPUT_DIR'] = '/tmp' + new_env['CXXFLAGS'] = new_env['CXXFLAGS'].replace('-stlib=libc++', '') + new_env['FUZZER_LIB'] = '/libfuzzer-harness.o' + new_env['OUT'] = symcc_build_directory + new_env['SYMCC_LIBCXX_PATH'] = '/libcxx_native_build' + new_env['SYMCC_NO_SYMBOLIC_INPUT'] = '1' + new_env['SYMCC_SILENT'] = '1' + + # For symcc build, set the OUT and FUZZ_TARGET environment + # variable to point to the new symcc build directory. + new_env['OUT'] = symcc_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(symcc_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for symcc fuzzing target') + utils.build_benchmark(env=new_env) + + shutil.copy('/aflplusplus/afl-fuzz', build_directory) + if os.path.exists('/aflplusplus/afl-qemu-trace'): + shutil.copy('/aflplusplus/afl-qemu-trace', build_directory) + if os.path.exists('/aflpp_qemu_driver_hook.so'): + shutil.copy('/aflpp_qemu_driver_hook.so', build_directory) + if os.path.exists('/get_frida_entry.sh'): + shutil.copy('/aflplusplus/afl-frida-trace.so', build_directory) + shutil.copy('/get_frida_entry.sh', build_directory) + shutil.copy('/aflplusplus/autotokens.so', build_directory) + + +def build_aflpp(): + """Build benchmark with AFL++.""" + print('Building with AFL++') + out_dir = os.environ['OUT'] + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + os.environ['OUT'] = aflpp_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(src): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + aflplusplus_build() + os.environ['OUT'] = out_dir + +def build_wingfuzz(): + """Build benchmark with wingfuzz.""" + print('Building with wingfuzz') + out_dir = os.environ['OUT'] + wingfuzz_target_dir = get_wingfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = wingfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + wingfuzz_build() + os.environ['OUT'] = out_dir + +def build_honggfuzz(): + """Build benchmark with Honggfuzz.""" + print('Building with Honggfuzz') + out_dir = os.environ['OUT'] + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = honggfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + honggfuzz_build() + os.environ['OUT'] = out_dir + +def prepare_build_environment(): + """Prepare build environment.""" + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + wingfuzz_target_dir = get_wingfuzz_target_dir(os.environ['OUT']) + + os.makedirs(aflpp_target_dir, exist_ok=True) + os.makedirs(honggfuzz_target_dir, exist_ok=True) + os.makedirs(wingfuzz_target_dir, exist_ok=True) + +def build(): + """Build benchmark.""" + prepare_build_environment() + new_env = os.environ.copy() + cflags = ['-fsanitize=fuzzer-no-link'] + utils.append_flags('CFLAGS', cflags, env=new_env) + utils.append_flags('CXXFLAGS', cflags, env=new_env) + src = new_env.get('SRC') + work = new_env.get('WORK') + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/usr/lib/libHCFUZZER.a' + with utils.restore_directory(src), utils.restore_directory(work): + utils.build_benchmark(env=new_env) + + + build_wingfuzz() + build_honggfuzz() + build_aflpp() + + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer. Wrapper that uses the defaults when calling + run_fuzzer.""" + run_fuzzer(input_corpus, + output_corpus, + target_binary, + extra_flags=['-keep_seed=0', '-cross_over_uniform_dist=1']) + + +def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None): + """Run fuzzer.""" + if extra_flags is None: + extra_flags = [] + + # Seperate out corpus and crash directories as sub-directories of + # |output_corpus| to avoid conflicts when corpus directory is reloaded. + crashes_dir = os.path.join(output_corpus, 'crashes') + output_corpus = os.path.join(output_corpus, 'corpus') + os.makedirs(crashes_dir) + os.makedirs(output_corpus) + + #prepare_fuzz_environment(input_corpus) + afl_fuzzer.prepare_fuzz_environment(input_corpus) + binary = os.path.basename(target_binary) + + os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' + os.environ['AFL_FAST_CAL'] = '1' + os.environ['AFL_NO_WARN_INSTABILITY'] = '1' + + flags = [ + '-print_final_stats=1', + # `close_fd_mask` to prevent too much logging output from the target. + '-close_fd_mask=3', + # Run in fork mode to allow ignoring ooms, timeouts, crashes and + # continue fuzzing indefinitely. + f'-target_program={binary}', + '-fuzzers=aflplusplus,wingfuzz,honggfuzz', + '-fork=1', + '-fork_job_budget_coe=1', + '-fork_num_seeds=1', + '-fork_max_job_time=600', + '-ignore_ooms=1', + '-ignore_timeouts=1', + '-ignore_crashes=1', + + # Don't use LSAN's leak detection. Other fuzzers won't be using it and + # using it will cause libFuzzer to find "crashes" no one cares about. + '-detect_leaks=0', + + # Store crashes along with corpus for bug based benchmarking. + f'-artifact_prefix={crashes_dir}/', + ] + flags += extra_flags + + if 'ADDITIONAL_ARGS' in os.environ: + flags += os.environ['ADDITIONAL_ARGS'].split(' ') + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + flags.append('-dict=' + dictionary_path) + + command = [target_binary] + flags + [output_corpus, input_corpus] + print('[run_fuzzer] Running command: ' + ' '.join(command)) + subprocess.check_call(command) diff --git a/fuzzers/orchestra_116/runner.Dockerfile b/fuzzers/orchestra_116/runner.Dockerfile new file mode 100644 index 000000000..6eb790acf --- /dev/null +++ b/fuzzers/orchestra_116/runner.Dockerfile @@ -0,0 +1,39 @@ +FROM gcr.io/fuzzbench/base-image + +# NOTE Comiple Python again with `--enabled-shared`. + +# Python 3.10.8 is not the default version in Ubuntu 20.04 (Focal Fossa). +ENV PYTHON_VERSION 3.10.8 + +RUN cd /tmp/ && \ + curl -O https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tar.xz && \ + tar -xvf Python-$PYTHON_VERSION.tar.xz > /dev/null && \ + cd Python-$PYTHON_VERSION && \ + ./configure \ + --enable-loadable-sqlite-extensions \ + --enable-optimizations \ + --enable-shared \ + > /dev/null && \ + make -j install > /dev/null && \ + rm -r /tmp/Python-$PYTHON_VERSION.tar.xz /tmp/Python-$PYTHON_VERSION + +# +# AFLplusplus +# + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 +ENV AFL_NO_AFFINITY=1 + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid +RUN apt-get update -y && apt-get install -y libbfd-dev libunwind-dev + diff --git a/fuzzers/orchestra_216/builder.Dockerfile b/fuzzers/orchestra_216/builder.Dockerfile new file mode 100644 index 000000000..77c035a0e --- /dev/null +++ b/fuzzers/orchestra_216/builder.Dockerfile @@ -0,0 +1,79 @@ +ARG parent_image +FROM $parent_image + +# +# AFLplusplus +# + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + python3-dev \ + python3-setuptools \ + automake \ + cmake \ + git \ + flex \ + bison \ + libglib2.0-dev \ + libpixman-1-dev \ + cargo \ + libgtk-3-dev \ + # for QEMU mode + ninja-build \ + gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev \ + libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev + +RUN git clone -b master https://github.com/gtt1995/GMFuzzer.git /gmfuzzer +RUN git clone -b fuzzers https://github.com/gtt1995/GMFuzzer.git /fuzzers +#COPY AFLplusplus /aflplusplus + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cp -r /fuzzers/AFLplusplus /aflplusplus && \ + cd /aflplusplus && \ + unset CFLAGS CXXFLAGS && \ + export CC=clang AFL_NO_X86=1 && \ + PYTHON_INCLUDE=/ make && \ + make install && \ + cp utils/aflpp_driver/libAFLDriver.a / && \ + make -C custom_mutators/autotokens && \ + cp -f custom_mutators/autotokens/autotokens.so . + + +#COPY wingfuzz wingfuzz + +RUN cp -r /fuzzers/wingfuzz /wingfuzz && \ + cd /wingfuzz && \ + ./build.sh && cd instrument && ./build.sh && clang -c WeakSym.c && \ + cp ../libFuzzer.a /libWingfuzz.a && cp WeakSym.o / && cp LoadCmpTracer.so / + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid. +RUN apt-get install -y \ + libbfd-dev \ + libunwind-dev \ + libblocksruntime-dev \ + liblzma-dev + +#COPY honggfuzz /honggfuzz + +# Set CFLAGS use honggfuzz's defaults except for -mnative which can build CPU +# dependent code that may not work on the machines we actually fuzz on. +# Create an empty object file which will become the FUZZER_LIB lib (since +# honggfuzz doesn't need this when hfuzz-clang(++) is used). +RUN cp -r /fuzzers/honggfuzz /honggfuzz && \ + cd /honggfuzz && \ + CFLAGS="-O3 -funroll-loops" make && \ + touch empty_lib.c && \ + cc -c -o empty_lib.o empty_lib.c + + +RUN cd /gmfuzzer &&\ + (for f in *.cpp; do \ + clang++ -stdlib=libc++ -fPIC -O2 -std=c++11 $f -c & \ + done && wait) && \ + ar r /usr/lib/libHCFUZZER.a *.o diff --git a/fuzzers/orchestra_216/fuzzer.py b/fuzzers/orchestra_216/fuzzer.py new file mode 100644 index 000000000..583b37ce5 --- /dev/null +++ b/fuzzers/orchestra_216/fuzzer.py @@ -0,0 +1,425 @@ +# Copyright 2020 Google LLC +# +# 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. +# +"""Integration code for Collabtive Fuzzer Framework.""" + +import os +import shutil +import subprocess + +from fuzzers import utils +from fuzzers.afl import fuzzer as afl_fuzzer +def get_cmplog_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'cmplog') + + +def get_uninstrumented_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'uninstrumented') + + +def get_aflpp_target_dir(output_directory): + """Return path to AFL++'s target directory.""" + return os.path.join(output_directory, 'aflplusplus') + + +def get_wingfuzz_target_dir(output_directory): + """Return path to wingfuzz's target directory.""" + return os.path.join(output_directory, 'wingfuzz') + +def get_honggfuzz_target_dir(output_directory): + """Return path to Honggfuzz's target directory.""" + return os.path.join(output_directory, 'honggfuzz') + + +def honggfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + + new_env['CC'] = '/honggfuzz/hfuzz_cc/hfuzz-clang' + new_env['CXX'] = '/honggfuzz/hfuzz_cc/hfuzz-clang++' + new_env['FUZZER_LIB'] = '/honggfuzz/empty_lib.o' + + utils.build_benchmark(env=new_env) + + print('[post_build] Copying honggfuzz to $OUT directory') + # Copy over honggfuzz's main fuzzing binary. + shutil.copy('/honggfuzz/honggfuzz', os.environ['OUT']) + + +def wingfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + cflags = [ + '-fsanitize=fuzzer-no-link', + '-fno-sanitize-coverage=trace-cmp', + '-fno-legacy-pass-manager', + '-fpass-plugin=/LoadCmpTracer.so', + '-w', + '-Wl,/WeakSym.o' + ] + utils.append_flags('CFLAGS', cflags, new_env) + utils.append_flags('CXXFLAGS', cflags, new_env) + + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/libWingfuzz.a' + utils.build_benchmark(env=new_env) + +def aflplusplus_build(*args): # pylint: disable=too-many-branches,too-many-statements + """Build benchmark.""" + # BUILD_MODES is not already supported by fuzzbench, meanwhile we provide + # a default configuration. + + build_modes = list(args) + if 'BUILD_MODES' in os.environ: + build_modes = os.environ['BUILD_MODES'].split(',') + + # Placeholder comment. + build_directory = os.environ['OUT'] + + # If nothing was set this is the default: + if not build_modes: + build_modes = ['tracepc', 'cmplog', 'dict2file'] + + # For bug type benchmarks we have to instrument via native clang pcguard :( + build_flags = os.environ['CFLAGS'] + + if build_flags.find( + 'array-bounds' + ) != -1 and 'qemu' not in build_modes and 'classic' not in build_modes: + if 'gcc' not in build_modes: + build_modes[0] = 'native' + + # Instrumentation coverage modes: + if 'lto' in build_modes: + os.environ['CC'] = '/aflplusplus/afl-clang-lto' + os.environ['CXX'] = '/aflplusplus/afl-clang-lto++' + edge_file = build_directory + '/aflpp_edges.txt' + os.environ['AFL_LLVM_DOCUMENT_IDS'] = edge_file + if os.path.isfile('/usr/local/bin/llvm-ranlib-13'): + os.environ['RANLIB'] = 'llvm-ranlib-13' + os.environ['AR'] = 'llvm-ar-13' + os.environ['AS'] = 'llvm-as-13' + elif os.path.isfile('/usr/local/bin/llvm-ranlib-12'): + os.environ['RANLIB'] = 'llvm-ranlib-12' + os.environ['AR'] = 'llvm-ar-12' + os.environ['AS'] = 'llvm-as-12' + else: + os.environ['RANLIB'] = 'llvm-ranlib' + os.environ['AR'] = 'llvm-ar' + os.environ['AS'] = 'llvm-as' + elif 'qemu' in build_modes: + os.environ['CC'] = 'clang' + os.environ['CXX'] = 'clang++' + elif 'gcc' in build_modes: + os.environ['CC'] = 'afl-gcc-fast' + os.environ['CXX'] = 'afl-g++-fast' + if build_flags.find('array-bounds') != -1: + os.environ['CFLAGS'] = '-fsanitize=address -O1' + os.environ['CXXFLAGS'] = '-fsanitize=address -O1' + else: + os.environ['CFLAGS'] = '' + os.environ['CXXFLAGS'] = '' + os.environ['CPPFLAGS'] = '' + else: + os.environ['CC'] = '/aflplusplus/afl-clang-fast' + os.environ['CXX'] = '/aflplusplus/afl-clang-fast++' + + print('AFL++ build: ') + print(build_modes) + + if 'qemu' in build_modes or 'symcc' in build_modes: + os.environ['CFLAGS'] = ' '.join(utils.NO_SANITIZER_COMPAT_CFLAGS) + cxxflags = [utils.LIBCPLUSPLUS_FLAG] + utils.NO_SANITIZER_COMPAT_CFLAGS + os.environ['CXXFLAGS'] = ' '.join(cxxflags) + + if 'tracepc' in build_modes or 'pcguard' in build_modes: + os.environ['AFL_LLVM_USE_TRACE_PC'] = '1' + elif 'classic' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'CLASSIC' + elif 'native' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'LLVMNATIVE' + + # Instrumentation coverage options: + # Do not use a fixed map location (LTO only) + if 'dynamic' in build_modes: + os.environ['AFL_LLVM_MAP_DYNAMIC'] = '1' + # Use a fixed map location (LTO only) + if 'fixed' in build_modes: + os.environ['AFL_LLVM_MAP_ADDR'] = '0x10000' + # Generate an extra dictionary. + if 'dict2file' in build_modes or 'native' in build_modes: + os.environ['AFL_LLVM_DICT2FILE'] = build_directory + '/afl++.dict' + os.environ['AFL_LLVM_DICT2FILE_NO_MAIN'] = '1' + # Enable context sentitivity for LLVM mode (non LTO only) + if 'ctx' in build_modes: + os.environ['AFL_LLVM_CTX'] = '1' + # Enable N-gram coverage for LLVM mode (non LTO only) + if 'ngram2' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '2' + elif 'ngram3' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '3' + elif 'ngram4' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '4' + elif 'ngram5' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '5' + elif 'ngram6' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '6' + elif 'ngram7' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '7' + elif 'ngram8' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '8' + elif 'ngram16' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '16' + if 'ctx1' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '1' + elif 'ctx2' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '2' + elif 'ctx3' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '3' + elif 'ctx4' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '4' + + # Only one of the following OR cmplog + # enable laf-intel compare splitting + if 'laf' in build_modes: + os.environ['AFL_LLVM_LAF_SPLIT_SWITCHES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_COMPARES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_FLOATS'] = '1' + if 'autodict' not in build_modes: + os.environ['AFL_LLVM_LAF_TRANSFORM_COMPARES'] = '1' + + if 'eclipser' in build_modes: + os.environ['FUZZER_LIB'] = '/libStandaloneFuzzTarget.a' + else: + os.environ['FUZZER_LIB'] = '/libAFLDriver.a' + + # Some benchmarks like lcms. (see: + # https://github.com/mm2/Little-CMS/commit/ab1093539b4287c233aca6a3cf53b234faceb792#diff-f0e6d05e72548974e852e8e55dffc4ccR212) + # fail to compile if the compiler outputs things to stderr in unexpected + # cases. Prevent these failures by using AFL_QUIET to stop afl-clang-fast + # from writing AFL specific messages to stderr. + os.environ['AFL_QUIET'] = '1' + os.environ['AFL_MAP_SIZE'] = '2621440' + + src = os.getenv('SRC') + work = os.getenv('WORK') + + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + utils.build_benchmark() + + if 'cmplog' in build_modes and 'qemu' not in build_modes: + + # CmpLog requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['AFL_LLVM_CMPLOG'] = '1' + + # For CmpLog build, set the OUT and FUZZ_TARGET environment + # variable to point to the new CmpLog build directory. + cmplog_build_directory = get_cmplog_build_directory(build_directory) + os.mkdir(cmplog_build_directory) + new_env['OUT'] = cmplog_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(cmplog_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for CmpLog fuzzing target') + utils.build_benchmark(env=new_env) + + if 'symcc' in build_modes: + + symcc_build_directory = get_uninstrumented_build_directory( + build_directory) + os.mkdir(symcc_build_directory) + + # symcc requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['CC'] = '/symcc/build/symcc' + new_env['CXX'] = '/symcc/build/sym++' + new_env['SYMCC_OUTPUT_DIR'] = '/tmp' + new_env['CXXFLAGS'] = new_env['CXXFLAGS'].replace('-stlib=libc++', '') + new_env['FUZZER_LIB'] = '/libfuzzer-harness.o' + new_env['OUT'] = symcc_build_directory + new_env['SYMCC_LIBCXX_PATH'] = '/libcxx_native_build' + new_env['SYMCC_NO_SYMBOLIC_INPUT'] = '1' + new_env['SYMCC_SILENT'] = '1' + + # For symcc build, set the OUT and FUZZ_TARGET environment + # variable to point to the new symcc build directory. + new_env['OUT'] = symcc_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(symcc_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for symcc fuzzing target') + utils.build_benchmark(env=new_env) + + shutil.copy('/aflplusplus/afl-fuzz', build_directory) + if os.path.exists('/aflplusplus/afl-qemu-trace'): + shutil.copy('/aflplusplus/afl-qemu-trace', build_directory) + if os.path.exists('/aflpp_qemu_driver_hook.so'): + shutil.copy('/aflpp_qemu_driver_hook.so', build_directory) + if os.path.exists('/get_frida_entry.sh'): + shutil.copy('/aflplusplus/afl-frida-trace.so', build_directory) + shutil.copy('/get_frida_entry.sh', build_directory) + shutil.copy('/aflplusplus/autotokens.so', build_directory) + + +def build_aflpp(): + """Build benchmark with AFL++.""" + print('Building with AFL++') + out_dir = os.environ['OUT'] + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + os.environ['OUT'] = aflpp_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(src): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + aflplusplus_build() + os.environ['OUT'] = out_dir + +def build_wingfuzz(): + """Build benchmark with wingfuzz.""" + print('Building with wingfuzz') + out_dir = os.environ['OUT'] + wingfuzz_target_dir = get_wingfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = wingfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + wingfuzz_build() + os.environ['OUT'] = out_dir + +def build_honggfuzz(): + """Build benchmark with Honggfuzz.""" + print('Building with Honggfuzz') + out_dir = os.environ['OUT'] + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = honggfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + honggfuzz_build() + os.environ['OUT'] = out_dir + +def prepare_build_environment(): + """Prepare build environment.""" + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + wingfuzz_target_dir = get_wingfuzz_target_dir(os.environ['OUT']) + + os.makedirs(aflpp_target_dir, exist_ok=True) + os.makedirs(honggfuzz_target_dir, exist_ok=True) + os.makedirs(wingfuzz_target_dir, exist_ok=True) + +def build(): + """Build benchmark.""" + prepare_build_environment() + new_env = os.environ.copy() + cflags = ['-fsanitize=fuzzer-no-link'] + utils.append_flags('CFLAGS', cflags, env=new_env) + utils.append_flags('CXXFLAGS', cflags, env=new_env) + src = new_env.get('SRC') + work = new_env.get('WORK') + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/usr/lib/libHCFUZZER.a' + with utils.restore_directory(src), utils.restore_directory(work): + utils.build_benchmark(env=new_env) + + + build_wingfuzz() + build_honggfuzz() + build_aflpp() + + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer. Wrapper that uses the defaults when calling + run_fuzzer.""" + run_fuzzer(input_corpus, + output_corpus, + target_binary, + extra_flags=['-keep_seed=0', '-cross_over_uniform_dist=1']) + + +def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None): + """Run fuzzer.""" + if extra_flags is None: + extra_flags = [] + + # Seperate out corpus and crash directories as sub-directories of + # |output_corpus| to avoid conflicts when corpus directory is reloaded. + crashes_dir = os.path.join(output_corpus, 'crashes') + output_corpus = os.path.join(output_corpus, 'corpus') + os.makedirs(crashes_dir) + os.makedirs(output_corpus) + + #prepare_fuzz_environment(input_corpus) + afl_fuzzer.prepare_fuzz_environment(input_corpus) + binary = os.path.basename(target_binary) + + os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' + os.environ['AFL_FAST_CAL'] = '1' + os.environ['AFL_NO_WARN_INSTABILITY'] = '1' + + flags = [ + '-print_final_stats=1', + # `close_fd_mask` to prevent too much logging output from the target. + '-close_fd_mask=3', + # Run in fork mode to allow ignoring ooms, timeouts, crashes and + # continue fuzzing indefinitely. + f'-target_program={binary}', + '-fuzzers=aflplusplus,wingfuzz,honggfuzz', + '-fork=1', + '-fork_job_budget_coe=2', + '-fork_num_seeds=1', + '-fork_max_job_time=900', + '-ignore_ooms=1', + '-ignore_timeouts=1', + '-ignore_crashes=1', + + # Don't use LSAN's leak detection. Other fuzzers won't be using it and + # using it will cause libFuzzer to find "crashes" no one cares about. + '-detect_leaks=0', + + # Store crashes along with corpus for bug based benchmarking. + f'-artifact_prefix={crashes_dir}/', + ] + flags += extra_flags + + if 'ADDITIONAL_ARGS' in os.environ: + flags += os.environ['ADDITIONAL_ARGS'].split(' ') + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + flags.append('-dict=' + dictionary_path) + + command = [target_binary] + flags + [output_corpus, input_corpus] + print('[run_fuzzer] Running command: ' + ' '.join(command)) + subprocess.check_call(command) diff --git a/fuzzers/orchestra_216/runner.Dockerfile b/fuzzers/orchestra_216/runner.Dockerfile new file mode 100644 index 000000000..6eb790acf --- /dev/null +++ b/fuzzers/orchestra_216/runner.Dockerfile @@ -0,0 +1,39 @@ +FROM gcr.io/fuzzbench/base-image + +# NOTE Comiple Python again with `--enabled-shared`. + +# Python 3.10.8 is not the default version in Ubuntu 20.04 (Focal Fossa). +ENV PYTHON_VERSION 3.10.8 + +RUN cd /tmp/ && \ + curl -O https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tar.xz && \ + tar -xvf Python-$PYTHON_VERSION.tar.xz > /dev/null && \ + cd Python-$PYTHON_VERSION && \ + ./configure \ + --enable-loadable-sqlite-extensions \ + --enable-optimizations \ + --enable-shared \ + > /dev/null && \ + make -j install > /dev/null && \ + rm -r /tmp/Python-$PYTHON_VERSION.tar.xz /tmp/Python-$PYTHON_VERSION + +# +# AFLplusplus +# + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 +ENV AFL_NO_AFFINITY=1 + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid +RUN apt-get update -y && apt-get install -y libbfd-dev libunwind-dev + diff --git a/fuzzers/orchestra_236/builder.Dockerfile b/fuzzers/orchestra_236/builder.Dockerfile new file mode 100644 index 000000000..77c035a0e --- /dev/null +++ b/fuzzers/orchestra_236/builder.Dockerfile @@ -0,0 +1,79 @@ +ARG parent_image +FROM $parent_image + +# +# AFLplusplus +# + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + python3-dev \ + python3-setuptools \ + automake \ + cmake \ + git \ + flex \ + bison \ + libglib2.0-dev \ + libpixman-1-dev \ + cargo \ + libgtk-3-dev \ + # for QEMU mode + ninja-build \ + gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev \ + libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev + +RUN git clone -b master https://github.com/gtt1995/GMFuzzer.git /gmfuzzer +RUN git clone -b fuzzers https://github.com/gtt1995/GMFuzzer.git /fuzzers +#COPY AFLplusplus /aflplusplus + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cp -r /fuzzers/AFLplusplus /aflplusplus && \ + cd /aflplusplus && \ + unset CFLAGS CXXFLAGS && \ + export CC=clang AFL_NO_X86=1 && \ + PYTHON_INCLUDE=/ make && \ + make install && \ + cp utils/aflpp_driver/libAFLDriver.a / && \ + make -C custom_mutators/autotokens && \ + cp -f custom_mutators/autotokens/autotokens.so . + + +#COPY wingfuzz wingfuzz + +RUN cp -r /fuzzers/wingfuzz /wingfuzz && \ + cd /wingfuzz && \ + ./build.sh && cd instrument && ./build.sh && clang -c WeakSym.c && \ + cp ../libFuzzer.a /libWingfuzz.a && cp WeakSym.o / && cp LoadCmpTracer.so / + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid. +RUN apt-get install -y \ + libbfd-dev \ + libunwind-dev \ + libblocksruntime-dev \ + liblzma-dev + +#COPY honggfuzz /honggfuzz + +# Set CFLAGS use honggfuzz's defaults except for -mnative which can build CPU +# dependent code that may not work on the machines we actually fuzz on. +# Create an empty object file which will become the FUZZER_LIB lib (since +# honggfuzz doesn't need this when hfuzz-clang(++) is used). +RUN cp -r /fuzzers/honggfuzz /honggfuzz && \ + cd /honggfuzz && \ + CFLAGS="-O3 -funroll-loops" make && \ + touch empty_lib.c && \ + cc -c -o empty_lib.o empty_lib.c + + +RUN cd /gmfuzzer &&\ + (for f in *.cpp; do \ + clang++ -stdlib=libc++ -fPIC -O2 -std=c++11 $f -c & \ + done && wait) && \ + ar r /usr/lib/libHCFUZZER.a *.o diff --git a/fuzzers/orchestra_236/fuzzer.py b/fuzzers/orchestra_236/fuzzer.py new file mode 100644 index 000000000..974193f53 --- /dev/null +++ b/fuzzers/orchestra_236/fuzzer.py @@ -0,0 +1,425 @@ +# Copyright 2020 Google LLC +# +# 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. +# +"""Integration code for Collabtive Fuzzer Framework.""" + +import os +import shutil +import subprocess + +from fuzzers import utils +from fuzzers.afl import fuzzer as afl_fuzzer +def get_cmplog_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'cmplog') + + +def get_uninstrumented_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'uninstrumented') + + +def get_aflpp_target_dir(output_directory): + """Return path to AFL++'s target directory.""" + return os.path.join(output_directory, 'aflplusplus') + + +def get_wingfuzz_target_dir(output_directory): + """Return path to wingfuzz's target directory.""" + return os.path.join(output_directory, 'wingfuzz') + +def get_honggfuzz_target_dir(output_directory): + """Return path to Honggfuzz's target directory.""" + return os.path.join(output_directory, 'honggfuzz') + + +def honggfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + + new_env['CC'] = '/honggfuzz/hfuzz_cc/hfuzz-clang' + new_env['CXX'] = '/honggfuzz/hfuzz_cc/hfuzz-clang++' + new_env['FUZZER_LIB'] = '/honggfuzz/empty_lib.o' + + utils.build_benchmark(env=new_env) + + print('[post_build] Copying honggfuzz to $OUT directory') + # Copy over honggfuzz's main fuzzing binary. + shutil.copy('/honggfuzz/honggfuzz', os.environ['OUT']) + + +def wingfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + cflags = [ + '-fsanitize=fuzzer-no-link', + '-fno-sanitize-coverage=trace-cmp', + '-fno-legacy-pass-manager', + '-fpass-plugin=/LoadCmpTracer.so', + '-w', + '-Wl,/WeakSym.o' + ] + utils.append_flags('CFLAGS', cflags, new_env) + utils.append_flags('CXXFLAGS', cflags, new_env) + + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/libWingfuzz.a' + utils.build_benchmark(env=new_env) + +def aflplusplus_build(*args): # pylint: disable=too-many-branches,too-many-statements + """Build benchmark.""" + # BUILD_MODES is not already supported by fuzzbench, meanwhile we provide + # a default configuration. + + build_modes = list(args) + if 'BUILD_MODES' in os.environ: + build_modes = os.environ['BUILD_MODES'].split(',') + + # Placeholder comment. + build_directory = os.environ['OUT'] + + # If nothing was set this is the default: + if not build_modes: + build_modes = ['tracepc', 'cmplog', 'dict2file'] + + # For bug type benchmarks we have to instrument via native clang pcguard :( + build_flags = os.environ['CFLAGS'] + + if build_flags.find( + 'array-bounds' + ) != -1 and 'qemu' not in build_modes and 'classic' not in build_modes: + if 'gcc' not in build_modes: + build_modes[0] = 'native' + + # Instrumentation coverage modes: + if 'lto' in build_modes: + os.environ['CC'] = '/aflplusplus/afl-clang-lto' + os.environ['CXX'] = '/aflplusplus/afl-clang-lto++' + edge_file = build_directory + '/aflpp_edges.txt' + os.environ['AFL_LLVM_DOCUMENT_IDS'] = edge_file + if os.path.isfile('/usr/local/bin/llvm-ranlib-13'): + os.environ['RANLIB'] = 'llvm-ranlib-13' + os.environ['AR'] = 'llvm-ar-13' + os.environ['AS'] = 'llvm-as-13' + elif os.path.isfile('/usr/local/bin/llvm-ranlib-12'): + os.environ['RANLIB'] = 'llvm-ranlib-12' + os.environ['AR'] = 'llvm-ar-12' + os.environ['AS'] = 'llvm-as-12' + else: + os.environ['RANLIB'] = 'llvm-ranlib' + os.environ['AR'] = 'llvm-ar' + os.environ['AS'] = 'llvm-as' + elif 'qemu' in build_modes: + os.environ['CC'] = 'clang' + os.environ['CXX'] = 'clang++' + elif 'gcc' in build_modes: + os.environ['CC'] = 'afl-gcc-fast' + os.environ['CXX'] = 'afl-g++-fast' + if build_flags.find('array-bounds') != -1: + os.environ['CFLAGS'] = '-fsanitize=address -O1' + os.environ['CXXFLAGS'] = '-fsanitize=address -O1' + else: + os.environ['CFLAGS'] = '' + os.environ['CXXFLAGS'] = '' + os.environ['CPPFLAGS'] = '' + else: + os.environ['CC'] = '/aflplusplus/afl-clang-fast' + os.environ['CXX'] = '/aflplusplus/afl-clang-fast++' + + print('AFL++ build: ') + print(build_modes) + + if 'qemu' in build_modes or 'symcc' in build_modes: + os.environ['CFLAGS'] = ' '.join(utils.NO_SANITIZER_COMPAT_CFLAGS) + cxxflags = [utils.LIBCPLUSPLUS_FLAG] + utils.NO_SANITIZER_COMPAT_CFLAGS + os.environ['CXXFLAGS'] = ' '.join(cxxflags) + + if 'tracepc' in build_modes or 'pcguard' in build_modes: + os.environ['AFL_LLVM_USE_TRACE_PC'] = '1' + elif 'classic' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'CLASSIC' + elif 'native' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'LLVMNATIVE' + + # Instrumentation coverage options: + # Do not use a fixed map location (LTO only) + if 'dynamic' in build_modes: + os.environ['AFL_LLVM_MAP_DYNAMIC'] = '1' + # Use a fixed map location (LTO only) + if 'fixed' in build_modes: + os.environ['AFL_LLVM_MAP_ADDR'] = '0x10000' + # Generate an extra dictionary. + if 'dict2file' in build_modes or 'native' in build_modes: + os.environ['AFL_LLVM_DICT2FILE'] = build_directory + '/afl++.dict' + os.environ['AFL_LLVM_DICT2FILE_NO_MAIN'] = '1' + # Enable context sentitivity for LLVM mode (non LTO only) + if 'ctx' in build_modes: + os.environ['AFL_LLVM_CTX'] = '1' + # Enable N-gram coverage for LLVM mode (non LTO only) + if 'ngram2' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '2' + elif 'ngram3' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '3' + elif 'ngram4' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '4' + elif 'ngram5' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '5' + elif 'ngram6' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '6' + elif 'ngram7' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '7' + elif 'ngram8' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '8' + elif 'ngram16' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '16' + if 'ctx1' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '1' + elif 'ctx2' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '2' + elif 'ctx3' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '3' + elif 'ctx4' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '4' + + # Only one of the following OR cmplog + # enable laf-intel compare splitting + if 'laf' in build_modes: + os.environ['AFL_LLVM_LAF_SPLIT_SWITCHES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_COMPARES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_FLOATS'] = '1' + if 'autodict' not in build_modes: + os.environ['AFL_LLVM_LAF_TRANSFORM_COMPARES'] = '1' + + if 'eclipser' in build_modes: + os.environ['FUZZER_LIB'] = '/libStandaloneFuzzTarget.a' + else: + os.environ['FUZZER_LIB'] = '/libAFLDriver.a' + + # Some benchmarks like lcms. (see: + # https://github.com/mm2/Little-CMS/commit/ab1093539b4287c233aca6a3cf53b234faceb792#diff-f0e6d05e72548974e852e8e55dffc4ccR212) + # fail to compile if the compiler outputs things to stderr in unexpected + # cases. Prevent these failures by using AFL_QUIET to stop afl-clang-fast + # from writing AFL specific messages to stderr. + os.environ['AFL_QUIET'] = '1' + os.environ['AFL_MAP_SIZE'] = '2621440' + + src = os.getenv('SRC') + work = os.getenv('WORK') + + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + utils.build_benchmark() + + if 'cmplog' in build_modes and 'qemu' not in build_modes: + + # CmpLog requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['AFL_LLVM_CMPLOG'] = '1' + + # For CmpLog build, set the OUT and FUZZ_TARGET environment + # variable to point to the new CmpLog build directory. + cmplog_build_directory = get_cmplog_build_directory(build_directory) + os.mkdir(cmplog_build_directory) + new_env['OUT'] = cmplog_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(cmplog_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for CmpLog fuzzing target') + utils.build_benchmark(env=new_env) + + if 'symcc' in build_modes: + + symcc_build_directory = get_uninstrumented_build_directory( + build_directory) + os.mkdir(symcc_build_directory) + + # symcc requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['CC'] = '/symcc/build/symcc' + new_env['CXX'] = '/symcc/build/sym++' + new_env['SYMCC_OUTPUT_DIR'] = '/tmp' + new_env['CXXFLAGS'] = new_env['CXXFLAGS'].replace('-stlib=libc++', '') + new_env['FUZZER_LIB'] = '/libfuzzer-harness.o' + new_env['OUT'] = symcc_build_directory + new_env['SYMCC_LIBCXX_PATH'] = '/libcxx_native_build' + new_env['SYMCC_NO_SYMBOLIC_INPUT'] = '1' + new_env['SYMCC_SILENT'] = '1' + + # For symcc build, set the OUT and FUZZ_TARGET environment + # variable to point to the new symcc build directory. + new_env['OUT'] = symcc_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(symcc_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for symcc fuzzing target') + utils.build_benchmark(env=new_env) + + shutil.copy('/aflplusplus/afl-fuzz', build_directory) + if os.path.exists('/aflplusplus/afl-qemu-trace'): + shutil.copy('/aflplusplus/afl-qemu-trace', build_directory) + if os.path.exists('/aflpp_qemu_driver_hook.so'): + shutil.copy('/aflpp_qemu_driver_hook.so', build_directory) + if os.path.exists('/get_frida_entry.sh'): + shutil.copy('/aflplusplus/afl-frida-trace.so', build_directory) + shutil.copy('/get_frida_entry.sh', build_directory) + shutil.copy('/aflplusplus/autotokens.so', build_directory) + + +def build_aflpp(): + """Build benchmark with AFL++.""" + print('Building with AFL++') + out_dir = os.environ['OUT'] + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + os.environ['OUT'] = aflpp_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(src): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + aflplusplus_build() + os.environ['OUT'] = out_dir + +def build_wingfuzz(): + """Build benchmark with wingfuzz.""" + print('Building with wingfuzz') + out_dir = os.environ['OUT'] + wingfuzz_target_dir = get_wingfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = wingfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + wingfuzz_build() + os.environ['OUT'] = out_dir + +def build_honggfuzz(): + """Build benchmark with Honggfuzz.""" + print('Building with Honggfuzz') + out_dir = os.environ['OUT'] + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = honggfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + honggfuzz_build() + os.environ['OUT'] = out_dir + +def prepare_build_environment(): + """Prepare build environment.""" + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + wingfuzz_target_dir = get_wingfuzz_target_dir(os.environ['OUT']) + + os.makedirs(aflpp_target_dir, exist_ok=True) + os.makedirs(honggfuzz_target_dir, exist_ok=True) + os.makedirs(wingfuzz_target_dir, exist_ok=True) + +def build(): + """Build benchmark.""" + prepare_build_environment() + new_env = os.environ.copy() + cflags = ['-fsanitize=fuzzer-no-link'] + utils.append_flags('CFLAGS', cflags, env=new_env) + utils.append_flags('CXXFLAGS', cflags, env=new_env) + src = new_env.get('SRC') + work = new_env.get('WORK') + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/usr/lib/libHCFUZZER.a' + with utils.restore_directory(src), utils.restore_directory(work): + utils.build_benchmark(env=new_env) + + + build_wingfuzz() + build_honggfuzz() + build_aflpp() + + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer. Wrapper that uses the defaults when calling + run_fuzzer.""" + run_fuzzer(input_corpus, + output_corpus, + target_binary, + extra_flags=['-keep_seed=0', '-cross_over_uniform_dist=1']) + + +def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None): + """Run fuzzer.""" + if extra_flags is None: + extra_flags = [] + + # Seperate out corpus and crash directories as sub-directories of + # |output_corpus| to avoid conflicts when corpus directory is reloaded. + crashes_dir = os.path.join(output_corpus, 'crashes') + output_corpus = os.path.join(output_corpus, 'corpus') + os.makedirs(crashes_dir) + os.makedirs(output_corpus) + + #prepare_fuzz_environment(input_corpus) + afl_fuzzer.prepare_fuzz_environment(input_corpus) + binary = os.path.basename(target_binary) + + os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' + os.environ['AFL_FAST_CAL'] = '1' + os.environ['AFL_NO_WARN_INSTABILITY'] = '1' + + flags = [ + '-print_final_stats=1', + # `close_fd_mask` to prevent too much logging output from the target. + '-close_fd_mask=3', + # Run in fork mode to allow ignoring ooms, timeouts, crashes and + # continue fuzzing indefinitely. + f'-target_program={binary}', + '-fuzzers=aflplusplus,wingfuzz,honggfuzz', + '-fork=1', + '-fork_job_budget_coe=2', + '-fork_num_seeds=3', + '-fork_max_job_time=600', + '-ignore_ooms=1', + '-ignore_timeouts=1', + '-ignore_crashes=1', + + # Don't use LSAN's leak detection. Other fuzzers won't be using it and + # using it will cause libFuzzer to find "crashes" no one cares about. + '-detect_leaks=0', + + # Store crashes along with corpus for bug based benchmarking. + f'-artifact_prefix={crashes_dir}/', + ] + flags += extra_flags + + if 'ADDITIONAL_ARGS' in os.environ: + flags += os.environ['ADDITIONAL_ARGS'].split(' ') + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + flags.append('-dict=' + dictionary_path) + + command = [target_binary] + flags + [output_corpus, input_corpus] + print('[run_fuzzer] Running command: ' + ' '.join(command)) + subprocess.check_call(command) diff --git a/fuzzers/orchestra_236/runner.Dockerfile b/fuzzers/orchestra_236/runner.Dockerfile new file mode 100644 index 000000000..6eb790acf --- /dev/null +++ b/fuzzers/orchestra_236/runner.Dockerfile @@ -0,0 +1,39 @@ +FROM gcr.io/fuzzbench/base-image + +# NOTE Comiple Python again with `--enabled-shared`. + +# Python 3.10.8 is not the default version in Ubuntu 20.04 (Focal Fossa). +ENV PYTHON_VERSION 3.10.8 + +RUN cd /tmp/ && \ + curl -O https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tar.xz && \ + tar -xvf Python-$PYTHON_VERSION.tar.xz > /dev/null && \ + cd Python-$PYTHON_VERSION && \ + ./configure \ + --enable-loadable-sqlite-extensions \ + --enable-optimizations \ + --enable-shared \ + > /dev/null && \ + make -j install > /dev/null && \ + rm -r /tmp/Python-$PYTHON_VERSION.tar.xz /tmp/Python-$PYTHON_VERSION + +# +# AFLplusplus +# + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 +ENV AFL_NO_AFFINITY=1 + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid +RUN apt-get update -y && apt-get install -y libbfd-dev libunwind-dev + diff --git a/fuzzers/orchestra_339/builder.Dockerfile b/fuzzers/orchestra_339/builder.Dockerfile new file mode 100644 index 000000000..77c035a0e --- /dev/null +++ b/fuzzers/orchestra_339/builder.Dockerfile @@ -0,0 +1,79 @@ +ARG parent_image +FROM $parent_image + +# +# AFLplusplus +# + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + python3-dev \ + python3-setuptools \ + automake \ + cmake \ + git \ + flex \ + bison \ + libglib2.0-dev \ + libpixman-1-dev \ + cargo \ + libgtk-3-dev \ + # for QEMU mode + ninja-build \ + gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev \ + libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev + +RUN git clone -b master https://github.com/gtt1995/GMFuzzer.git /gmfuzzer +RUN git clone -b fuzzers https://github.com/gtt1995/GMFuzzer.git /fuzzers +#COPY AFLplusplus /aflplusplus + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cp -r /fuzzers/AFLplusplus /aflplusplus && \ + cd /aflplusplus && \ + unset CFLAGS CXXFLAGS && \ + export CC=clang AFL_NO_X86=1 && \ + PYTHON_INCLUDE=/ make && \ + make install && \ + cp utils/aflpp_driver/libAFLDriver.a / && \ + make -C custom_mutators/autotokens && \ + cp -f custom_mutators/autotokens/autotokens.so . + + +#COPY wingfuzz wingfuzz + +RUN cp -r /fuzzers/wingfuzz /wingfuzz && \ + cd /wingfuzz && \ + ./build.sh && cd instrument && ./build.sh && clang -c WeakSym.c && \ + cp ../libFuzzer.a /libWingfuzz.a && cp WeakSym.o / && cp LoadCmpTracer.so / + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid. +RUN apt-get install -y \ + libbfd-dev \ + libunwind-dev \ + libblocksruntime-dev \ + liblzma-dev + +#COPY honggfuzz /honggfuzz + +# Set CFLAGS use honggfuzz's defaults except for -mnative which can build CPU +# dependent code that may not work on the machines we actually fuzz on. +# Create an empty object file which will become the FUZZER_LIB lib (since +# honggfuzz doesn't need this when hfuzz-clang(++) is used). +RUN cp -r /fuzzers/honggfuzz /honggfuzz && \ + cd /honggfuzz && \ + CFLAGS="-O3 -funroll-loops" make && \ + touch empty_lib.c && \ + cc -c -o empty_lib.o empty_lib.c + + +RUN cd /gmfuzzer &&\ + (for f in *.cpp; do \ + clang++ -stdlib=libc++ -fPIC -O2 -std=c++11 $f -c & \ + done && wait) && \ + ar r /usr/lib/libHCFUZZER.a *.o diff --git a/fuzzers/orchestra_339/fuzzer.py b/fuzzers/orchestra_339/fuzzer.py new file mode 100644 index 000000000..45f53911e --- /dev/null +++ b/fuzzers/orchestra_339/fuzzer.py @@ -0,0 +1,425 @@ +# Copyright 2020 Google LLC +# +# 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. +# +"""Integration code for Collabtive Fuzzer Framework.""" + +import os +import shutil +import subprocess + +from fuzzers import utils +from fuzzers.afl import fuzzer as afl_fuzzer +def get_cmplog_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'cmplog') + + +def get_uninstrumented_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'uninstrumented') + + +def get_aflpp_target_dir(output_directory): + """Return path to AFL++'s target directory.""" + return os.path.join(output_directory, 'aflplusplus') + + +def get_wingfuzz_target_dir(output_directory): + """Return path to wingfuzz's target directory.""" + return os.path.join(output_directory, 'wingfuzz') + +def get_honggfuzz_target_dir(output_directory): + """Return path to Honggfuzz's target directory.""" + return os.path.join(output_directory, 'honggfuzz') + + +def honggfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + + new_env['CC'] = '/honggfuzz/hfuzz_cc/hfuzz-clang' + new_env['CXX'] = '/honggfuzz/hfuzz_cc/hfuzz-clang++' + new_env['FUZZER_LIB'] = '/honggfuzz/empty_lib.o' + + utils.build_benchmark(env=new_env) + + print('[post_build] Copying honggfuzz to $OUT directory') + # Copy over honggfuzz's main fuzzing binary. + shutil.copy('/honggfuzz/honggfuzz', os.environ['OUT']) + + +def wingfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + cflags = [ + '-fsanitize=fuzzer-no-link', + '-fno-sanitize-coverage=trace-cmp', + '-fno-legacy-pass-manager', + '-fpass-plugin=/LoadCmpTracer.so', + '-w', + '-Wl,/WeakSym.o' + ] + utils.append_flags('CFLAGS', cflags, new_env) + utils.append_flags('CXXFLAGS', cflags, new_env) + + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/libWingfuzz.a' + utils.build_benchmark(env=new_env) + +def aflplusplus_build(*args): # pylint: disable=too-many-branches,too-many-statements + """Build benchmark.""" + # BUILD_MODES is not already supported by fuzzbench, meanwhile we provide + # a default configuration. + + build_modes = list(args) + if 'BUILD_MODES' in os.environ: + build_modes = os.environ['BUILD_MODES'].split(',') + + # Placeholder comment. + build_directory = os.environ['OUT'] + + # If nothing was set this is the default: + if not build_modes: + build_modes = ['tracepc', 'cmplog', 'dict2file'] + + # For bug type benchmarks we have to instrument via native clang pcguard :( + build_flags = os.environ['CFLAGS'] + + if build_flags.find( + 'array-bounds' + ) != -1 and 'qemu' not in build_modes and 'classic' not in build_modes: + if 'gcc' not in build_modes: + build_modes[0] = 'native' + + # Instrumentation coverage modes: + if 'lto' in build_modes: + os.environ['CC'] = '/aflplusplus/afl-clang-lto' + os.environ['CXX'] = '/aflplusplus/afl-clang-lto++' + edge_file = build_directory + '/aflpp_edges.txt' + os.environ['AFL_LLVM_DOCUMENT_IDS'] = edge_file + if os.path.isfile('/usr/local/bin/llvm-ranlib-13'): + os.environ['RANLIB'] = 'llvm-ranlib-13' + os.environ['AR'] = 'llvm-ar-13' + os.environ['AS'] = 'llvm-as-13' + elif os.path.isfile('/usr/local/bin/llvm-ranlib-12'): + os.environ['RANLIB'] = 'llvm-ranlib-12' + os.environ['AR'] = 'llvm-ar-12' + os.environ['AS'] = 'llvm-as-12' + else: + os.environ['RANLIB'] = 'llvm-ranlib' + os.environ['AR'] = 'llvm-ar' + os.environ['AS'] = 'llvm-as' + elif 'qemu' in build_modes: + os.environ['CC'] = 'clang' + os.environ['CXX'] = 'clang++' + elif 'gcc' in build_modes: + os.environ['CC'] = 'afl-gcc-fast' + os.environ['CXX'] = 'afl-g++-fast' + if build_flags.find('array-bounds') != -1: + os.environ['CFLAGS'] = '-fsanitize=address -O1' + os.environ['CXXFLAGS'] = '-fsanitize=address -O1' + else: + os.environ['CFLAGS'] = '' + os.environ['CXXFLAGS'] = '' + os.environ['CPPFLAGS'] = '' + else: + os.environ['CC'] = '/aflplusplus/afl-clang-fast' + os.environ['CXX'] = '/aflplusplus/afl-clang-fast++' + + print('AFL++ build: ') + print(build_modes) + + if 'qemu' in build_modes or 'symcc' in build_modes: + os.environ['CFLAGS'] = ' '.join(utils.NO_SANITIZER_COMPAT_CFLAGS) + cxxflags = [utils.LIBCPLUSPLUS_FLAG] + utils.NO_SANITIZER_COMPAT_CFLAGS + os.environ['CXXFLAGS'] = ' '.join(cxxflags) + + if 'tracepc' in build_modes or 'pcguard' in build_modes: + os.environ['AFL_LLVM_USE_TRACE_PC'] = '1' + elif 'classic' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'CLASSIC' + elif 'native' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'LLVMNATIVE' + + # Instrumentation coverage options: + # Do not use a fixed map location (LTO only) + if 'dynamic' in build_modes: + os.environ['AFL_LLVM_MAP_DYNAMIC'] = '1' + # Use a fixed map location (LTO only) + if 'fixed' in build_modes: + os.environ['AFL_LLVM_MAP_ADDR'] = '0x10000' + # Generate an extra dictionary. + if 'dict2file' in build_modes or 'native' in build_modes: + os.environ['AFL_LLVM_DICT2FILE'] = build_directory + '/afl++.dict' + os.environ['AFL_LLVM_DICT2FILE_NO_MAIN'] = '1' + # Enable context sentitivity for LLVM mode (non LTO only) + if 'ctx' in build_modes: + os.environ['AFL_LLVM_CTX'] = '1' + # Enable N-gram coverage for LLVM mode (non LTO only) + if 'ngram2' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '2' + elif 'ngram3' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '3' + elif 'ngram4' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '4' + elif 'ngram5' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '5' + elif 'ngram6' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '6' + elif 'ngram7' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '7' + elif 'ngram8' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '8' + elif 'ngram16' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '16' + if 'ctx1' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '1' + elif 'ctx2' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '2' + elif 'ctx3' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '3' + elif 'ctx4' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '4' + + # Only one of the following OR cmplog + # enable laf-intel compare splitting + if 'laf' in build_modes: + os.environ['AFL_LLVM_LAF_SPLIT_SWITCHES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_COMPARES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_FLOATS'] = '1' + if 'autodict' not in build_modes: + os.environ['AFL_LLVM_LAF_TRANSFORM_COMPARES'] = '1' + + if 'eclipser' in build_modes: + os.environ['FUZZER_LIB'] = '/libStandaloneFuzzTarget.a' + else: + os.environ['FUZZER_LIB'] = '/libAFLDriver.a' + + # Some benchmarks like lcms. (see: + # https://github.com/mm2/Little-CMS/commit/ab1093539b4287c233aca6a3cf53b234faceb792#diff-f0e6d05e72548974e852e8e55dffc4ccR212) + # fail to compile if the compiler outputs things to stderr in unexpected + # cases. Prevent these failures by using AFL_QUIET to stop afl-clang-fast + # from writing AFL specific messages to stderr. + os.environ['AFL_QUIET'] = '1' + os.environ['AFL_MAP_SIZE'] = '2621440' + + src = os.getenv('SRC') + work = os.getenv('WORK') + + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + utils.build_benchmark() + + if 'cmplog' in build_modes and 'qemu' not in build_modes: + + # CmpLog requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['AFL_LLVM_CMPLOG'] = '1' + + # For CmpLog build, set the OUT and FUZZ_TARGET environment + # variable to point to the new CmpLog build directory. + cmplog_build_directory = get_cmplog_build_directory(build_directory) + os.mkdir(cmplog_build_directory) + new_env['OUT'] = cmplog_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(cmplog_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for CmpLog fuzzing target') + utils.build_benchmark(env=new_env) + + if 'symcc' in build_modes: + + symcc_build_directory = get_uninstrumented_build_directory( + build_directory) + os.mkdir(symcc_build_directory) + + # symcc requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['CC'] = '/symcc/build/symcc' + new_env['CXX'] = '/symcc/build/sym++' + new_env['SYMCC_OUTPUT_DIR'] = '/tmp' + new_env['CXXFLAGS'] = new_env['CXXFLAGS'].replace('-stlib=libc++', '') + new_env['FUZZER_LIB'] = '/libfuzzer-harness.o' + new_env['OUT'] = symcc_build_directory + new_env['SYMCC_LIBCXX_PATH'] = '/libcxx_native_build' + new_env['SYMCC_NO_SYMBOLIC_INPUT'] = '1' + new_env['SYMCC_SILENT'] = '1' + + # For symcc build, set the OUT and FUZZ_TARGET environment + # variable to point to the new symcc build directory. + new_env['OUT'] = symcc_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(symcc_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for symcc fuzzing target') + utils.build_benchmark(env=new_env) + + shutil.copy('/aflplusplus/afl-fuzz', build_directory) + if os.path.exists('/aflplusplus/afl-qemu-trace'): + shutil.copy('/aflplusplus/afl-qemu-trace', build_directory) + if os.path.exists('/aflpp_qemu_driver_hook.so'): + shutil.copy('/aflpp_qemu_driver_hook.so', build_directory) + if os.path.exists('/get_frida_entry.sh'): + shutil.copy('/aflplusplus/afl-frida-trace.so', build_directory) + shutil.copy('/get_frida_entry.sh', build_directory) + shutil.copy('/aflplusplus/autotokens.so', build_directory) + + +def build_aflpp(): + """Build benchmark with AFL++.""" + print('Building with AFL++') + out_dir = os.environ['OUT'] + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + os.environ['OUT'] = aflpp_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(src): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + aflplusplus_build() + os.environ['OUT'] = out_dir + +def build_wingfuzz(): + """Build benchmark with wingfuzz.""" + print('Building with wingfuzz') + out_dir = os.environ['OUT'] + wingfuzz_target_dir = get_wingfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = wingfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + wingfuzz_build() + os.environ['OUT'] = out_dir + +def build_honggfuzz(): + """Build benchmark with Honggfuzz.""" + print('Building with Honggfuzz') + out_dir = os.environ['OUT'] + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = honggfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + honggfuzz_build() + os.environ['OUT'] = out_dir + +def prepare_build_environment(): + """Prepare build environment.""" + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + wingfuzz_target_dir = get_wingfuzz_target_dir(os.environ['OUT']) + + os.makedirs(aflpp_target_dir, exist_ok=True) + os.makedirs(honggfuzz_target_dir, exist_ok=True) + os.makedirs(wingfuzz_target_dir, exist_ok=True) + +def build(): + """Build benchmark.""" + prepare_build_environment() + new_env = os.environ.copy() + cflags = ['-fsanitize=fuzzer-no-link'] + utils.append_flags('CFLAGS', cflags, env=new_env) + utils.append_flags('CXXFLAGS', cflags, env=new_env) + src = new_env.get('SRC') + work = new_env.get('WORK') + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/usr/lib/libHCFUZZER.a' + with utils.restore_directory(src), utils.restore_directory(work): + utils.build_benchmark(env=new_env) + + + build_wingfuzz() + build_honggfuzz() + build_aflpp() + + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer. Wrapper that uses the defaults when calling + run_fuzzer.""" + run_fuzzer(input_corpus, + output_corpus, + target_binary, + extra_flags=['-keep_seed=0', '-cross_over_uniform_dist=1']) + + +def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None): + """Run fuzzer.""" + if extra_flags is None: + extra_flags = [] + + # Seperate out corpus and crash directories as sub-directories of + # |output_corpus| to avoid conflicts when corpus directory is reloaded. + crashes_dir = os.path.join(output_corpus, 'crashes') + output_corpus = os.path.join(output_corpus, 'corpus') + os.makedirs(crashes_dir) + os.makedirs(output_corpus) + + #prepare_fuzz_environment(input_corpus) + afl_fuzzer.prepare_fuzz_environment(input_corpus) + binary = os.path.basename(target_binary) + + os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' + os.environ['AFL_FAST_CAL'] = '1' + os.environ['AFL_NO_WARN_INSTABILITY'] = '1' + + flags = [ + '-print_final_stats=1', + # `close_fd_mask` to prevent too much logging output from the target. + '-close_fd_mask=3', + # Run in fork mode to allow ignoring ooms, timeouts, crashes and + # continue fuzzing indefinitely. + f'-target_program={binary}', + '-fuzzers=aflplusplus,wingfuzz,honggfuzz', + '-fork=1', + '-fork_job_budget_coe=3', + '-fork_num_seeds=3', + '-fork_max_job_time=900', + '-ignore_ooms=1', + '-ignore_timeouts=1', + '-ignore_crashes=1', + + # Don't use LSAN's leak detection. Other fuzzers won't be using it and + # using it will cause libFuzzer to find "crashes" no one cares about. + '-detect_leaks=0', + + # Store crashes along with corpus for bug based benchmarking. + f'-artifact_prefix={crashes_dir}/', + ] + flags += extra_flags + + if 'ADDITIONAL_ARGS' in os.environ: + flags += os.environ['ADDITIONAL_ARGS'].split(' ') + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + flags.append('-dict=' + dictionary_path) + + command = [target_binary] + flags + [output_corpus, input_corpus] + print('[run_fuzzer] Running command: ' + ' '.join(command)) + subprocess.check_call(command) diff --git a/fuzzers/orchestra_339/runner.Dockerfile b/fuzzers/orchestra_339/runner.Dockerfile new file mode 100644 index 000000000..6eb790acf --- /dev/null +++ b/fuzzers/orchestra_339/runner.Dockerfile @@ -0,0 +1,39 @@ +FROM gcr.io/fuzzbench/base-image + +# NOTE Comiple Python again with `--enabled-shared`. + +# Python 3.10.8 is not the default version in Ubuntu 20.04 (Focal Fossa). +ENV PYTHON_VERSION 3.10.8 + +RUN cd /tmp/ && \ + curl -O https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tar.xz && \ + tar -xvf Python-$PYTHON_VERSION.tar.xz > /dev/null && \ + cd Python-$PYTHON_VERSION && \ + ./configure \ + --enable-loadable-sqlite-extensions \ + --enable-optimizations \ + --enable-shared \ + > /dev/null && \ + make -j install > /dev/null && \ + rm -r /tmp/Python-$PYTHON_VERSION.tar.xz /tmp/Python-$PYTHON_VERSION + +# +# AFLplusplus +# + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 +ENV AFL_NO_AFFINITY=1 + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid +RUN apt-get update -y && apt-get install -y libbfd-dev libunwind-dev + diff --git a/fuzzers/orchestra_4310/builder.Dockerfile b/fuzzers/orchestra_4310/builder.Dockerfile new file mode 100644 index 000000000..77c035a0e --- /dev/null +++ b/fuzzers/orchestra_4310/builder.Dockerfile @@ -0,0 +1,79 @@ +ARG parent_image +FROM $parent_image + +# +# AFLplusplus +# + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + python3-dev \ + python3-setuptools \ + automake \ + cmake \ + git \ + flex \ + bison \ + libglib2.0-dev \ + libpixman-1-dev \ + cargo \ + libgtk-3-dev \ + # for QEMU mode + ninja-build \ + gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev \ + libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev + +RUN git clone -b master https://github.com/gtt1995/GMFuzzer.git /gmfuzzer +RUN git clone -b fuzzers https://github.com/gtt1995/GMFuzzer.git /fuzzers +#COPY AFLplusplus /aflplusplus + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cp -r /fuzzers/AFLplusplus /aflplusplus && \ + cd /aflplusplus && \ + unset CFLAGS CXXFLAGS && \ + export CC=clang AFL_NO_X86=1 && \ + PYTHON_INCLUDE=/ make && \ + make install && \ + cp utils/aflpp_driver/libAFLDriver.a / && \ + make -C custom_mutators/autotokens && \ + cp -f custom_mutators/autotokens/autotokens.so . + + +#COPY wingfuzz wingfuzz + +RUN cp -r /fuzzers/wingfuzz /wingfuzz && \ + cd /wingfuzz && \ + ./build.sh && cd instrument && ./build.sh && clang -c WeakSym.c && \ + cp ../libFuzzer.a /libWingfuzz.a && cp WeakSym.o / && cp LoadCmpTracer.so / + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid. +RUN apt-get install -y \ + libbfd-dev \ + libunwind-dev \ + libblocksruntime-dev \ + liblzma-dev + +#COPY honggfuzz /honggfuzz + +# Set CFLAGS use honggfuzz's defaults except for -mnative which can build CPU +# dependent code that may not work on the machines we actually fuzz on. +# Create an empty object file which will become the FUZZER_LIB lib (since +# honggfuzz doesn't need this when hfuzz-clang(++) is used). +RUN cp -r /fuzzers/honggfuzz /honggfuzz && \ + cd /honggfuzz && \ + CFLAGS="-O3 -funroll-loops" make && \ + touch empty_lib.c && \ + cc -c -o empty_lib.o empty_lib.c + + +RUN cd /gmfuzzer &&\ + (for f in *.cpp; do \ + clang++ -stdlib=libc++ -fPIC -O2 -std=c++11 $f -c & \ + done && wait) && \ + ar r /usr/lib/libHCFUZZER.a *.o diff --git a/fuzzers/orchestra_4310/fuzzer.py b/fuzzers/orchestra_4310/fuzzer.py new file mode 100644 index 000000000..3d765f257 --- /dev/null +++ b/fuzzers/orchestra_4310/fuzzer.py @@ -0,0 +1,425 @@ +# Copyright 2020 Google LLC +# +# 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. +# +"""Integration code for Collabtive Fuzzer Framework.""" + +import os +import shutil +import subprocess + +from fuzzers import utils +from fuzzers.afl import fuzzer as afl_fuzzer +def get_cmplog_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'cmplog') + + +def get_uninstrumented_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'uninstrumented') + + +def get_aflpp_target_dir(output_directory): + """Return path to AFL++'s target directory.""" + return os.path.join(output_directory, 'aflplusplus') + + +def get_wingfuzz_target_dir(output_directory): + """Return path to wingfuzz's target directory.""" + return os.path.join(output_directory, 'wingfuzz') + +def get_honggfuzz_target_dir(output_directory): + """Return path to Honggfuzz's target directory.""" + return os.path.join(output_directory, 'honggfuzz') + + +def honggfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + + new_env['CC'] = '/honggfuzz/hfuzz_cc/hfuzz-clang' + new_env['CXX'] = '/honggfuzz/hfuzz_cc/hfuzz-clang++' + new_env['FUZZER_LIB'] = '/honggfuzz/empty_lib.o' + + utils.build_benchmark(env=new_env) + + print('[post_build] Copying honggfuzz to $OUT directory') + # Copy over honggfuzz's main fuzzing binary. + shutil.copy('/honggfuzz/honggfuzz', os.environ['OUT']) + + +def wingfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + cflags = [ + '-fsanitize=fuzzer-no-link', + '-fno-sanitize-coverage=trace-cmp', + '-fno-legacy-pass-manager', + '-fpass-plugin=/LoadCmpTracer.so', + '-w', + '-Wl,/WeakSym.o' + ] + utils.append_flags('CFLAGS', cflags, new_env) + utils.append_flags('CXXFLAGS', cflags, new_env) + + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/libWingfuzz.a' + utils.build_benchmark(env=new_env) + +def aflplusplus_build(*args): # pylint: disable=too-many-branches,too-many-statements + """Build benchmark.""" + # BUILD_MODES is not already supported by fuzzbench, meanwhile we provide + # a default configuration. + + build_modes = list(args) + if 'BUILD_MODES' in os.environ: + build_modes = os.environ['BUILD_MODES'].split(',') + + # Placeholder comment. + build_directory = os.environ['OUT'] + + # If nothing was set this is the default: + if not build_modes: + build_modes = ['tracepc', 'cmplog', 'dict2file'] + + # For bug type benchmarks we have to instrument via native clang pcguard :( + build_flags = os.environ['CFLAGS'] + + if build_flags.find( + 'array-bounds' + ) != -1 and 'qemu' not in build_modes and 'classic' not in build_modes: + if 'gcc' not in build_modes: + build_modes[0] = 'native' + + # Instrumentation coverage modes: + if 'lto' in build_modes: + os.environ['CC'] = '/aflplusplus/afl-clang-lto' + os.environ['CXX'] = '/aflplusplus/afl-clang-lto++' + edge_file = build_directory + '/aflpp_edges.txt' + os.environ['AFL_LLVM_DOCUMENT_IDS'] = edge_file + if os.path.isfile('/usr/local/bin/llvm-ranlib-13'): + os.environ['RANLIB'] = 'llvm-ranlib-13' + os.environ['AR'] = 'llvm-ar-13' + os.environ['AS'] = 'llvm-as-13' + elif os.path.isfile('/usr/local/bin/llvm-ranlib-12'): + os.environ['RANLIB'] = 'llvm-ranlib-12' + os.environ['AR'] = 'llvm-ar-12' + os.environ['AS'] = 'llvm-as-12' + else: + os.environ['RANLIB'] = 'llvm-ranlib' + os.environ['AR'] = 'llvm-ar' + os.environ['AS'] = 'llvm-as' + elif 'qemu' in build_modes: + os.environ['CC'] = 'clang' + os.environ['CXX'] = 'clang++' + elif 'gcc' in build_modes: + os.environ['CC'] = 'afl-gcc-fast' + os.environ['CXX'] = 'afl-g++-fast' + if build_flags.find('array-bounds') != -1: + os.environ['CFLAGS'] = '-fsanitize=address -O1' + os.environ['CXXFLAGS'] = '-fsanitize=address -O1' + else: + os.environ['CFLAGS'] = '' + os.environ['CXXFLAGS'] = '' + os.environ['CPPFLAGS'] = '' + else: + os.environ['CC'] = '/aflplusplus/afl-clang-fast' + os.environ['CXX'] = '/aflplusplus/afl-clang-fast++' + + print('AFL++ build: ') + print(build_modes) + + if 'qemu' in build_modes or 'symcc' in build_modes: + os.environ['CFLAGS'] = ' '.join(utils.NO_SANITIZER_COMPAT_CFLAGS) + cxxflags = [utils.LIBCPLUSPLUS_FLAG] + utils.NO_SANITIZER_COMPAT_CFLAGS + os.environ['CXXFLAGS'] = ' '.join(cxxflags) + + if 'tracepc' in build_modes or 'pcguard' in build_modes: + os.environ['AFL_LLVM_USE_TRACE_PC'] = '1' + elif 'classic' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'CLASSIC' + elif 'native' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'LLVMNATIVE' + + # Instrumentation coverage options: + # Do not use a fixed map location (LTO only) + if 'dynamic' in build_modes: + os.environ['AFL_LLVM_MAP_DYNAMIC'] = '1' + # Use a fixed map location (LTO only) + if 'fixed' in build_modes: + os.environ['AFL_LLVM_MAP_ADDR'] = '0x10000' + # Generate an extra dictionary. + if 'dict2file' in build_modes or 'native' in build_modes: + os.environ['AFL_LLVM_DICT2FILE'] = build_directory + '/afl++.dict' + os.environ['AFL_LLVM_DICT2FILE_NO_MAIN'] = '1' + # Enable context sentitivity for LLVM mode (non LTO only) + if 'ctx' in build_modes: + os.environ['AFL_LLVM_CTX'] = '1' + # Enable N-gram coverage for LLVM mode (non LTO only) + if 'ngram2' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '2' + elif 'ngram3' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '3' + elif 'ngram4' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '4' + elif 'ngram5' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '5' + elif 'ngram6' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '6' + elif 'ngram7' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '7' + elif 'ngram8' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '8' + elif 'ngram16' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '16' + if 'ctx1' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '1' + elif 'ctx2' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '2' + elif 'ctx3' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '3' + elif 'ctx4' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '4' + + # Only one of the following OR cmplog + # enable laf-intel compare splitting + if 'laf' in build_modes: + os.environ['AFL_LLVM_LAF_SPLIT_SWITCHES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_COMPARES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_FLOATS'] = '1' + if 'autodict' not in build_modes: + os.environ['AFL_LLVM_LAF_TRANSFORM_COMPARES'] = '1' + + if 'eclipser' in build_modes: + os.environ['FUZZER_LIB'] = '/libStandaloneFuzzTarget.a' + else: + os.environ['FUZZER_LIB'] = '/libAFLDriver.a' + + # Some benchmarks like lcms. (see: + # https://github.com/mm2/Little-CMS/commit/ab1093539b4287c233aca6a3cf53b234faceb792#diff-f0e6d05e72548974e852e8e55dffc4ccR212) + # fail to compile if the compiler outputs things to stderr in unexpected + # cases. Prevent these failures by using AFL_QUIET to stop afl-clang-fast + # from writing AFL specific messages to stderr. + os.environ['AFL_QUIET'] = '1' + os.environ['AFL_MAP_SIZE'] = '2621440' + + src = os.getenv('SRC') + work = os.getenv('WORK') + + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + utils.build_benchmark() + + if 'cmplog' in build_modes and 'qemu' not in build_modes: + + # CmpLog requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['AFL_LLVM_CMPLOG'] = '1' + + # For CmpLog build, set the OUT and FUZZ_TARGET environment + # variable to point to the new CmpLog build directory. + cmplog_build_directory = get_cmplog_build_directory(build_directory) + os.mkdir(cmplog_build_directory) + new_env['OUT'] = cmplog_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(cmplog_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for CmpLog fuzzing target') + utils.build_benchmark(env=new_env) + + if 'symcc' in build_modes: + + symcc_build_directory = get_uninstrumented_build_directory( + build_directory) + os.mkdir(symcc_build_directory) + + # symcc requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['CC'] = '/symcc/build/symcc' + new_env['CXX'] = '/symcc/build/sym++' + new_env['SYMCC_OUTPUT_DIR'] = '/tmp' + new_env['CXXFLAGS'] = new_env['CXXFLAGS'].replace('-stlib=libc++', '') + new_env['FUZZER_LIB'] = '/libfuzzer-harness.o' + new_env['OUT'] = symcc_build_directory + new_env['SYMCC_LIBCXX_PATH'] = '/libcxx_native_build' + new_env['SYMCC_NO_SYMBOLIC_INPUT'] = '1' + new_env['SYMCC_SILENT'] = '1' + + # For symcc build, set the OUT and FUZZ_TARGET environment + # variable to point to the new symcc build directory. + new_env['OUT'] = symcc_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(symcc_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for symcc fuzzing target') + utils.build_benchmark(env=new_env) + + shutil.copy('/aflplusplus/afl-fuzz', build_directory) + if os.path.exists('/aflplusplus/afl-qemu-trace'): + shutil.copy('/aflplusplus/afl-qemu-trace', build_directory) + if os.path.exists('/aflpp_qemu_driver_hook.so'): + shutil.copy('/aflpp_qemu_driver_hook.so', build_directory) + if os.path.exists('/get_frida_entry.sh'): + shutil.copy('/aflplusplus/afl-frida-trace.so', build_directory) + shutil.copy('/get_frida_entry.sh', build_directory) + shutil.copy('/aflplusplus/autotokens.so', build_directory) + + +def build_aflpp(): + """Build benchmark with AFL++.""" + print('Building with AFL++') + out_dir = os.environ['OUT'] + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + os.environ['OUT'] = aflpp_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(src): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + aflplusplus_build() + os.environ['OUT'] = out_dir + +def build_wingfuzz(): + """Build benchmark with wingfuzz.""" + print('Building with wingfuzz') + out_dir = os.environ['OUT'] + wingfuzz_target_dir = get_wingfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = wingfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + wingfuzz_build() + os.environ['OUT'] = out_dir + +def build_honggfuzz(): + """Build benchmark with Honggfuzz.""" + print('Building with Honggfuzz') + out_dir = os.environ['OUT'] + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = honggfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + honggfuzz_build() + os.environ['OUT'] = out_dir + +def prepare_build_environment(): + """Prepare build environment.""" + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + wingfuzz_target_dir = get_wingfuzz_target_dir(os.environ['OUT']) + + os.makedirs(aflpp_target_dir, exist_ok=True) + os.makedirs(honggfuzz_target_dir, exist_ok=True) + os.makedirs(wingfuzz_target_dir, exist_ok=True) + +def build(): + """Build benchmark.""" + prepare_build_environment() + new_env = os.environ.copy() + cflags = ['-fsanitize=fuzzer-no-link'] + utils.append_flags('CFLAGS', cflags, env=new_env) + utils.append_flags('CXXFLAGS', cflags, env=new_env) + src = new_env.get('SRC') + work = new_env.get('WORK') + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/usr/lib/libHCFUZZER.a' + with utils.restore_directory(src), utils.restore_directory(work): + utils.build_benchmark(env=new_env) + + + build_wingfuzz() + build_honggfuzz() + build_aflpp() + + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer. Wrapper that uses the defaults when calling + run_fuzzer.""" + run_fuzzer(input_corpus, + output_corpus, + target_binary, + extra_flags=['-keep_seed=0', '-cross_over_uniform_dist=1']) + + +def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None): + """Run fuzzer.""" + if extra_flags is None: + extra_flags = [] + + # Seperate out corpus and crash directories as sub-directories of + # |output_corpus| to avoid conflicts when corpus directory is reloaded. + crashes_dir = os.path.join(output_corpus, 'crashes') + output_corpus = os.path.join(output_corpus, 'corpus') + os.makedirs(crashes_dir) + os.makedirs(output_corpus) + + #prepare_fuzz_environment(input_corpus) + afl_fuzzer.prepare_fuzz_environment(input_corpus) + binary = os.path.basename(target_binary) + + os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' + os.environ['AFL_FAST_CAL'] = '1' + os.environ['AFL_NO_WARN_INSTABILITY'] = '1' + + flags = [ + '-print_final_stats=1', + # `close_fd_mask` to prevent too much logging output from the target. + '-close_fd_mask=3', + # Run in fork mode to allow ignoring ooms, timeouts, crashes and + # continue fuzzing indefinitely. + f'-target_program={binary}', + '-fuzzers=aflplusplus,wingfuzz,honggfuzz', + '-fork=1', + '-fork_job_budget_coe=4', + '-fork_num_seeds=3', + '-fork_max_job_time=1000', + '-ignore_ooms=1', + '-ignore_timeouts=1', + '-ignore_crashes=1', + + # Don't use LSAN's leak detection. Other fuzzers won't be using it and + # using it will cause libFuzzer to find "crashes" no one cares about. + '-detect_leaks=0', + + # Store crashes along with corpus for bug based benchmarking. + f'-artifact_prefix={crashes_dir}/', + ] + flags += extra_flags + + if 'ADDITIONAL_ARGS' in os.environ: + flags += os.environ['ADDITIONAL_ARGS'].split(' ') + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + flags.append('-dict=' + dictionary_path) + + command = [target_binary] + flags + [output_corpus, input_corpus] + print('[run_fuzzer] Running command: ' + ' '.join(command)) + subprocess.check_call(command) diff --git a/fuzzers/orchestra_4310/runner.Dockerfile b/fuzzers/orchestra_4310/runner.Dockerfile new file mode 100644 index 000000000..6eb790acf --- /dev/null +++ b/fuzzers/orchestra_4310/runner.Dockerfile @@ -0,0 +1,39 @@ +FROM gcr.io/fuzzbench/base-image + +# NOTE Comiple Python again with `--enabled-shared`. + +# Python 3.10.8 is not the default version in Ubuntu 20.04 (Focal Fossa). +ENV PYTHON_VERSION 3.10.8 + +RUN cd /tmp/ && \ + curl -O https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tar.xz && \ + tar -xvf Python-$PYTHON_VERSION.tar.xz > /dev/null && \ + cd Python-$PYTHON_VERSION && \ + ./configure \ + --enable-loadable-sqlite-extensions \ + --enable-optimizations \ + --enable-shared \ + > /dev/null && \ + make -j install > /dev/null && \ + rm -r /tmp/Python-$PYTHON_VERSION.tar.xz /tmp/Python-$PYTHON_VERSION + +# +# AFLplusplus +# + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 +ENV AFL_NO_AFFINITY=1 + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid +RUN apt-get update -y && apt-get install -y libbfd-dev libunwind-dev + diff --git a/fuzzers/orchestra_aflplusplus/builder.Dockerfile b/fuzzers/orchestra_aflplusplus/builder.Dockerfile new file mode 100644 index 000000000..ab3887d09 --- /dev/null +++ b/fuzzers/orchestra_aflplusplus/builder.Dockerfile @@ -0,0 +1,48 @@ +ARG parent_image +FROM $parent_image + +# +# AFLplusplus +# + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + python3-dev \ + python3-setuptools \ + automake \ + cmake \ + git \ + flex \ + bison \ + libglib2.0-dev \ + libpixman-1-dev \ + cargo \ + libgtk-3-dev \ + # for QEMU mode + ninja-build \ + gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev \ + libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev + +RUN git clone -b master https://github.com/gtt1995/GMFuzzer.git /gmfuzzer +RUN git clone -b fuzzers https://github.com/gtt1995/GMFuzzer.git /fuzzers +#COPY AFLplusplus /aflplusplus + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cp -r /fuzzers/AFLplusplus /aflplusplus && \ + cd /aflplusplus && \ + unset CFLAGS CXXFLAGS && \ + export CC=clang AFL_NO_X86=1 && \ + PYTHON_INCLUDE=/ make && \ + make install && \ + cp utils/aflpp_driver/libAFLDriver.a / && \ + make -C custom_mutators/autotokens && \ + cp -f custom_mutators/autotokens/autotokens.so . + + +RUN cd /gmfuzzer &&\ + (for f in *.cpp; do \ + clang++ -stdlib=libc++ -fPIC -O2 -std=c++11 $f -c & \ + done && wait) && \ + ar r /usr/lib/libHCFUZZER.a *.o diff --git a/fuzzers/orchestra_aflplusplus/fuzzer.py b/fuzzers/orchestra_aflplusplus/fuzzer.py new file mode 100644 index 000000000..0ab46509b --- /dev/null +++ b/fuzzers/orchestra_aflplusplus/fuzzer.py @@ -0,0 +1,344 @@ +# Copyright 2020 Google LLC +# +# 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. +# +"""Integration code for Collabtive Fuzzer Framework.""" + +import os +import shutil +import subprocess + +from fuzzers import utils +from fuzzers.afl import fuzzer as afl_fuzzer +def get_cmplog_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'cmplog') + + +def get_uninstrumented_build_directory(target_directory): + """Return path to CmpLog target directory.""" + return os.path.join(target_directory, 'uninstrumented') + + +def get_aflpp_target_dir(output_directory): + """Return path to AFL++'s target directory.""" + return os.path.join(output_directory, 'aflplusplus') + + +def aflplusplus_build(*args): # pylint: disable=too-many-branches,too-many-statements + """Build benchmark.""" + # BUILD_MODES is not already supported by fuzzbench, meanwhile we provide + # a default configuration. + + build_modes = list(args) + if 'BUILD_MODES' in os.environ: + build_modes = os.environ['BUILD_MODES'].split(',') + + # Placeholder comment. + build_directory = os.environ['OUT'] + + # If nothing was set this is the default: + if not build_modes: + build_modes = ['tracepc', 'cmplog', 'dict2file'] + + # For bug type benchmarks we have to instrument via native clang pcguard :( + build_flags = os.environ['CFLAGS'] + + if build_flags.find( + 'array-bounds' + ) != -1 and 'qemu' not in build_modes and 'classic' not in build_modes: + if 'gcc' not in build_modes: + build_modes[0] = 'native' + + # Instrumentation coverage modes: + if 'lto' in build_modes: + os.environ['CC'] = '/aflplusplus/afl-clang-lto' + os.environ['CXX'] = '/aflplusplus/afl-clang-lto++' + edge_file = build_directory + '/aflpp_edges.txt' + os.environ['AFL_LLVM_DOCUMENT_IDS'] = edge_file + if os.path.isfile('/usr/local/bin/llvm-ranlib-13'): + os.environ['RANLIB'] = 'llvm-ranlib-13' + os.environ['AR'] = 'llvm-ar-13' + os.environ['AS'] = 'llvm-as-13' + elif os.path.isfile('/usr/local/bin/llvm-ranlib-12'): + os.environ['RANLIB'] = 'llvm-ranlib-12' + os.environ['AR'] = 'llvm-ar-12' + os.environ['AS'] = 'llvm-as-12' + else: + os.environ['RANLIB'] = 'llvm-ranlib' + os.environ['AR'] = 'llvm-ar' + os.environ['AS'] = 'llvm-as' + elif 'qemu' in build_modes: + os.environ['CC'] = 'clang' + os.environ['CXX'] = 'clang++' + elif 'gcc' in build_modes: + os.environ['CC'] = 'afl-gcc-fast' + os.environ['CXX'] = 'afl-g++-fast' + if build_flags.find('array-bounds') != -1: + os.environ['CFLAGS'] = '-fsanitize=address -O1' + os.environ['CXXFLAGS'] = '-fsanitize=address -O1' + else: + os.environ['CFLAGS'] = '' + os.environ['CXXFLAGS'] = '' + os.environ['CPPFLAGS'] = '' + else: + os.environ['CC'] = '/aflplusplus/afl-clang-fast' + os.environ['CXX'] = '/aflplusplus/afl-clang-fast++' + + print('AFL++ build: ') + print(build_modes) + + if 'qemu' in build_modes or 'symcc' in build_modes: + os.environ['CFLAGS'] = ' '.join(utils.NO_SANITIZER_COMPAT_CFLAGS) + cxxflags = [utils.LIBCPLUSPLUS_FLAG] + utils.NO_SANITIZER_COMPAT_CFLAGS + os.environ['CXXFLAGS'] = ' '.join(cxxflags) + + if 'tracepc' in build_modes or 'pcguard' in build_modes: + os.environ['AFL_LLVM_USE_TRACE_PC'] = '1' + elif 'classic' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'CLASSIC' + elif 'native' in build_modes: + os.environ['AFL_LLVM_INSTRUMENT'] = 'LLVMNATIVE' + + # Instrumentation coverage options: + # Do not use a fixed map location (LTO only) + if 'dynamic' in build_modes: + os.environ['AFL_LLVM_MAP_DYNAMIC'] = '1' + # Use a fixed map location (LTO only) + if 'fixed' in build_modes: + os.environ['AFL_LLVM_MAP_ADDR'] = '0x10000' + # Generate an extra dictionary. + if 'dict2file' in build_modes or 'native' in build_modes: + os.environ['AFL_LLVM_DICT2FILE'] = build_directory + '/afl++.dict' + os.environ['AFL_LLVM_DICT2FILE_NO_MAIN'] = '1' + # Enable context sentitivity for LLVM mode (non LTO only) + if 'ctx' in build_modes: + os.environ['AFL_LLVM_CTX'] = '1' + # Enable N-gram coverage for LLVM mode (non LTO only) + if 'ngram2' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '2' + elif 'ngram3' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '3' + elif 'ngram4' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '4' + elif 'ngram5' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '5' + elif 'ngram6' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '6' + elif 'ngram7' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '7' + elif 'ngram8' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '8' + elif 'ngram16' in build_modes: + os.environ['AFL_LLVM_NGRAM_SIZE'] = '16' + if 'ctx1' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '1' + elif 'ctx2' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '2' + elif 'ctx3' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '3' + elif 'ctx4' in build_modes: + os.environ['AFL_LLVM_CTX_K'] = '4' + + # Only one of the following OR cmplog + # enable laf-intel compare splitting + if 'laf' in build_modes: + os.environ['AFL_LLVM_LAF_SPLIT_SWITCHES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_COMPARES'] = '1' + os.environ['AFL_LLVM_LAF_SPLIT_FLOATS'] = '1' + if 'autodict' not in build_modes: + os.environ['AFL_LLVM_LAF_TRANSFORM_COMPARES'] = '1' + + if 'eclipser' in build_modes: + os.environ['FUZZER_LIB'] = '/libStandaloneFuzzTarget.a' + else: + os.environ['FUZZER_LIB'] = '/libAFLDriver.a' + + # Some benchmarks like lcms. (see: + # https://github.com/mm2/Little-CMS/commit/ab1093539b4287c233aca6a3cf53b234faceb792#diff-f0e6d05e72548974e852e8e55dffc4ccR212) + # fail to compile if the compiler outputs things to stderr in unexpected + # cases. Prevent these failures by using AFL_QUIET to stop afl-clang-fast + # from writing AFL specific messages to stderr. + os.environ['AFL_QUIET'] = '1' + os.environ['AFL_MAP_SIZE'] = '2621440' + + src = os.getenv('SRC') + work = os.getenv('WORK') + + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + utils.build_benchmark() + + if 'cmplog' in build_modes and 'qemu' not in build_modes: + + # CmpLog requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['AFL_LLVM_CMPLOG'] = '1' + + # For CmpLog build, set the OUT and FUZZ_TARGET environment + # variable to point to the new CmpLog build directory. + cmplog_build_directory = get_cmplog_build_directory(build_directory) + os.mkdir(cmplog_build_directory) + new_env['OUT'] = cmplog_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(cmplog_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for CmpLog fuzzing target') + utils.build_benchmark(env=new_env) + + if 'symcc' in build_modes: + + symcc_build_directory = get_uninstrumented_build_directory( + build_directory) + os.mkdir(symcc_build_directory) + + # symcc requires an build with different instrumentation. + new_env = os.environ.copy() + new_env['CC'] = '/symcc/build/symcc' + new_env['CXX'] = '/symcc/build/sym++' + new_env['SYMCC_OUTPUT_DIR'] = '/tmp' + new_env['CXXFLAGS'] = new_env['CXXFLAGS'].replace('-stlib=libc++', '') + new_env['FUZZER_LIB'] = '/libfuzzer-harness.o' + new_env['OUT'] = symcc_build_directory + new_env['SYMCC_LIBCXX_PATH'] = '/libcxx_native_build' + new_env['SYMCC_NO_SYMBOLIC_INPUT'] = '1' + new_env['SYMCC_SILENT'] = '1' + + # For symcc build, set the OUT and FUZZ_TARGET environment + # variable to point to the new symcc build directory. + new_env['OUT'] = symcc_build_directory + fuzz_target = os.getenv('FUZZ_TARGET') + if fuzz_target: + new_env['FUZZ_TARGET'] = os.path.join(symcc_build_directory, + os.path.basename(fuzz_target)) + + print('Re-building benchmark for symcc fuzzing target') + utils.build_benchmark(env=new_env) + + shutil.copy('/aflplusplus/afl-fuzz', build_directory) + if os.path.exists('/aflplusplus/afl-qemu-trace'): + shutil.copy('/aflplusplus/afl-qemu-trace', build_directory) + if os.path.exists('/aflpp_qemu_driver_hook.so'): + shutil.copy('/aflpp_qemu_driver_hook.so', build_directory) + if os.path.exists('/get_frida_entry.sh'): + shutil.copy('/aflplusplus/afl-frida-trace.so', build_directory) + shutil.copy('/get_frida_entry.sh', build_directory) + shutil.copy('/aflplusplus/autotokens.so', build_directory) + + +def build_aflpp(): + """Build benchmark with AFL++.""" + print('Building with AFL++') + out_dir = os.environ['OUT'] + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + os.environ['OUT'] = aflpp_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(src): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + aflplusplus_build() + os.environ['OUT'] = out_dir + +def prepare_build_environment(): + """Prepare build environment.""" + aflpp_target_dir = get_aflpp_target_dir(os.environ['OUT']) + os.makedirs(aflpp_target_dir, exist_ok=True) + +def build(): + """Build benchmark.""" + prepare_build_environment() + new_env = os.environ.copy() + cflags = ['-fsanitize=fuzzer-no-link'] + utils.append_flags('CFLAGS', cflags, env=new_env) + utils.append_flags('CXXFLAGS', cflags, env=new_env) + src = new_env.get('SRC') + work = new_env.get('WORK') + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/usr/lib/libHCFUZZER.a' + with utils.restore_directory(src), utils.restore_directory(work): + utils.build_benchmark(env=new_env) + + build_aflpp() + + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer. Wrapper that uses the defaults when calling + run_fuzzer.""" + run_fuzzer(input_corpus, + output_corpus, + target_binary, + extra_flags=['-keep_seed=0', '-cross_over_uniform_dist=1']) + + +def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None): + """Run fuzzer.""" + if extra_flags is None: + extra_flags = [] + + # Seperate out corpus and crash directories as sub-directories of + # |output_corpus| to avoid conflicts when corpus directory is reloaded. + crashes_dir = os.path.join(output_corpus, 'crashes') + output_corpus = os.path.join(output_corpus, 'corpus') + os.makedirs(crashes_dir) + os.makedirs(output_corpus) + + #prepare_fuzz_environment(input_corpus) + afl_fuzzer.prepare_fuzz_environment(input_corpus) + binary = os.path.basename(target_binary) + + os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' + os.environ['AFL_FAST_CAL'] = '1' + os.environ['AFL_NO_WARN_INSTABILITY'] = '1' + + flags = [ + '-print_final_stats=1', + # `close_fd_mask` to prevent too much logging output from the target. + '-close_fd_mask=3', + # Run in fork mode to allow ignoring ooms, timeouts, crashes and + # continue fuzzing indefinitely. + f'-target_program={binary}', + '-fuzzers=aflplusplus', + '-fork=1', + '-fork_job_budget_coe=2', + '-fork_num_seeds=3', + '-fork_max_job_time=600', + '-ignore_ooms=1', + '-ignore_timeouts=1', + '-ignore_crashes=1', + + # Don't use LSAN's leak detection. Other fuzzers won't be using it and + # using it will cause libFuzzer to find "crashes" no one cares about. + '-detect_leaks=0', + + # Store crashes along with corpus for bug based benchmarking. + f'-artifact_prefix={crashes_dir}/', + ] + flags += extra_flags + + if 'ADDITIONAL_ARGS' in os.environ: + flags += os.environ['ADDITIONAL_ARGS'].split(' ') + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + flags.append('-dict=' + dictionary_path) + + command = [target_binary] + flags + [output_corpus, input_corpus] + print('[run_fuzzer] Running command: ' + ' '.join(command)) + subprocess.check_call(command) diff --git a/fuzzers/orchestra_aflplusplus/runner.Dockerfile b/fuzzers/orchestra_aflplusplus/runner.Dockerfile new file mode 100644 index 000000000..c86ab1375 --- /dev/null +++ b/fuzzers/orchestra_aflplusplus/runner.Dockerfile @@ -0,0 +1,34 @@ +FROM gcr.io/fuzzbench/base-image + +# NOTE Comiple Python again with `--enabled-shared`. + +# Python 3.10.8 is not the default version in Ubuntu 20.04 (Focal Fossa). +ENV PYTHON_VERSION 3.10.8 + +RUN cd /tmp/ && \ + curl -O https://www.python.org/ftp/python/$PYTHON_VERSION/Python-$PYTHON_VERSION.tar.xz && \ + tar -xvf Python-$PYTHON_VERSION.tar.xz > /dev/null && \ + cd Python-$PYTHON_VERSION && \ + ./configure \ + --enable-loadable-sqlite-extensions \ + --enable-optimizations \ + --enable-shared \ + > /dev/null && \ + make -j install > /dev/null && \ + rm -r /tmp/Python-$PYTHON_VERSION.tar.xz /tmp/Python-$PYTHON_VERSION + +# +# AFLplusplus +# + +# This makes interactive docker runs painless: +ENV LD_LIBRARY_PATH="$LD_LIBRARY_PATH:/out" +#ENV AFL_MAP_SIZE=2621440 +ENV PATH="$PATH:/out" +ENV AFL_SKIP_CPUFREQ=1 +ENV AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES=1 +ENV AFL_TESTCACHE_SIZE=2 +ENV AFL_NO_AFFINITY=1 + + + diff --git a/fuzzers/orchestra_honggfuzz/builder.Dockerfile b/fuzzers/orchestra_honggfuzz/builder.Dockerfile new file mode 100644 index 000000000..844f9e069 --- /dev/null +++ b/fuzzers/orchestra_honggfuzz/builder.Dockerfile @@ -0,0 +1,57 @@ +ARG parent_image +FROM $parent_image + +# +# AFLplusplus +# + +RUN apt-get update && \ + apt-get install -y \ + build-essential \ + python3-dev \ + python3-setuptools \ + automake \ + cmake \ + git \ + flex \ + bison \ + libglib2.0-dev \ + libpixman-1-dev \ + cargo \ + libgtk-3-dev \ + # for QEMU mode + ninja-build \ + gcc-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-plugin-dev \ + libstdc++-$(gcc --version|head -n1|sed 's/\..*//'|sed 's/.* //')-dev + +RUN git clone -b master https://github.com/gtt1995/GMFuzzer.git /gmfuzzer +RUN git clone -b fuzzers https://github.com/gtt1995/GMFuzzer.git /fuzzers +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid. +RUN apt-get install -y \ + libbfd-dev \ + libunwind-dev \ + libblocksruntime-dev \ + liblzma-dev + +#COPY honggfuzz /honggfuzz + +# Set CFLAGS use honggfuzz's defaults except for -mnative which can build CPU +# dependent code that may not work on the machines we actually fuzz on. +# Create an empty object file which will become the FUZZER_LIB lib (since +# honggfuzz doesn't need this when hfuzz-clang(++) is used). +RUN cp -r /fuzzers/honggfuzz /honggfuzz && \ + cd /honggfuzz && \ + CFLAGS="-O3 -funroll-loops" make && \ + touch empty_lib.c && \ + cc -c -o empty_lib.o empty_lib.c + + +RUN cd /gmfuzzer &&\ + (for f in *.cpp; do \ + clang++ -stdlib=libc++ -fPIC -O2 -std=c++11 $f -c & \ + done && wait) && \ + ar r /usr/lib/libHCFUZZER.a *.o diff --git a/fuzzers/orchestra_honggfuzz/fuzzer.py b/fuzzers/orchestra_honggfuzz/fuzzer.py new file mode 100644 index 000000000..ef5060ec3 --- /dev/null +++ b/fuzzers/orchestra_honggfuzz/fuzzer.py @@ -0,0 +1,146 @@ +# Copyright 2020 Google LLC +# +# 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. +# +"""Integration code for Collabtive Fuzzer Framework.""" + +import os +import shutil +import subprocess + +from fuzzers import utils +from fuzzers.afl import fuzzer as afl_fuzzer + + +def get_honggfuzz_target_dir(output_directory): + """Return path to Honggfuzz's target directory.""" + return os.path.join(output_directory, 'honggfuzz') + + +def honggfuzz_build(): + """Build benchmark.""" + new_env = os.environ.copy() + + new_env['CC'] = '/honggfuzz/hfuzz_cc/hfuzz-clang' + new_env['CXX'] = '/honggfuzz/hfuzz_cc/hfuzz-clang++' + new_env['FUZZER_LIB'] = '/honggfuzz/empty_lib.o' + + utils.build_benchmark(env=new_env) + + print('[post_build] Copying honggfuzz to $OUT directory') + # Copy over honggfuzz's main fuzzing binary. + shutil.copy('/honggfuzz/honggfuzz', os.environ['OUT']) + + +def build_honggfuzz(): + """Build benchmark with Honggfuzz.""" + print('Building with Honggfuzz') + out_dir = os.environ['OUT'] + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + os.environ['OUT'] = honggfuzz_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + honggfuzz_build() + os.environ['OUT'] = out_dir + +def prepare_build_environment(): + """Prepare build environment.""" + honggfuzz_target_dir = get_honggfuzz_target_dir(os.environ['OUT']) + + os.makedirs(honggfuzz_target_dir, exist_ok=True) + +def build(): + """Build benchmark.""" + prepare_build_environment() + new_env = os.environ.copy() + cflags = ['-fsanitize=fuzzer-no-link'] + utils.append_flags('CFLAGS', cflags, env=new_env) + utils.append_flags('CXXFLAGS', cflags, env=new_env) + src = new_env.get('SRC') + work = new_env.get('WORK') + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/usr/lib/libHCFUZZER.a' + with utils.restore_directory(src), utils.restore_directory(work): + utils.build_benchmark(env=new_env) + + build_honggfuzz() + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer. Wrapper that uses the defaults when calling + run_fuzzer.""" + run_fuzzer(input_corpus, + output_corpus, + target_binary, + extra_flags=['-keep_seed=0', '-cross_over_uniform_dist=1']) + + +def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None): + """Run fuzzer.""" + if extra_flags is None: + extra_flags = [] + + # Seperate out corpus and crash directories as sub-directories of + # |output_corpus| to avoid conflicts when corpus directory is reloaded. + crashes_dir = os.path.join(output_corpus, 'crashes') + output_corpus = os.path.join(output_corpus, 'corpus') + os.makedirs(crashes_dir) + os.makedirs(output_corpus) + + #prepare_fuzz_environment(input_corpus) + afl_fuzzer.prepare_fuzz_environment(input_corpus) + binary = os.path.basename(target_binary) + + os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' + os.environ['AFL_FAST_CAL'] = '1' + os.environ['AFL_NO_WARN_INSTABILITY'] = '1' + + flags = [ + '-print_final_stats=1', + # `close_fd_mask` to prevent too much logging output from the target. + '-close_fd_mask=3', + # Run in fork mode to allow ignoring ooms, timeouts, crashes and + # continue fuzzing indefinitely. + f'-target_program={binary}', + '-fuzzers=honggfuzz', + '-fork=1', + '-fork_job_budget_coe=2', + '-fork_num_seeds=3', + '-fork_max_job_time=600', + '-ignore_ooms=1', + '-ignore_timeouts=1', + '-ignore_crashes=1', + + # Don't use LSAN's leak detection. Other fuzzers won't be using it and + # using it will cause libFuzzer to find "crashes" no one cares about. + '-detect_leaks=0', + + # Store crashes along with corpus for bug based benchmarking. + f'-artifact_prefix={crashes_dir}/', + ] + flags += extra_flags + + if 'ADDITIONAL_ARGS' in os.environ: + flags += os.environ['ADDITIONAL_ARGS'].split(' ') + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + flags.append('-dict=' + dictionary_path) + + command = [target_binary] + flags + [output_corpus, input_corpus] + print('[run_fuzzer] Running command: ' + ' '.join(command)) + subprocess.check_call(command) diff --git a/fuzzers/orchestra_honggfuzz/runner.Dockerfile b/fuzzers/orchestra_honggfuzz/runner.Dockerfile new file mode 100644 index 000000000..5312db163 --- /dev/null +++ b/fuzzers/orchestra_honggfuzz/runner.Dockerfile @@ -0,0 +1,9 @@ +FROM gcr.io/fuzzbench/base-image + +# +# Honggfuzz +# + +# honggfuzz requires libfd and libunwid +RUN apt-get update -y && apt-get install -y libbfd-dev libunwind-dev + diff --git a/fuzzers/orchestra_libfuzzer/builder.Dockerfile b/fuzzers/orchestra_libfuzzer/builder.Dockerfile new file mode 100644 index 000000000..cf3445d6b --- /dev/null +++ b/fuzzers/orchestra_libfuzzer/builder.Dockerfile @@ -0,0 +1,34 @@ +ARG parent_image +FROM $parent_image + +# +# AFLplusplus +# + +RUN apt-get update && \ + apt-get install -y \ + wget + +RUN git clone -b master https://github.com/gtt1995/GMFuzzer.git /gmfuzzer +RUN git clone -b fuzzers https://github.com/gtt1995/GMFuzzer.git /fuzzers + +# +#libfuzzer +# + +ENV LF_PATH /tmp/libfuzzer.zip + +# libFuzzer from branch llvmorg-15.0.3 with minor changes to build script. +RUN wget https://storage.googleapis.com/fuzzbench-artifacts/libfuzzer.zip -O $LF_PATH && \ + echo "ed761c02a98a16adf6bb9966bf9a3ffd6794367a29dd29d4944a5aae5dba3c90 $LF_PATH" | sha256sum --check --status && \ + mkdir /tmp/libfuzzer && \ + cd /tmp/libfuzzer && \ + unzip $LF_PATH && \ + bash build.sh && \ + cp libFuzzer.a /usr/lib + +RUN cd /gmfuzzer &&\ + (for f in *.cpp; do \ + clang++ -stdlib=libc++ -fPIC -O2 -std=c++11 $f -c & \ + done && wait) && \ + ar r /usr/lib/libHCFUZZER.a *.o diff --git a/fuzzers/orchestra_libfuzzer/fuzzer.py b/fuzzers/orchestra_libfuzzer/fuzzer.py new file mode 100644 index 000000000..1f85777a9 --- /dev/null +++ b/fuzzers/orchestra_libfuzzer/fuzzer.py @@ -0,0 +1,149 @@ +# Copyright 2020 Google LLC +# +# 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. +# +"""Integration code for Collabtive Fuzzer Framework.""" + +import os +import shutil +import subprocess + +from fuzzers import utils +from fuzzers.afl import fuzzer as afl_fuzzer + +def get_libfuzzer_target_dir(output_directory): + """Return path to libfuzzer's target directory.""" + return os.path.join(output_directory, 'libfuzzer') + +def libfuzzer_build(): + """Build benchmark.""" + # With LibFuzzer we use -fsanitize=fuzzer-no-link for build CFLAGS and then + # /usr/lib/libFuzzer.a as the FUZZER_LIB for the main fuzzing binary. This + # allows us to link against a version of LibFuzzer that we specify. + cflags = ['-fsanitize=fuzzer-no-link'] + utils.append_flags('CFLAGS', cflags) + utils.append_flags('CXXFLAGS', cflags) + + new_env = os.environ.copy() + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/usr/lib/libFuzzer.a' + + utils.build_benchmark(env=new_env) + +def build_libfuzzer(): + """Build benchmark with libfuzzer.""" + print('Building with libfuzzer') + out_dir = os.environ['OUT'] + libfuzzer_target_dir = get_libfuzzer_target_dir(os.environ['OUT']) + os.environ['OUT'] = libfuzzer_target_dir + src = os.getenv('SRC') + work = os.getenv('WORK') + with utils.restore_directory(src), utils.restore_directory(work): + # Restore SRC to its initial state so we can build again without any + # trouble. For some OSS-Fuzz projects, build_benchmark cannot be run + # twice in the same directory without this. + libfuzzer_build() + os.environ['OUT'] = out_dir + + +def prepare_build_environment(): + """Prepare build environment.""" + + libfuzzer_target_dir = get_libfuzzer_target_dir(os.environ['OUT']) + + os.makedirs(libfuzzer_target_dir, exist_ok=True) + + +def build(): + """Build benchmark.""" + prepare_build_environment() + new_env = os.environ.copy() + cflags = ['-fsanitize=fuzzer-no-link'] + utils.append_flags('CFLAGS', cflags, env=new_env) + utils.append_flags('CXXFLAGS', cflags, env=new_env) + src = new_env.get('SRC') + work = new_env.get('WORK') + new_env['CC'] = 'clang' + new_env['CXX'] = 'clang++' + new_env['FUZZER_LIB'] = '/usr/lib/libHCFUZZER.a' + with utils.restore_directory(src), utils.restore_directory(work): + utils.build_benchmark(env=new_env) + + build_libfuzzer() + + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer. Wrapper that uses the defaults when calling + run_fuzzer.""" + run_fuzzer(input_corpus, + output_corpus, + target_binary, + extra_flags=['-keep_seed=0', '-cross_over_uniform_dist=1']) + + +def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None): + """Run fuzzer.""" + if extra_flags is None: + extra_flags = [] + + # Seperate out corpus and crash directories as sub-directories of + # |output_corpus| to avoid conflicts when corpus directory is reloaded. + crashes_dir = os.path.join(output_corpus, 'crashes') + output_corpus = os.path.join(output_corpus, 'corpus') + os.makedirs(crashes_dir) + os.makedirs(output_corpus) + + #prepare_fuzz_environment(input_corpus) + afl_fuzzer.prepare_fuzz_environment(input_corpus) + binary = os.path.basename(target_binary) + + os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' + os.environ['AFL_FAST_CAL'] = '1' + os.environ['AFL_NO_WARN_INSTABILITY'] = '1' + + flags = [ + '-print_final_stats=1', + # `close_fd_mask` to prevent too much logging output from the target. + '-close_fd_mask=3', + # Run in fork mode to allow ignoring ooms, timeouts, crashes and + # continue fuzzing indefinitely. + f'-target_program={binary}', + '-fuzzers=libfuzzer', + '-fork=1', + '-fork_job_budget_coe=2', + '-fork_num_seeds=3', + '-fork_max_job_time=600', + '-ignore_ooms=1', + '-ignore_timeouts=1', + '-ignore_crashes=1', + + # Don't use LSAN's leak detection. Other fuzzers won't be using it and + # using it will cause libFuzzer to find "crashes" no one cares about. + '-detect_leaks=0', + + # Store crashes along with corpus for bug based benchmarking. + f'-artifact_prefix={crashes_dir}/', + ] + flags += extra_flags + + if 'ADDITIONAL_ARGS' in os.environ: + flags += os.environ['ADDITIONAL_ARGS'].split(' ') + dictionary_path = utils.get_dictionary_path(target_binary) + if dictionary_path: + flags.append('-dict=' + dictionary_path) + + command = [target_binary] + flags + [output_corpus, input_corpus] + print('[run_fuzzer] Running command: ' + ' '.join(command)) + subprocess.check_call(command) diff --git a/fuzzers/orchestra_libfuzzer/runner.Dockerfile b/fuzzers/orchestra_libfuzzer/runner.Dockerfile new file mode 100644 index 000000000..500175092 --- /dev/null +++ b/fuzzers/orchestra_libfuzzer/runner.Dockerfile @@ -0,0 +1 @@ +FROM gcr.io/fuzzbench/base-image diff --git a/service/experiment-requests.yaml b/service/experiment-requests.yaml index fe0efe2a2..3733800fa 100644 --- a/service/experiment-requests.yaml +++ b/service/experiment-requests.yaml @@ -20,6 +20,19 @@ # Please add new experiment requests towards the top of this file. # +- experiment: 2023-09-25 + description: "Benchmark orchestra config" + fuzzers: + - orchestra_236 + - orchestra_339 + - orchestra_4310 + - orchestra_219 + - orchestra_116 + - orchestra_aflplusplus + - orchestra_honggfuzz + - orchestra_libfuzzer + - pastis + - experiment: 2023-06-12-aflpp description: "Benchmark afl++ releases and newmutation" fuzzers: diff --git a/service/gcbrun_experiment.py b/service/gcbrun_experiment.py index bbebcf1b9..452807778 100644 --- a/service/gcbrun_experiment.py +++ b/service/gcbrun_experiment.py @@ -22,6 +22,7 @@ import sys # pytype: disable=import-error +# a dummpy comment import github # pylint: disable=import-error from experiment import run_experiment