From ad7daed2647c1c7a091bd1b16a0fd1a806c03db4 Mon Sep 17 00:00:00 2001 From: Toka Date: Tue, 13 Aug 2024 15:29:59 +0200 Subject: [PATCH 01/17] empty --- fuzzers/afl_empty_seeds/builder.Dockerfile | 33 ++ fuzzers/afl_empty_seeds/fuzzer.py | 151 +++++++++ fuzzers/afl_empty_seeds/runner.Dockerfile | 15 + .../builder.Dockerfile | 49 +++ .../aflplusplus_empty_seeds/description.md | 14 + fuzzers/aflplusplus_empty_seeds/fuzzer.py | 291 ++++++++++++++++++ .../aflplusplus_empty_seeds/runner.Dockerfile | 24 ++ .../honggfuzz_empty_seeds/builder.Dockerfile | 36 +++ fuzzers/honggfuzz_empty_seeds/fuzzer.py | 78 +++++ .../honggfuzz_empty_seeds/runner.Dockerfile | 18 ++ fuzzers/libafl_empty_seeds/builder.Dockerfile | 60 ++++ fuzzers/libafl_empty_seeds/description.md | 11 + fuzzers/libafl_empty_seeds/fuzzer.py | 80 +++++ fuzzers/libafl_empty_seeds/runner.Dockerfile | 25 ++ .../libfuzzer_empty_seeds/builder.Dockerfile | 26 ++ fuzzers/libfuzzer_empty_seeds/fuzzer.py | 102 ++++++ fuzzers/libfuzzer_empty_seeds/patch.diff | 100 ++++++ .../libfuzzer_empty_seeds/runner.Dockerfile | 15 + 18 files changed, 1128 insertions(+) create mode 100644 fuzzers/afl_empty_seeds/builder.Dockerfile create mode 100755 fuzzers/afl_empty_seeds/fuzzer.py create mode 100644 fuzzers/afl_empty_seeds/runner.Dockerfile create mode 100644 fuzzers/aflplusplus_empty_seeds/builder.Dockerfile create mode 100644 fuzzers/aflplusplus_empty_seeds/description.md create mode 100755 fuzzers/aflplusplus_empty_seeds/fuzzer.py create mode 100644 fuzzers/aflplusplus_empty_seeds/runner.Dockerfile create mode 100644 fuzzers/honggfuzz_empty_seeds/builder.Dockerfile create mode 100644 fuzzers/honggfuzz_empty_seeds/fuzzer.py create mode 100644 fuzzers/honggfuzz_empty_seeds/runner.Dockerfile create mode 100644 fuzzers/libafl_empty_seeds/builder.Dockerfile create mode 100644 fuzzers/libafl_empty_seeds/description.md create mode 100755 fuzzers/libafl_empty_seeds/fuzzer.py create mode 100644 fuzzers/libafl_empty_seeds/runner.Dockerfile create mode 100644 fuzzers/libfuzzer_empty_seeds/builder.Dockerfile create mode 100755 fuzzers/libfuzzer_empty_seeds/fuzzer.py create mode 100644 fuzzers/libfuzzer_empty_seeds/patch.diff create mode 100644 fuzzers/libfuzzer_empty_seeds/runner.Dockerfile diff --git a/fuzzers/afl_empty_seeds/builder.Dockerfile b/fuzzers/afl_empty_seeds/builder.Dockerfile new file mode 100644 index 000000000..94d7f5076 --- /dev/null +++ b/fuzzers/afl_empty_seeds/builder.Dockerfile @@ -0,0 +1,33 @@ +# 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. + +ARG parent_image +FROM $parent_image + +# Download and compile AFL v2.57b. +# Set AFL_NO_X86 to skip flaky tests. +RUN git clone \ + --depth 1 \ + --branch v2.57b \ + https://github.com/google/AFL.git /afl && \ + cd /afl && \ + CFLAGS= CXXFLAGS= AFL_NO_X86=1 make + +# Use afl_driver.cpp from LLVM as our fuzzing library. +RUN apt-get update && \ + apt-get install wget -y && \ + wget https://raw.githubusercontent.com/llvm/llvm-project/5feb80e748924606531ba28c97fe65145c65372e/compiler-rt/lib/fuzzer/afl/afl_driver.cpp -O /afl/afl_driver.cpp && \ + clang -Wno-pointer-sign -c /afl/llvm_mode/afl-llvm-rt.o.c -I/afl && \ + clang++ -stdlib=libc++ -std=c++11 -O2 -c /afl/afl_driver.cpp && \ + ar r /libAFL.a *.o diff --git a/fuzzers/afl_empty_seeds/fuzzer.py b/fuzzers/afl_empty_seeds/fuzzer.py new file mode 100755 index 000000000..c0d8956eb --- /dev/null +++ b/fuzzers/afl_empty_seeds/fuzzer.py @@ -0,0 +1,151 @@ +# 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 AFL fuzzer.""" + +import json +import os +import shutil +import subprocess + +from fuzzers import utils + + +def prepare_build_environment(): + """Set environment variables used to build targets for AFL-based + fuzzers.""" + cflags = ['-fsanitize-coverage=trace-pc-guard'] + utils.append_flags('CFLAGS', cflags) + utils.append_flags('CXXFLAGS', cflags) + + os.environ['CC'] = 'clang' + os.environ['CXX'] = 'clang++' + os.environ['FUZZER_LIB'] = '/libAFL.a' + + +def build(): + """Build benchmark.""" + prepare_build_environment() + + utils.build_benchmark() + + print('[post_build] Copying afl-fuzz to $OUT directory') + # Copy out the afl-fuzz binary as a build artifact. + shutil.copy('/afl/afl-fuzz', os.environ['OUT']) + + +def get_stats(output_corpus, fuzzer_log): # pylint: disable=unused-argument + """Gets fuzzer stats for AFL.""" + # Get a dictionary containing the stats AFL reports. + stats_file = os.path.join(output_corpus, 'fuzzer_stats') + if not os.path.exists(stats_file): + print('Can\'t find fuzzer_stats') + return '{}' + with open(stats_file, encoding='utf-8') as file_handle: + stats_file_lines = file_handle.read().splitlines() + stats_file_dict = {} + for stats_line in stats_file_lines: + key, value = stats_line.split(': ') + stats_file_dict[key.strip()] = value.strip() + + # Report to FuzzBench the stats it accepts. + stats = {'execs_per_sec': float(stats_file_dict['execs_per_sec'])} + return json.dumps(stats) + + +def prepare_fuzz_environment(input_corpus): + """Prepare to fuzz with AFL or another AFL-based fuzzer.""" + # Tell AFL to not use its terminal UI so we get usable logs. + os.environ['AFL_NO_UI'] = '1' + # Skip AFL's CPU frequency check (fails on Docker). + os.environ['AFL_SKIP_CPUFREQ'] = '1' + # No need to bind affinity to one core, Docker enforces 1 core usage. + os.environ['AFL_NO_AFFINITY'] = '1' + # AFL will abort on startup if the core pattern sends notifications to + # external programs. We don't care about this. + os.environ['AFL_I_DONT_CARE_ABOUT_MISSING_CRASHES'] = '1' + # Don't exit when crashes are found. This can happen when corpus from + # OSS-Fuzz is used. + os.environ['AFL_SKIP_CRASHES'] = '1' + # Shuffle the queue + os.environ['AFL_SHUFFLE_QUEUE'] = '1' + + # AFL needs at least one non-empty seed to start. + utils.create_seed_file_for_empty_corpus(input_corpus) + + +def check_skip_det_compatible(additional_flags): + """ Checks if additional flags are compatible with '-d' option""" + # AFL refuses to take in '-d' with '-M' or '-S' options for parallel mode. + # (cf. https://github.com/google/AFL/blob/8da80951/afl-fuzz.c#L7477) + if '-M' in additional_flags or '-S' in additional_flags: + return False + return True + +def prepare_empty_corpus(input_corpus): + if os.path.exists(input_corpus): + shutil.rmtree(input_corpus) + os.makedirs(input_corpus) + with open(os.path.join(input_corpus, 'a'), 'wb') as f: + f.write(b'a') + + +def run_afl_fuzz(input_corpus, + output_corpus, + target_binary, + additional_flags=None, + hide_output=False): + """Run afl-fuzz.""" + + prepare_empty_corpus(input_corpus) + # Spawn the afl fuzzing process. + print('[run_afl_fuzz] Running target with afl-fuzz') + command = [ + './afl-fuzz', + '-i', + input_corpus, + '-o', + output_corpus, + # Use no memory limit as ASAN doesn't play nicely with one. + '-m', + 'none', + '-t', + '1000+', # Use same default 1 sec timeout, but add '+' to skip hangs. + ] + # Use '-d' to skip deterministic mode, as long as it it compatible with + # additional flags. + if not additional_flags or check_skip_det_compatible(additional_flags): + command.append('-d') + if additional_flags: + command.extend(additional_flags) + dictionary_path = utils.get_dictionary_path(target_binary) + + # if dictionary_path: + # command.extend(['-x', dictionary_path]) + command += [ + '--', + target_binary, + # Pass INT_MAX to afl the maximize the number of persistent loops it + # performs. + '2147483647' + ] + print('[run_afl_fuzz] Running command: ' + ' '.join(command)) + output_stream = subprocess.DEVNULL if hide_output else None + subprocess.check_call(command, stdout=output_stream, stderr=output_stream) + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run afl-fuzz on target.""" + prepare_fuzz_environment(input_corpus) + + run_afl_fuzz(input_corpus, output_corpus, target_binary) diff --git a/fuzzers/afl_empty_seeds/runner.Dockerfile b/fuzzers/afl_empty_seeds/runner.Dockerfile new file mode 100644 index 000000000..0d6cf004e --- /dev/null +++ b/fuzzers/afl_empty_seeds/runner.Dockerfile @@ -0,0 +1,15 @@ +# 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. + +FROM gcr.io/fuzzbench/base-image diff --git a/fuzzers/aflplusplus_empty_seeds/builder.Dockerfile b/fuzzers/aflplusplus_empty_seeds/builder.Dockerfile new file mode 100644 index 000000000..fc0561c41 --- /dev/null +++ b/fuzzers/aflplusplus_empty_seeds/builder.Dockerfile @@ -0,0 +1,49 @@ +# 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. + +ARG parent_image +FROM $parent_image + +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 + +# Download afl++. +RUN git clone -b dev https://github.com/AFLplusplus/AFLplusplus /afl && \ + cd /afl && \ + git checkout 56d5aa3101945e81519a3fac8783d0d8fad82779 || \ + true + +# Build without Python support as we don't need it. +# Set AFL_NO_X86 to skip flaky tests. +RUN cd /afl && \ + unset CFLAGS CXXFLAGS && \ + export CC=clang AFL_NO_X86=1 && \ + PYTHON_INCLUDE=/ make && \ + cp utils/aflpp_driver/libAFLDriver.a / diff --git a/fuzzers/aflplusplus_empty_seeds/description.md b/fuzzers/aflplusplus_empty_seeds/description.md new file mode 100644 index 000000000..f7eb407ad --- /dev/null +++ b/fuzzers/aflplusplus_empty_seeds/description.md @@ -0,0 +1,14 @@ +# aflplusplus + +AFL++ fuzzer instance that has the following config active for all benchmarks: + - PCGUARD instrumentation + - cmplog feature + - dict2file feature + - "fast" power schedule + - persistent mode + shared memory test cases + +Repository: [https://github.com/AFLplusplus/AFLplusplus/](https://github.com/AFLplusplus/AFLplusplus/) + +[builder.Dockerfile](builder.Dockerfile) +[fuzzer.py](fuzzer.py) +[runner.Dockerfile](runner.Dockerfile) diff --git a/fuzzers/aflplusplus_empty_seeds/fuzzer.py b/fuzzers/aflplusplus_empty_seeds/fuzzer.py new file mode 100755 index 000000000..295d4c8f4 --- /dev/null +++ b/fuzzers/aflplusplus_empty_seeds/fuzzer.py @@ -0,0 +1,291 @@ +# 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 AFLplusplus fuzzer.""" + +import os +import shutil + +from fuzzers.afl import fuzzer as afl_fuzzer +from fuzzers import utils + + +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 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'] = '/afl/afl-clang-lto' + os.environ['CXX'] = '/afl/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'] = '/afl/afl-clang-fast' + os.environ['CXX'] = '/afl/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('/afl/afl-fuzz', build_directory) + if os.path.exists('/afl/afl-qemu-trace'): + shutil.copy('/afl/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('/afl/afl-frida-trace.so', build_directory) + shutil.copy('/get_frida_entry.sh', build_directory) + +def prepare_empty_corpus(input_corpus): + if os.path.exists(input_corpus): + shutil.rmtree(input_corpus) + os.makedirs(input_corpus) + with open(os.path.join(input_corpus, 'a'), 'wb') as f: + f.write(b'a') + + +# pylint: disable=too-many-arguments +def fuzz(input_corpus, + output_corpus, + target_binary, + flags=tuple(), + skip=False, + no_cmplog=False): # pylint: disable=too-many-arguments + """Run fuzzer.""" + + prepare_empty_corpus(input_corpus) + # Calculate CmpLog binary path from the instrumented target binary. + target_binary_directory = os.path.dirname(target_binary) + cmplog_target_binary_directory = ( + get_cmplog_build_directory(target_binary_directory)) + target_binary_name = os.path.basename(target_binary) + cmplog_target_binary = os.path.join(cmplog_target_binary_directory, + target_binary_name) + + afl_fuzzer.prepare_fuzz_environment(input_corpus) + # decomment this to enable libdislocator. + # os.environ['AFL_ALIGNED_ALLOC'] = '1' # align malloc to max_align_t + # os.environ['AFL_PRELOAD'] = '/afl/libdislocator.so' + + flags = list(flags) + + # if os.path.exists('./afl++.dict'): + # flags += ['-x', './afl++.dict'] + + # Move the following to skip for upcoming _double tests: + if os.path.exists(cmplog_target_binary) and no_cmplog is False: + flags += ['-c', cmplog_target_binary] + + #os.environ['AFL_IGNORE_TIMEOUTS'] = '1' + os.environ['AFL_IGNORE_UNKNOWN_ENVS'] = '1' + os.environ['AFL_FAST_CAL'] = '1' + os.environ['AFL_NO_WARN_INSTABILITY'] = '1' + + if not skip: + os.environ['AFL_DISABLE_TRIM'] = '1' + os.environ['AFL_CMPLOG_ONLY_NEW'] = '1' + if 'ADDITIONAL_ARGS' in os.environ: + flags += os.environ['ADDITIONAL_ARGS'].split(' ') + + afl_fuzzer.run_afl_fuzz(input_corpus, + output_corpus, + target_binary, + additional_flags=flags) diff --git a/fuzzers/aflplusplus_empty_seeds/runner.Dockerfile b/fuzzers/aflplusplus_empty_seeds/runner.Dockerfile new file mode 100644 index 000000000..5640d5b24 --- /dev/null +++ b/fuzzers/aflplusplus_empty_seeds/runner.Dockerfile @@ -0,0 +1,24 @@ +# 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. + +FROM gcr.io/fuzzbench/base-image + +# 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 +# RUN apt-get update && apt-get upgrade && apt install -y unzip git gdb joe diff --git a/fuzzers/honggfuzz_empty_seeds/builder.Dockerfile b/fuzzers/honggfuzz_empty_seeds/builder.Dockerfile new file mode 100644 index 000000000..11a483288 --- /dev/null +++ b/fuzzers/honggfuzz_empty_seeds/builder.Dockerfile @@ -0,0 +1,36 @@ +# 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. + +ARG parent_image +FROM $parent_image + +# honggfuzz requires libfd and libunwid. +RUN apt-get update -y && \ + apt-get install -y \ + libbfd-dev \ + libunwind-dev \ + libblocksruntime-dev \ + liblzma-dev + +# Download honggfuz version 2.3.1 + 0b4cd5b1c4cf26b7e022dc1deb931d9318c054cb +# 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 git clone https://github.com/google/honggfuzz.git /honggfuzz && \ + cd /honggfuzz && \ + git checkout oss-fuzz && \ + CFLAGS="-O3 -funroll-loops" make && \ + touch empty_lib.c && \ + cc -c -o empty_lib.o empty_lib.c \ No newline at end of file diff --git a/fuzzers/honggfuzz_empty_seeds/fuzzer.py b/fuzzers/honggfuzz_empty_seeds/fuzzer.py new file mode 100644 index 000000000..642e8d1e0 --- /dev/null +++ b/fuzzers/honggfuzz_empty_seeds/fuzzer.py @@ -0,0 +1,78 @@ +# 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 Honggfuzz fuzzer.""" + +import os +import shutil +import subprocess + +from fuzzers import utils + + +def build(): + """Build benchmark.""" + # honggfuzz doesn't need additional libraries when code is compiled + # with hfuzz-clang(++) + os.environ['CC'] = '/honggfuzz/hfuzz_cc/hfuzz-clang' + os.environ['CXX'] = '/honggfuzz/hfuzz_cc/hfuzz-clang++' + os.environ['FUZZER_LIB'] = '/honggfuzz/empty_lib.o' + + utils.build_benchmark() + + print('[post_build] Copying honggfuzz to $OUT directory') + # Copy over honggfuzz's main fuzzing binary. + shutil.copy('/honggfuzz/honggfuzz', os.environ['OUT']) + + +def prepare_empty_corpus(input_corpus): + if os.path.exists(input_corpus): + shutil.rmtree(input_corpus) + os.makedirs(input_corpus) + with open(os.path.join(input_corpus, 'a'), 'wb') as f: + f.write(b'a') + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer.""" + + prepare_empty_corpus(input_corpus) + # 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) + + print('[fuzz] Running target with honggfuzz') + command = [ + './honggfuzz', + '--persistent', + '--rlimit_rss', + '2048', + '--sanitizers_del_report=true', + '--input', + input_corpus, + '--output', + output_corpus, + + # Store crashes along with corpus for bug based benchmarking. + '--crashdir', + crashes_dir, + ] + dictionary_path = utils.get_dictionary_path(target_binary) + #if dictionary_path: + # command.extend(['--dict', dictionary_path]) + command.extend(['--', target_binary]) + + print('[fuzz] Running command: ' + ' '.join(command)) + subprocess.check_call(command) diff --git a/fuzzers/honggfuzz_empty_seeds/runner.Dockerfile b/fuzzers/honggfuzz_empty_seeds/runner.Dockerfile new file mode 100644 index 000000000..f3eb30039 --- /dev/null +++ b/fuzzers/honggfuzz_empty_seeds/runner.Dockerfile @@ -0,0 +1,18 @@ +# 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. + +FROM gcr.io/fuzzbench/base-image + +# honggfuzz requires libfd and libunwid +RUN apt-get update -y && apt-get install -y libbfd-dev libunwind-dev diff --git a/fuzzers/libafl_empty_seeds/builder.Dockerfile b/fuzzers/libafl_empty_seeds/builder.Dockerfile new file mode 100644 index 000000000..3f726cfec --- /dev/null +++ b/fuzzers/libafl_empty_seeds/builder.Dockerfile @@ -0,0 +1,60 @@ +# 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. + +ARG parent_image +FROM $parent_image + +# Uninstall old Rust & Install the latest one. +RUN if which rustup; then rustup self uninstall -y; fi && \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /rustup.sh && \ + sh /rustup.sh --default-toolchain nightly-2023-09-21 -y && \ + rm /rustup.sh + +# Install dependencies. +RUN apt-get update && \ + apt-get remove -y llvm-10 && \ + apt-get install -y \ + build-essential \ + lsb-release wget software-properties-common gnupg && \ + apt-get install -y wget libstdc++5 libtool-bin automake flex bison \ + libglib2.0-dev libpixman-1-dev python3-setuptools unzip \ + apt-utils apt-transport-https ca-certificates joe curl && \ + wget https://apt.llvm.org/llvm.sh && chmod +x llvm.sh && ./llvm.sh 17 + +RUN wget https://gist.githubusercontent.com/tokatoka/26f4ba95991c6e33139999976332aa8e/raw/698ac2087d58ce5c7a6ad59adce58dbfdc32bd46/createAliases.sh && chmod u+x ./createAliases.sh && ./createAliases.sh + +# Uninstall old Rust & Install the latest one. +RUN if which rustup; then rustup self uninstall -y; fi && \ + curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /rustup.sh && \ + sh /rustup.sh --default-toolchain nightly-2024-03-12 -y && \ + rm /rustup.sh + +# Download libafl. +RUN git clone https://github.com/AFLplusplus/LibAFL /libafl + +# Checkout a current commit +RUN cd /libafl && git pull && git checkout b4efb6151550a37f61a869acf2957a1b07894a93 || true +# Note that due a nightly bug it is currently fixed to a known version on top! + +# Compile libafl. +RUN cd /libafl && \ + unset CFLAGS CXXFLAGS && \ + export LIBAFL_EDGES_MAP_SIZE=2621440 && \ + cd ./fuzzers/fuzzbench && \ + PATH="/root/.cargo/bin/:$PATH" cargo build --profile release-fuzzbench --features no_link_main + +# Auxiliary weak references. +RUN cd /libafl/fuzzers/fuzzbench && \ + clang -c stub_rt.c && \ + ar r /stub_rt.a stub_rt.o diff --git a/fuzzers/libafl_empty_seeds/description.md b/fuzzers/libafl_empty_seeds/description.md new file mode 100644 index 000000000..ea9b947d6 --- /dev/null +++ b/fuzzers/libafl_empty_seeds/description.md @@ -0,0 +1,11 @@ +# libafl + +libafl fuzzer instance + - cmplog feature + - persistent mode + +Repository: [https://github.com/AFLplusplus/libafl/](https://github.com/AFLplusplus/libafl/) + +[builder.Dockerfile](builder.Dockerfile) +[fuzzer.py](fuzzer.py) +[runner.Dockerfile](runner.Dockerfile) diff --git a/fuzzers/libafl_empty_seeds/fuzzer.py b/fuzzers/libafl_empty_seeds/fuzzer.py new file mode 100755 index 000000000..f3b578fb5 --- /dev/null +++ b/fuzzers/libafl_empty_seeds/fuzzer.py @@ -0,0 +1,80 @@ +# 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 a LibAFL-based fuzzer.""" + +import os +import subprocess +import shutil +from fuzzers import utils + + +def prepare_fuzz_environment(input_corpus): + """Prepare to fuzz with a LibAFL-based fuzzer.""" + os.environ['ASAN_OPTIONS'] = 'abort_on_error=1:detect_leaks=0:'\ + 'malloc_context_size=0:symbolize=0:'\ + 'allocator_may_return_null=1:'\ + 'detect_odr_violation=0:handle_segv=0:'\ + 'handle_sigbus=0:handle_abort=0:'\ + 'handle_sigfpe=0:handle_sigill=0' + os.environ['UBSAN_OPTIONS'] = 'abort_on_error=1:'\ + 'allocator_release_to_os_interval_ms=500:'\ + 'handle_abort=0:handle_segv=0:'\ + 'handle_sigbus=0:handle_sigfpe=0:'\ + 'handle_sigill=0:print_stacktrace=0:'\ + 'symbolize=0:symbolize_inline_frames=0' + # Create at least one non-empty seed to start. + utils.create_seed_file_for_empty_corpus(input_corpus) + + +def build(): # pylint: disable=too-many-branches,too-many-statements + """Build benchmark.""" + os.environ[ + 'CC'] = '/libafl/fuzzers/fuzzbench/target/release-fuzzbench/libafl_cc' + os.environ[ + 'CXX'] = '/libafl/fuzzers/fuzzbench/target/release-fuzzbench/libafl_cxx' + + os.environ['ASAN_OPTIONS'] = 'abort_on_error=0:allocator_may_return_null=1' + os.environ['UBSAN_OPTIONS'] = 'abort_on_error=0' + + cflags = ['--libafl'] + cxxflags = ['--libafl', '--std=c++14'] + utils.append_flags('CFLAGS', cflags) + utils.append_flags('CXXFLAGS', cxxflags) + utils.append_flags('LDFLAGS', cflags) + + os.environ['FUZZER_LIB'] = '/stub_rt.a' + utils.build_benchmark() + +def prepare_empty_corpus(input_corpus): + if os.path.exists(input_corpus): + shutil.rmtree(input_corpus) + os.makedirs(input_corpus) + with open(os.path.join(input_corpus, 'a'), 'wb') as f: + f.write(b'a') + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer.""" + prepare_fuzz_environment(input_corpus) + prepare_empty_corpus(input_corpus) + dictionary_path = utils.get_dictionary_path(target_binary) + command = [target_binary] + #if dictionary_path: + # command += (['-x', dictionary_path]) + command += (['-o', output_corpus, '-i', input_corpus]) + fuzzer_env = os.environ.copy() + fuzzer_env['LD_PRELOAD'] = '/usr/lib/x86_64-linux-gnu/libjemalloc.so.2' + print(command) + subprocess.check_call(command, cwd=os.environ['OUT'], env=fuzzer_env) diff --git a/fuzzers/libafl_empty_seeds/runner.Dockerfile b/fuzzers/libafl_empty_seeds/runner.Dockerfile new file mode 100644 index 000000000..f0c5eb6cc --- /dev/null +++ b/fuzzers/libafl_empty_seeds/runner.Dockerfile @@ -0,0 +1,25 @@ +# 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. + +FROM gcr.io/fuzzbench/base-image + +RUN apt install libjemalloc2 + +# 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 diff --git a/fuzzers/libfuzzer_empty_seeds/builder.Dockerfile b/fuzzers/libfuzzer_empty_seeds/builder.Dockerfile new file mode 100644 index 000000000..7fe80447e --- /dev/null +++ b/fuzzers/libfuzzer_empty_seeds/builder.Dockerfile @@ -0,0 +1,26 @@ +# 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. + +ARG parent_image +FROM $parent_image + +RUN git clone https://github.com/llvm/llvm-project.git /llvm-project && \ + cd /llvm-project && \ + git checkout 5cda4dc7b4d28fcd11307d4234c513ff779a1c6f && \ + cd compiler-rt/lib/fuzzer && \ + (for f in *.cpp; do \ + clang++ -stdlib=libc++ -fPIC -O2 -std=c++11 $f -c & \ + done && wait) && \ + ar r libFuzzer.a *.o && \ + cp libFuzzer.a /usr/lib diff --git a/fuzzers/libfuzzer_empty_seeds/fuzzer.py b/fuzzers/libfuzzer_empty_seeds/fuzzer.py new file mode 100755 index 000000000..78a1e2f8f --- /dev/null +++ b/fuzzers/libfuzzer_empty_seeds/fuzzer.py @@ -0,0 +1,102 @@ +# 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 libFuzzer fuzzer.""" + +import subprocess +import os + +from fuzzers import utils + + +def 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) + + os.environ['CC'] = 'clang' + os.environ['CXX'] = 'clang++' + os.environ['FUZZER_LIB'] = '/usr/lib/libFuzzer.a' + + utils.build_benchmark() + + +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) + + +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) + + # Enable symbolization if needed. + # Note: if the flags are like `symbolize=0:..:symbolize=1` then + # only symbolize=1 is respected. + for flag in extra_flags: + if flag.startswith('-focus_function'): + if 'ASAN_OPTIONS' in os.environ: + os.environ['ASAN_OPTIONS'] += ':symbolize=1' + else: + os.environ['ASAN_OPTIONS'] = 'symbolize=1' + if 'UBSAN_OPTIONS' in os.environ: + os.environ['UBSAN_OPTIONS'] += ':symbolize=1' + else: + os.environ['UBSAN_OPTIONS'] = 'symbolize=1' + break + + 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. + '-fork=1', + '-ignore_ooms=1', + '-ignore_timeouts=1', + '-ignore_crashes=1', + '-entropic=1', + '-keep_seed=1', + '-cross_over_uniform_dist=1', + '-entropic_scale_per_exec_time=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/libfuzzer_empty_seeds/patch.diff b/fuzzers/libfuzzer_empty_seeds/patch.diff new file mode 100644 index 000000000..a31cc301e --- /dev/null +++ b/fuzzers/libfuzzer_empty_seeds/patch.diff @@ -0,0 +1,100 @@ +diff --git a/compiler-rt/lib/fuzzer/FuzzerFork.cpp b/compiler-rt/lib/fuzzer/FuzzerFork.cpp +index 84725d2..4e1a506 100644 +--- a/compiler-rt/lib/fuzzer/FuzzerFork.cpp ++++ b/compiler-rt/lib/fuzzer/FuzzerFork.cpp +@@ -26,6 +26,8 @@ + #include + #include + #include ++#include ++#include + + namespace fuzzer { + +@@ -70,6 +72,8 @@ struct FuzzJob { + std::string SeedListPath; + std::string CFPath; + size_t JobId; ++ bool Executing = false; ++ Vector CopiedSeeds; + + int DftTimeInSeconds = 0; + +@@ -124,7 +128,6 @@ struct GlobalEnv { + Cmd.addFlag("reload", "0"); // working in an isolated dir, no reload. + Cmd.addFlag("print_final_stats", "1"); + Cmd.addFlag("print_funcs", "0"); // no need to spend time symbolizing. +- Cmd.addFlag("max_total_time", std::to_string(std::min((size_t)300, JobId))); + Cmd.addFlag("stop_file", StopFile()); + if (!DataFlowBinary.empty()) { + Cmd.addFlag("data_flow_trace", DFTDir); +@@ -133,11 +136,10 @@ struct GlobalEnv { + } + auto Job = new FuzzJob; + std::string Seeds; +- if (size_t CorpusSubsetSize = +- std::min(Files.size(), (size_t)sqrt(Files.size() + 2))) { ++ if (size_t CorpusSubsetSize = Files.size()) { + auto Time1 = std::chrono::system_clock::now(); + for (size_t i = 0; i < CorpusSubsetSize; i++) { +- auto &SF = Files[Rand->SkewTowardsLast(Files.size())]; ++ auto &SF = Files[i]; + Seeds += (Seeds.empty() ? "" : ",") + SF; + CollectDFT(SF); + } +@@ -213,11 +215,20 @@ struct GlobalEnv { + Set NewFeatures, NewCov; + CrashResistantMerge(Args, {}, MergeCandidates, &FilesToAdd, Features, + &NewFeatures, Cov, &NewCov, Job->CFPath, false); ++ RemoveFile(Job->CFPath); + for (auto &Path : FilesToAdd) { +- auto U = FileToVector(Path); +- auto NewPath = DirPlusFile(MainCorpusDir, Hash(U)); +- WriteToFile(U, NewPath); +- Files.push_back(NewPath); ++ // Only merge files that have not been merged already. ++ if (std::find(Job->CopiedSeeds.begin(), Job->CopiedSeeds.end(), Path) == Job->CopiedSeeds.end()) { ++ // NOT THREAD SAFE: Fast check whether file still exists. ++ struct stat buffer; ++ if (stat (Path.c_str(), &buffer) == 0) { ++ auto U = FileToVector(Path); ++ auto NewPath = DirPlusFile(MainCorpusDir, Hash(U)); ++ WriteToFile(U, NewPath); ++ Files.push_back(NewPath); ++ Job->CopiedSeeds.push_back(Path); ++ } ++ } + } + Features.insert(NewFeatures.begin(), NewFeatures.end()); + Cov.insert(NewCov.begin(), NewCov.end()); +@@ -271,10 +282,19 @@ struct JobQueue { + } + }; + +-void WorkerThread(JobQueue *FuzzQ, JobQueue *MergeQ) { ++void WorkerThread(GlobalEnv *Env, JobQueue *FuzzQ, JobQueue *MergeQ) { + while (auto Job = FuzzQ->Pop()) { +- // Printf("WorkerThread: job %p\n", Job); ++ Job->Executing = true; ++ int Sleep_ms = 5 * 60 * 1000; ++ std::thread([=]() { ++ std::this_thread::sleep_for(std::chrono::milliseconds(Sleep_ms / 5)); ++ while (Job->Executing) { ++ Env->RunOneMergeJob(Job); ++ std::this_thread::sleep_for(std::chrono::milliseconds(Sleep_ms)); ++ } ++ }).detach(); + Job->ExitCode = ExecuteCommand(Job->Cmd); ++ Job->Executing = false; + MergeQ->Push(Job); + } + } +@@ -335,7 +355,7 @@ void FuzzWithFork(Random &Rand, const FuzzingOptions &Options, + size_t JobId = 1; + Vector Threads; + for (int t = 0; t < NumJobs; t++) { +- Threads.push_back(std::thread(WorkerThread, &FuzzQ, &MergeQ)); ++ Threads.push_back(std::thread(WorkerThread, &Env, &FuzzQ, &MergeQ)); + FuzzQ.Push(Env.CreateNewJob(JobId++)); + } + diff --git a/fuzzers/libfuzzer_empty_seeds/runner.Dockerfile b/fuzzers/libfuzzer_empty_seeds/runner.Dockerfile new file mode 100644 index 000000000..0d6cf004e --- /dev/null +++ b/fuzzers/libfuzzer_empty_seeds/runner.Dockerfile @@ -0,0 +1,15 @@ +# 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. + +FROM gcr.io/fuzzbench/base-image From caca3f06d9396cacd8f5ff8eee856844d6a3061e Mon Sep 17 00:00:00 2001 From: Toka Date: Tue, 13 Aug 2024 15:37:25 +0200 Subject: [PATCH 02/17] dummy --- service/gcbrun_experiment.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/gcbrun_experiment.py b/service/gcbrun_experiment.py index f19ab493d..99f9eb921 100644 --- a/service/gcbrun_experiment.py +++ b/service/gcbrun_experiment.py @@ -28,7 +28,7 @@ TRIGGER_COMMAND = '/gcbrun' RUN_EXPERIMENT_COMMAND_STR = f'{TRIGGER_COMMAND} run_experiment.py ' SKIP_COMMAND_STR = f'{TRIGGER_COMMAND} skip' -# A DUMMY COMMENT +# A DuMMY COMMENT def get_comments(pull_request_number): From 546aae8d67072f73b0a7a728f2f8acdfd6508bd8 Mon Sep 17 00:00:00 2001 From: Toka Date: Tue, 13 Aug 2024 16:34:22 +0200 Subject: [PATCH 03/17] libfuzzer empty seeds --- fuzzers/libfuzzer_empty_seeds/fuzzer.py | 13 ++++++++++--- 1 file changed, 10 insertions(+), 3 deletions(-) diff --git a/fuzzers/libfuzzer_empty_seeds/fuzzer.py b/fuzzers/libfuzzer_empty_seeds/fuzzer.py index 78a1e2f8f..d08c58fc3 100755 --- a/fuzzers/libfuzzer_empty_seeds/fuzzer.py +++ b/fuzzers/libfuzzer_empty_seeds/fuzzer.py @@ -40,12 +40,19 @@ def fuzz(input_corpus, output_corpus, target_binary): run_fuzzer.""" run_fuzzer(input_corpus, output_corpus, target_binary) +def prepare_empty_corpus(input_corpus): + if os.path.exists(input_corpus): + shutil.rmtree(input_corpus) + os.makedirs(input_corpus) + with open(os.path.join(input_corpus, 'a'), 'wb') as f: + f.write(b'a') + def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None): """Run fuzzer.""" if extra_flags is None: extra_flags = [] - + prepare_empty_corpus(input_corpus) # 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') @@ -94,8 +101,8 @@ def run_fuzzer(input_corpus, output_corpus, target_binary, extra_flags=None): 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) + #if dictionary_path: + # flags.append('-dict=' + dictionary_path) command = [target_binary] + flags + [output_corpus, input_corpus] print('[run_fuzzer] Running command: ' + ' '.join(command)) From 1d291835e29f39ad30e5761a667bc94e4487fa6f Mon Sep 17 00:00:00 2001 From: Toka Date: Tue, 13 Aug 2024 16:56:57 +0200 Subject: [PATCH 04/17] shutil --- fuzzers/libfuzzer_empty_seeds/fuzzer.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzers/libfuzzer_empty_seeds/fuzzer.py b/fuzzers/libfuzzer_empty_seeds/fuzzer.py index d08c58fc3..97c0f221d 100755 --- a/fuzzers/libfuzzer_empty_seeds/fuzzer.py +++ b/fuzzers/libfuzzer_empty_seeds/fuzzer.py @@ -15,7 +15,7 @@ import subprocess import os - +import shutil from fuzzers import utils From 616cfc27fffd0aae23830dcf86c4a09d8bdcd9ec Mon Sep 17 00:00:00 2001 From: Toka Date: Mon, 19 Aug 2024 13:36:20 +0200 Subject: [PATCH 05/17] change to latest commit for the empty_seed fuzzers too --- fuzzers/libafl_empty_seeds/builder.Dockerfile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/fuzzers/libafl_empty_seeds/builder.Dockerfile b/fuzzers/libafl_empty_seeds/builder.Dockerfile index 3f726cfec..5e5f26590 100644 --- a/fuzzers/libafl_empty_seeds/builder.Dockerfile +++ b/fuzzers/libafl_empty_seeds/builder.Dockerfile @@ -44,7 +44,7 @@ RUN if which rustup; then rustup self uninstall -y; fi && \ RUN git clone https://github.com/AFLplusplus/LibAFL /libafl # Checkout a current commit -RUN cd /libafl && git pull && git checkout b4efb6151550a37f61a869acf2957a1b07894a93 || true +RUN cd /libafl && git pull && git checkout f3433767bea0cc3d7ee3b4c08be138e61d20c468 || true # Note that due a nightly bug it is currently fixed to a known version on top! # Compile libafl. From 71823ee262e3eaf5b9211a0dde176ec0467f2c1f Mon Sep 17 00:00:00 2001 From: Toka Date: Tue, 20 Aug 2024 15:30:17 +0200 Subject: [PATCH 06/17] update to latest --- fuzzers/libafl_empty_seeds/builder.Dockerfile | 12 +++------- fuzzers/libafl_empty_seeds/fuzzer.py | 22 ++++++------------- 2 files changed, 10 insertions(+), 24 deletions(-) diff --git a/fuzzers/libafl_empty_seeds/builder.Dockerfile b/fuzzers/libafl_empty_seeds/builder.Dockerfile index 5e5f26590..7fd7462a7 100644 --- a/fuzzers/libafl_empty_seeds/builder.Dockerfile +++ b/fuzzers/libafl_empty_seeds/builder.Dockerfile @@ -18,7 +18,7 @@ FROM $parent_image # Uninstall old Rust & Install the latest one. RUN if which rustup; then rustup self uninstall -y; fi && \ curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /rustup.sh && \ - sh /rustup.sh --default-toolchain nightly-2023-09-21 -y && \ + sh /rustup.sh --default-toolchain nightly-2024-08-12 -y && \ rm /rustup.sh # Install dependencies. @@ -34,12 +34,6 @@ RUN apt-get update && \ RUN wget https://gist.githubusercontent.com/tokatoka/26f4ba95991c6e33139999976332aa8e/raw/698ac2087d58ce5c7a6ad59adce58dbfdc32bd46/createAliases.sh && chmod u+x ./createAliases.sh && ./createAliases.sh -# Uninstall old Rust & Install the latest one. -RUN if which rustup; then rustup self uninstall -y; fi && \ - curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs > /rustup.sh && \ - sh /rustup.sh --default-toolchain nightly-2024-03-12 -y && \ - rm /rustup.sh - # Download libafl. RUN git clone https://github.com/AFLplusplus/LibAFL /libafl @@ -51,10 +45,10 @@ RUN cd /libafl && git pull && git checkout f3433767bea0cc3d7ee3b4c08be138e61d20c RUN cd /libafl && \ unset CFLAGS CXXFLAGS && \ export LIBAFL_EDGES_MAP_SIZE=2621440 && \ - cd ./fuzzers/fuzzbench && \ + cd ./fuzzers/fuzzbench/fuzzbench && \ PATH="/root/.cargo/bin/:$PATH" cargo build --profile release-fuzzbench --features no_link_main # Auxiliary weak references. -RUN cd /libafl/fuzzers/fuzzbench && \ +RUN cd /libafl/fuzzers/fuzzbench/fuzzbench && \ clang -c stub_rt.c && \ ar r /stub_rt.a stub_rt.o diff --git a/fuzzers/libafl_empty_seeds/fuzzer.py b/fuzzers/libafl_empty_seeds/fuzzer.py index f3b578fb5..544ec9a56 100755 --- a/fuzzers/libafl_empty_seeds/fuzzer.py +++ b/fuzzers/libafl_empty_seeds/fuzzer.py @@ -16,7 +16,7 @@ import os import subprocess -import shutil + from fuzzers import utils @@ -40,10 +40,10 @@ def prepare_fuzz_environment(input_corpus): def build(): # pylint: disable=too-many-branches,too-many-statements """Build benchmark.""" - os.environ[ - 'CC'] = '/libafl/fuzzers/fuzzbench/target/release-fuzzbench/libafl_cc' - os.environ[ - 'CXX'] = '/libafl/fuzzers/fuzzbench/target/release-fuzzbench/libafl_cxx' + os.environ['CC'] = ('/libafl/fuzzers/fuzzbench/fuzzbench' + '/target/release-fuzzbench/libafl_cc') + os.environ['CXX'] = ('/libafl/fuzzers/fuzzbench/fuzzbench' + '/target/release-fuzzbench/libafl_cxx') os.environ['ASAN_OPTIONS'] = 'abort_on_error=0:allocator_may_return_null=1' os.environ['UBSAN_OPTIONS'] = 'abort_on_error=0' @@ -57,22 +57,14 @@ def build(): # pylint: disable=too-many-branches,too-many-statements os.environ['FUZZER_LIB'] = '/stub_rt.a' utils.build_benchmark() -def prepare_empty_corpus(input_corpus): - if os.path.exists(input_corpus): - shutil.rmtree(input_corpus) - os.makedirs(input_corpus) - with open(os.path.join(input_corpus, 'a'), 'wb') as f: - f.write(b'a') - def fuzz(input_corpus, output_corpus, target_binary): """Run fuzzer.""" prepare_fuzz_environment(input_corpus) - prepare_empty_corpus(input_corpus) dictionary_path = utils.get_dictionary_path(target_binary) command = [target_binary] - #if dictionary_path: - # command += (['-x', dictionary_path]) + # if dictionary_path: + # command += (['-x', dictionary_path]) command += (['-o', output_corpus, '-i', input_corpus]) fuzzer_env = os.environ.copy() fuzzer_env['LD_PRELOAD'] = '/usr/lib/x86_64-linux-gnu/libjemalloc.so.2' From 6bae06968314892134202f78da69e84c97034baf Mon Sep 17 00:00:00 2001 From: Toka Date: Mon, 26 Aug 2024 14:57:58 +0200 Subject: [PATCH 07/17] update libafl here, too --- fuzzers/libafl/builder.Dockerfile | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/fuzzers/libafl/builder.Dockerfile b/fuzzers/libafl/builder.Dockerfile index 7fd7462a7..2b23ce321 100644 --- a/fuzzers/libafl/builder.Dockerfile +++ b/fuzzers/libafl/builder.Dockerfile @@ -38,9 +38,11 @@ RUN wget https://gist.githubusercontent.com/tokatoka/26f4ba95991c6e3313999997633 RUN git clone https://github.com/AFLplusplus/LibAFL /libafl # Checkout a current commit -RUN cd /libafl && git pull && git checkout f3433767bea0cc3d7ee3b4c08be138e61d20c468 || true +RUN cd /libafl && git pull && git checkout 683f590bbdc4a18d9ddef63c609bbae6b9376023 || true # Note that due a nightly bug it is currently fixed to a known version on top! +RUN ls /libafl/fuzzers + # Compile libafl. RUN cd /libafl && \ unset CFLAGS CXXFLAGS && \ From 0cd6c5dc14d252590e228923467d630fd3892667 Mon Sep 17 00:00:00 2001 From: Toka Date: Tue, 27 Aug 2024 17:07:57 +0200 Subject: [PATCH 08/17] forgot this --- fuzzers/libafl_empty_seeds/builder.Dockerfile | 2 +- fuzzers/libafl_empty_seeds/fuzzer.py | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/fuzzers/libafl_empty_seeds/builder.Dockerfile b/fuzzers/libafl_empty_seeds/builder.Dockerfile index 7fd7462a7..8231a2f72 100644 --- a/fuzzers/libafl_empty_seeds/builder.Dockerfile +++ b/fuzzers/libafl_empty_seeds/builder.Dockerfile @@ -38,7 +38,7 @@ RUN wget https://gist.githubusercontent.com/tokatoka/26f4ba95991c6e3313999997633 RUN git clone https://github.com/AFLplusplus/LibAFL /libafl # Checkout a current commit -RUN cd /libafl && git pull && git checkout f3433767bea0cc3d7ee3b4c08be138e61d20c468 || true +RUN cd /libafl && git pull && git checkout 683f590bbdc4a18d9ddef63c609bbae6b9376023 || true # Note that due a nightly bug it is currently fixed to a known version on top! # Compile libafl. diff --git a/fuzzers/libafl_empty_seeds/fuzzer.py b/fuzzers/libafl_empty_seeds/fuzzer.py index 544ec9a56..2b31e3d32 100755 --- a/fuzzers/libafl_empty_seeds/fuzzer.py +++ b/fuzzers/libafl_empty_seeds/fuzzer.py @@ -37,6 +37,13 @@ def prepare_fuzz_environment(input_corpus): # Create at least one non-empty seed to start. utils.create_seed_file_for_empty_corpus(input_corpus) +def prepare_empty_corpus(input_corpus): + if os.path.exists(input_corpus): + shutil.rmtree(input_corpus) + os.makedirs(input_corpus) + with open(os.path.join(input_corpus, 'a'), 'wb') as f: + f.write(b'a') + def build(): # pylint: disable=too-many-branches,too-many-statements """Build benchmark.""" @@ -61,6 +68,7 @@ def build(): # pylint: disable=too-many-branches,too-many-statements def fuzz(input_corpus, output_corpus, target_binary): """Run fuzzer.""" prepare_fuzz_environment(input_corpus) + prepare_empty_corpus(input_corpus) dictionary_path = utils.get_dictionary_path(target_binary) command = [target_binary] # if dictionary_path: From 0ef9a84493981a9d813c5e59f34b890d5eec6950 Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Wed, 28 Aug 2024 03:53:21 +0200 Subject: [PATCH 09/17] commit hash --- fuzzers/libafl/builder.Dockerfile | 2 +- fuzzers/libafl_empty_seeds/builder.Dockerfile | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/fuzzers/libafl/builder.Dockerfile b/fuzzers/libafl/builder.Dockerfile index 2b23ce321..076232936 100644 --- a/fuzzers/libafl/builder.Dockerfile +++ b/fuzzers/libafl/builder.Dockerfile @@ -38,7 +38,7 @@ RUN wget https://gist.githubusercontent.com/tokatoka/26f4ba95991c6e3313999997633 RUN git clone https://github.com/AFLplusplus/LibAFL /libafl # Checkout a current commit -RUN cd /libafl && git pull && git checkout 683f590bbdc4a18d9ddef63c609bbae6b9376023 || true +RUN cd /libafl && git pull && git checkout f856092f3d393056b010fcae3b086769377cba18 || true # Note that due a nightly bug it is currently fixed to a known version on top! RUN ls /libafl/fuzzers diff --git a/fuzzers/libafl_empty_seeds/builder.Dockerfile b/fuzzers/libafl_empty_seeds/builder.Dockerfile index 8231a2f72..f0136ff46 100644 --- a/fuzzers/libafl_empty_seeds/builder.Dockerfile +++ b/fuzzers/libafl_empty_seeds/builder.Dockerfile @@ -38,7 +38,7 @@ RUN wget https://gist.githubusercontent.com/tokatoka/26f4ba95991c6e3313999997633 RUN git clone https://github.com/AFLplusplus/LibAFL /libafl # Checkout a current commit -RUN cd /libafl && git pull && git checkout 683f590bbdc4a18d9ddef63c609bbae6b9376023 || true +RUN cd /libafl && git pull && git checkout f856092f3d393056b010fcae3b086769377cba18 || true # Note that due a nightly bug it is currently fixed to a known version on top! # Compile libafl. From 2d4de27fd11d11b8dc46a2be6e8f1f38057e2197 Mon Sep 17 00:00:00 2001 From: Dongge Liu Date: Fri, 23 Aug 2024 11:27:46 +1000 Subject: [PATCH 10/17] More informative logs to help debugging --- common/fuzzer_utils.py | 4 ++++ experiment/measurer/coverage_utils.py | 4 +++- experiment/runner.py | 3 ++- 3 files changed, 9 insertions(+), 2 deletions(-) diff --git a/common/fuzzer_utils.py b/common/fuzzer_utils.py index 049ba8ce3..a28acf5db 100644 --- a/common/fuzzer_utils.py +++ b/common/fuzzer_utils.py @@ -83,7 +83,11 @@ def get_fuzz_target_binary(search_directory: str, if os.path.exists(default_fuzz_target_binary): return default_fuzz_target_binary + logs.info('Searching for possible fuzz target in search directory: ' + f'{search_directory}') for root, _, files in os.walk(search_directory): + logs.info(f'Searching for possible fuzz target under subdir {root}: ' + f'{files}') if root == 'uninstrumented': continue for filename in files: diff --git a/experiment/measurer/coverage_utils.py b/experiment/measurer/coverage_utils.py index 27ab69965..9f8e295c9 100644 --- a/experiment/measurer/coverage_utils.py +++ b/experiment/measurer/coverage_utils.py @@ -133,7 +133,9 @@ def merge_profdata_files(self): result = merge_profdata_files(files_to_merge, self.merged_profdata_file) if result.retcode != 0: - logger.error('Profdata files merging failed.') + logger.error( + f'Profdata files merging failed for (fuzzer, benchmark): ' + f'({self.fuzzer}, {self.benchmark}).') def generate_coverage_summary_json(self): """Generates the coverage summary json from merged profdata file.""" diff --git a/experiment/runner.py b/experiment/runner.py index b8c95fcca..6715c51e0 100644 --- a/experiment/runner.py +++ b/experiment/runner.py @@ -180,7 +180,8 @@ def run_fuzzer(max_total_time, log_filename): target_binary = fuzzer_utils.get_fuzz_target_binary(FUZZ_TARGET_DIR, fuzz_target_name) if not target_binary: - logs.error('Fuzz target binary not found.') + logs.error(f'Fuzz target binary {fuzz_target_name} not found under ' + f'{FUZZ_TARGET_DIR}') return if max_total_time is None: From 1dc03f15ec53ef0420931e99ecf0c2c0fb3561a7 Mon Sep 17 00:00:00 2001 From: Dongge Liu Date: Sun, 25 Aug 2024 09:34:23 +1000 Subject: [PATCH 11/17] More logs for cloud build --- experiment/build/gcb_build.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/experiment/build/gcb_build.py b/experiment/build/gcb_build.py index f553848c7..8030f23dd 100644 --- a/experiment/build/gcb_build.py +++ b/experiment/build/gcb_build.py @@ -105,7 +105,8 @@ def _build( # TODO(metzman): Refactor code so that local_build stores logs as well. build_utils.store_build_logs(config_name, result) if result.retcode != 0: - logs.error('%s failed.', command) + logs.error('%s failed. Return code: %d. Output: %s. Timedout: %s', + command, result.retcode, result.output, result.timed_out) raise subprocess.CalledProcessError(result.retcode, command) return result From b6f2693db2750c0ec03a2308f7394a1f7d4c37d2 Mon Sep 17 00:00:00 2001 From: Dongge Liu Date: Sun, 25 Aug 2024 09:47:21 +1000 Subject: [PATCH 12/17] More logs to help debug no binary --- common/fuzzer_utils.py | 6 ++++++ experiment/runner.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/common/fuzzer_utils.py b/common/fuzzer_utils.py index a28acf5db..b47e2860f 100644 --- a/common/fuzzer_utils.py +++ b/common/fuzzer_utils.py @@ -72,6 +72,12 @@ def dockerfiles(self): def get_fuzz_target_binary(search_directory: str, fuzz_target_name: str) -> Optional[str]: """Return target binary path.""" + logs.info(f'Searching for fuzz target binary named {fuzz_target_name} under' + f' directory {search_directory}') + logs.info(f'Search diretory {os.path.abspath(search_directory)} exists: ' + f'{os.path.exists(os.path.abspath(search_directory))}') + logs.info(f'list Search diretory {search_directory}: ' + f'{os.listdir(search_directory)}') if fuzz_target_name: fuzz_target_binary = os.path.join(search_directory, fuzz_target_name) if os.path.exists(fuzz_target_binary): diff --git a/experiment/runner.py b/experiment/runner.py index 6715c51e0..776a4656e 100644 --- a/experiment/runner.py +++ b/experiment/runner.py @@ -177,6 +177,8 @@ def run_fuzzer(max_total_time, log_filename): input_corpus = environment.get('SEED_CORPUS_DIR') output_corpus = os.environ['OUTPUT_CORPUS_DIR'] fuzz_target_name = environment.get('FUZZ_TARGET') + logs.info('all ENV VAR ' + f'{[f"{key}: {value}" for key, value in os.environ.items()]}') target_binary = fuzzer_utils.get_fuzz_target_binary(FUZZ_TARGET_DIR, fuzz_target_name) if not target_binary: From 72f5aeb69bac2a3683859b2a5a204c5241dd73d8 Mon Sep 17 00:00:00 2001 From: Dongge Liu Date: Sun, 25 Aug 2024 09:48:07 +1000 Subject: [PATCH 13/17] Trigger gcb exp --- service/gcbrun_experiment.py | 1 + 1 file changed, 1 insertion(+) diff --git a/service/gcbrun_experiment.py b/service/gcbrun_experiment.py index 99f9eb921..41f48d77c 100644 --- a/service/gcbrun_experiment.py +++ b/service/gcbrun_experiment.py @@ -20,6 +20,7 @@ import logging import os import sys +# dummy # pytype: disable=import-error import github # pylint: disable=import-error From a874e206b3309a6307b34519ff2c38230190203a Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Thu, 29 Aug 2024 23:50:33 +0200 Subject: [PATCH 14/17] Fix and format for debug branch #2040 (#2041) --- fuzzers/afl_empty_seeds/fuzzer.py | 1 + fuzzers/aflplusplus_empty_seeds/fuzzer.py | 1 + fuzzers/honggfuzz_empty_seeds/fuzzer.py | 1 + fuzzers/libafl_empty_seeds/fuzzer.py | 2 ++ fuzzers/libfuzzer_empty_seeds/fuzzer.py | 1 + 5 files changed, 6 insertions(+) diff --git a/fuzzers/afl_empty_seeds/fuzzer.py b/fuzzers/afl_empty_seeds/fuzzer.py index c0d8956eb..a0c00a185 100755 --- a/fuzzers/afl_empty_seeds/fuzzer.py +++ b/fuzzers/afl_empty_seeds/fuzzer.py @@ -92,6 +92,7 @@ def check_skip_det_compatible(additional_flags): return False return True + def prepare_empty_corpus(input_corpus): if os.path.exists(input_corpus): shutil.rmtree(input_corpus) diff --git a/fuzzers/aflplusplus_empty_seeds/fuzzer.py b/fuzzers/aflplusplus_empty_seeds/fuzzer.py index 295d4c8f4..1d7c371de 100755 --- a/fuzzers/aflplusplus_empty_seeds/fuzzer.py +++ b/fuzzers/aflplusplus_empty_seeds/fuzzer.py @@ -234,6 +234,7 @@ def build(*args): # pylint: disable=too-many-branches,too-many-statements shutil.copy('/afl/afl-frida-trace.so', build_directory) shutil.copy('/get_frida_entry.sh', build_directory) + def prepare_empty_corpus(input_corpus): if os.path.exists(input_corpus): shutil.rmtree(input_corpus) diff --git a/fuzzers/honggfuzz_empty_seeds/fuzzer.py b/fuzzers/honggfuzz_empty_seeds/fuzzer.py index 642e8d1e0..07101bce0 100644 --- a/fuzzers/honggfuzz_empty_seeds/fuzzer.py +++ b/fuzzers/honggfuzz_empty_seeds/fuzzer.py @@ -42,6 +42,7 @@ def prepare_empty_corpus(input_corpus): with open(os.path.join(input_corpus, 'a'), 'wb') as f: f.write(b'a') + def fuzz(input_corpus, output_corpus, target_binary): """Run fuzzer.""" diff --git a/fuzzers/libafl_empty_seeds/fuzzer.py b/fuzzers/libafl_empty_seeds/fuzzer.py index 2b31e3d32..a0153f385 100755 --- a/fuzzers/libafl_empty_seeds/fuzzer.py +++ b/fuzzers/libafl_empty_seeds/fuzzer.py @@ -16,6 +16,7 @@ import os import subprocess +import shutil from fuzzers import utils @@ -37,6 +38,7 @@ def prepare_fuzz_environment(input_corpus): # Create at least one non-empty seed to start. utils.create_seed_file_for_empty_corpus(input_corpus) + def prepare_empty_corpus(input_corpus): if os.path.exists(input_corpus): shutil.rmtree(input_corpus) diff --git a/fuzzers/libfuzzer_empty_seeds/fuzzer.py b/fuzzers/libfuzzer_empty_seeds/fuzzer.py index 97c0f221d..bd3a233b8 100755 --- a/fuzzers/libfuzzer_empty_seeds/fuzzer.py +++ b/fuzzers/libfuzzer_empty_seeds/fuzzer.py @@ -40,6 +40,7 @@ def fuzz(input_corpus, output_corpus, target_binary): run_fuzzer.""" run_fuzzer(input_corpus, output_corpus, target_binary) + def prepare_empty_corpus(input_corpus): if os.path.exists(input_corpus): shutil.rmtree(input_corpus) From b926a58edacb80452072bbaead50b8f25abc6c43 Mon Sep 17 00:00:00 2001 From: Dongge Liu Date: Tue, 3 Sep 2024 15:26:53 +1000 Subject: [PATCH 15/17] More logs about profraw/profdata --- experiment/measurer/coverage_utils.py | 4 ++++ experiment/measurer/measure_manager.py | 11 +++++++++++ 2 files changed, 15 insertions(+) diff --git a/experiment/measurer/coverage_utils.py b/experiment/measurer/coverage_utils.py index 9f8e295c9..90abc172b 100644 --- a/experiment/measurer/coverage_utils.py +++ b/experiment/measurer/coverage_utils.py @@ -226,6 +226,10 @@ def get_trial_ids(experiment: str, fuzzer: str, benchmark: str): def merge_profdata_files(src_files, dst_file): """Uses llvm-profdata to merge |src_files| to |dst_files|.""" + if src_files: + logger.info('llvm-profdata src files are: %s', src_files) + else: + logger.error('llvm-profdata has no src files: %s', src_files) command = ['llvm-profdata', 'merge', '-sparse'] command.extend(src_files) command.extend(['-o', dst_file]) diff --git a/experiment/measurer/measure_manager.py b/experiment/measurer/measure_manager.py index 288148401..f22608472 100644 --- a/experiment/measurer/measure_manager.py +++ b/experiment/measurer/measure_manager.py @@ -436,11 +436,22 @@ def get_current_coverage(self) -> int: def generate_profdata(self, cycle: int): """Generate .profdata file from .profraw file.""" + self.logger.info('Listing all files under %s to find profraw files: %s', + self.coverage_dir, os.listdir(self.coverage_dir)) + candiates = { + f: os.path.getsize(f) + for f in glob.glob(self.profraw_file_pattern.replace('%m', '*')) + } + self.logger.info('Candidate profraw files are: %s', candiates) files_to_merge = self.get_profraw_files() if os.path.isfile(self.profdata_file): # If coverage profdata exists, then merge it with # existing available data. files_to_merge += [self.profdata_file] + self.logger.info('profdata_file does exist: %s', self.profdata_file) + else: + self.logger.warning('profdata_file does not exist: %s', + self.profdata_file) result = coverage_utils.merge_profdata_files(files_to_merge, self.profdata_file) From 2f990079d93bde9de66914778007c8987f855d65 Mon Sep 17 00:00:00 2001 From: Dongge Liu Date: Tue, 3 Sep 2024 15:27:11 +1000 Subject: [PATCH 16/17] No merge result --- service/experiment-config.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/service/experiment-config.yaml b/service/experiment-config.yaml index b9acb09f8..53885721b 100644 --- a/service/experiment-config.yaml +++ b/service/experiment-config.yaml @@ -15,7 +15,7 @@ preemptible_runners: true # This experiment should generate a report that is combined with other public # "production" experiments. -merge_with_nonprivate: true +merge_with_nonprivate: false # This experiment should be merged with other reports in later experiments. private: false From e6b60d5ae64d06901e9b91dc7eb624d029cc61ab Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Tue, 3 Sep 2024 14:26:52 +0200 Subject: [PATCH 17/17] Debug 2040 (#2042) Just to check if profraw is generated in coverage_run() --- experiment/measurer/run_coverage.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/experiment/measurer/run_coverage.py b/experiment/measurer/run_coverage.py index 05fb2a1c0..14fd8fc22 100644 --- a/experiment/measurer/run_coverage.py +++ b/experiment/measurer/run_coverage.py @@ -44,6 +44,7 @@ def do_coverage_run( # pylint: disable=too-many-locals """Does a coverage run of |coverage_binary| on |new_units_dir|. Writes the result to |profraw_file_pattern|.""" with tempfile.TemporaryDirectory() as merge_dir: + logger.info("coverage binary exists?: %s", os.path.exists(os.path.abspath(coverage_binary))) command = [ coverage_binary, '-merge=1', '-dump_coverage=1', f'-artifact_prefix={crashes_dir}/', f'-timeout={UNIT_TIMEOUT}', @@ -61,6 +62,8 @@ def do_coverage_run( # pylint: disable=too-many-locals expect_zero=False, kill_children=True, timeout=MAX_TOTAL_TIME) + + logger.info("coverage dir after coverage run %s", os.listdir(coverage_binary_dir)) if result.retcode != 0: logger.error('Coverage run failed.',