diff --git a/fuzzers/aflplusplus_muttfuzz/builder.Dockerfile b/fuzzers/aflplusplus_muttfuzz/builder.Dockerfile new file mode 100644 index 000000000..fa2b3813e --- /dev/null +++ b/fuzzers/aflplusplus_muttfuzz/builder.Dockerfile @@ -0,0 +1,54 @@ +# 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 27d05f3c216e18163236efa42b630a5b3784d2e9 || \ + 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 / + +RUN apt-get update && apt-get install -y python3 + +RUN pip3 install --upgrade --force pip +RUN pip install muttfuzz \ No newline at end of file diff --git a/fuzzers/aflplusplus_muttfuzz/fuzzer.py b/fuzzers/aflplusplus_muttfuzz/fuzzer.py new file mode 100644 index 000000000..7999d34d7 --- /dev/null +++ b/fuzzers/aflplusplus_muttfuzz/fuzzer.py @@ -0,0 +1,74 @@ +# 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.""" + +# This optimized afl++ variant should always be run together with +# "aflplusplus" to show the difference - a default configured afl++ vs. +# a hand-crafted optimized one. afl++ is configured not to enable the good +# stuff by default to be as close to vanilla afl as possible. +# But this means that the good stuff is hidden away in this benchmark +# otherwise. + +import os + +from fuzzers.aflplusplus import fuzzer as aflplusplus_fuzzer +from fuzzers.aflplusplus_muttfuzz import fuzzutil + + +def build(): # pylint: disable=too-many-branches,too-many-statements + """Build benchmark.""" + aflplusplus_fuzzer.build() + + +def restore_out(input_corpus, output_corpus, crashes_storage): + """Restores output dir and copies crashes after mutant is done running""" + # os.system(f"rm -rf {input_corpus}/*") + # os.system( + # f"cp {output_corpus}/default/crashes/crashes.*/id* {crashes_storage}/") + # os.system( + # f"cp {output_corpus}/default/crashes/crashes.*/id* {input_corpus}/") + # os.system(f"cp {output_corpus}/default/queue/* {input_corpus}/") + # os.system(f"rm -rf {output_corpus}/*") + pass + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run fuzzer.""" + os.environ["AFL_SKIP_CRASHES"] = "1" + os.environ["AFL_AUTORESUME"] = "1" + print(f"{input_corpus} {output_corpus} {target_binary}") + + crashes_storage = "/storage" + os.makedirs(crashes_storage, exist_ok=True) + + aflplusplus_fuzz_fn = lambda: aflplusplus_fuzzer.fuzz( + input_corpus, output_corpus, target_binary) + + budget = 86_400 + fraction_mutant = 0.5 + time_per_mutant = 300 + initial_budget = 1_800 + post_mutant_fn = lambda: restore_out(input_corpus, output_corpus, + crashes_storage) + fuzzutil.fuzz_with_mutants_via_function( + aflplusplus_fuzz_fn, + target_binary, + budget, + time_per_mutant, + fraction_mutant, + initial_fn=aflplusplus_fuzz_fn, + initial_budget=initial_budget, + post_initial_fn=post_mutant_fn, + post_mutant_fn=post_mutant_fn, + ) diff --git a/fuzzers/aflplusplus_muttfuzz/fuzzutil.py b/fuzzers/aflplusplus_muttfuzz/fuzzutil.py new file mode 100644 index 000000000..dca0daa1d --- /dev/null +++ b/fuzzers/aflplusplus_muttfuzz/fuzzutil.py @@ -0,0 +1,274 @@ +# 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. +"""Utilities for running muttfuzz""" +import os +import signal +import subprocess +import time +from contextlib import contextmanager +from datetime import datetime + +from fuzzers.aflplusplus_muttfuzz import mutate + + +class TimeoutException(Exception): + """ "Exception thrown when timeouts occur""" + + +@contextmanager +def time_limit(seconds): + """Method to define a time limit before throwing exception""" + + def signal_handler(signum, frame): + raise TimeoutException("Timed out!") + + signal.signal(signal.SIGALRM, signal_handler) + signal.alarm(seconds) + try: + yield + finally: + signal.alarm(0) + + +def restore_executable(executable, executable_code): + """Method to restore the original executable""" + # We do this because it could still be busy if fuzzer hasn't shut down yet + with open("/tmp/new_executable", "wb") as f_name: + f_name.write(executable_code) + os.rename("/tmp/new_executable", executable) + subprocess.check_call(["chmod", "+x", executable]) + + +def silent_run_with_timeout(cmd, timeout): + """Method to run command silently with timeout""" + dnull = open(os.devnull, "w") + start_p = time.time() + process = None + try: + with open("cmd_errors.txt", "w") as cmd_errors: + process = subprocess.Popen( # pylint: disable=subprocess-popen-preexec-fn + cmd, + shell=True, + preexec_fn=os.setsid, + stdout=dnull, + stderr=cmd_errors, + ) + while (process.poll() is None) and ( + (time.time() - start_p) < timeout): + time.sleep(0.5) + if process.poll() is None: + os.killpg(os.getpgid(process.pid), signal.SIGTERM) + with open("cmd_errors.txt", "r") as cmd_errors: + cmd_errors_out = cmd_errors.read() + if len(cmd_errors_out) > 0: + print("ERRORS:") + print(cmd_errors_out) + finally: + if process is not None: + if process.poll() is None: + os.killpg(os.getpgid(process.pid), signal.SIGTERM) + + +def fuzz_with_mutants( # pylint: disable=too-many-locals,too-many-arguments + fuzzer_cmd, + executable, + budget, + time_per_mutant, + fraction_mutant, + initial_fuzz_cmd="", + initial_budget=0, + post_initial_cmd="", + post_mutant_cmd="", + status_cmd="", + order=1, +): + """Function to fuzz mutants from commands""" + executable_code = mutate.get_code(executable) + executable_jumps = mutate.get_jumps(executable) + start_fuzz = time.time() + mutant_no = 1 + try: + if initial_fuzz_cmd != "": + print( + "=" * 10, + datetime.utcfromtimestamp( + time.time()).strftime("%Y-%m-%d %H:%M:%S"), + "=" * 10, + ) + print("RUNNING INITIAL FUZZING...") + silent_run_with_timeout(initial_fuzz_cmd, initial_budget) + if status_cmd != "": + print("INITIAL STATUS:") + subprocess.call(status_cmd, shell=True) + if post_initial_cmd != "": + subprocess.call(post_initial_cmd, shell=True) + + while ((time.time() - start_fuzz) - initial_budget) < (budget * + fraction_mutant): + print( + "=" * 10, + datetime.utcfromtimestamp( + time.time()).strftime("%Y-%m-%d %H:%M:%S"), + "=" * 10, + ) + print( + round(time.time() - start_fuzz, 2), + "ELAPSED: GENERATING MUTANT #" + str(mutant_no), + ) + mutant_no += 1 + # make a new mutant of the executable; rename + # avoids hitting a busy executable + mutate.mutate_from( + executable_code, + executable_jumps, + "/tmp/new_executable", + order=order, + ) + os.rename("/tmp/new_executable", executable) + subprocess.check_call(["chmod", "+x", executable]) + print("FUZZING MUTANT...") + start_run = time.time() + silent_run_with_timeout(fuzzer_cmd, time_per_mutant) + print( + "FINISHED FUZZING IN", + round(time.time() - start_run, 2), + "SECONDS", + ) + if post_mutant_cmd != "": + subprocess.call(post_mutant_cmd, shell=True) + if status_cmd != "": + print("STATUS:") + subprocess.call(status_cmd, shell=True) + + print( + datetime.utcfromtimestamp( + time.time()).strftime("%Y-%m-%d %H:%M:%S")) + print(round(time.time() - start_fuzz, 2), + "ELAPSED: STARTING FINAL FUZZ") + restore_executable(executable, executable_code) + silent_run_with_timeout(fuzzer_cmd, budget - (time.time() - start_fuzz)) + print( + "COMPLETED ALL FUZZING AFTER", + round(time.time() - start_fuzz, 2), + "SECONDS", + ) + if status_cmd != "": + print("FINAL STATUS:") + subprocess.call(status_cmd, shell=True) + finally: + # always restore the original binary! + restore_executable(executable, executable_code) + + +def fuzz_with_mutants_via_function( # pylint: disable=too-many-locals,too-many-statements,too-many-arguments + fuzzer_fn, + executable, + budget, + time_per_mutant, + fraction_mutant, + initial_fn=None, + initial_budget=0, + post_initial_fn=None, + post_mutant_fn=None, + status_fn=None, + order=1, +): + """Fuzz mutants from initial and post mutant functions""" + executable_code = mutate.get_code(executable) + executable_jumps = mutate.get_jumps(executable) + start_fuzz = time.time() + mutant_no = 1 + try: + if initial_fn is not None: + print( + "=" * 10, + datetime.utcfromtimestamp( + time.time()).strftime("%Y-%m-%d %H:%M:%S"), + "=" * 10, + ) + print("RUNNING INITIAL FUZZING...") + try: + with time_limit(initial_budget): + initial_fn() + except TimeoutException: + pass + if status_fn is not None: + print("INITIAL STATUS:") + status_fn() + if post_initial_fn is not None: + post_initial_fn() + + while ((time.time() - start_fuzz) - initial_budget) < (budget * + fraction_mutant): + print( + "=" * 10, + datetime.utcfromtimestamp( + time.time()).strftime("%Y-%m-%d %H:%M:%S"), + "=" * 10, + ) + print( + round(time.time() - start_fuzz, 2), + "ELAPSED: GENERATING MUTANT #" + str(mutant_no), + ) + mutant_no += 1 + # make a new mutant of the executable; rename avoids + # hitting a busy executable + mutate.mutate_from( + executable_code, + executable_jumps, + "/tmp/new_executable", + order=order, + ) + os.rename("/tmp/new_executable", executable) + subprocess.check_call(["chmod", "+x", executable]) + print("FUZZING MUTANT...") + start_run = time.time() + try: + with time_limit(time_per_mutant): + fuzzer_fn() + except TimeoutException: + pass + print( + "FINISHED FUZZING IN", + round(time.time() - start_run, 2), + "SECONDS", + ) + if post_mutant_fn is not None: + post_mutant_fn() + if status_fn is not None: + print("STATUS:") + status_fn() + + print( + datetime.utcfromtimestamp( + time.time()).strftime("%Y-%m-%d %H:%M:%S")) + print(round(time.time() - start_fuzz, 2), + "ELAPSED: STARTING FINAL FUZZ") + restore_executable(executable, executable_code) + try: + with time_limit(int(budget - (time.time() - start_fuzz))): + fuzzer_fn() + except TimeoutException: + pass + print( + "COMPLETED ALL FUZZING AFTER", + round(time.time() - start_fuzz, 2), + "SECONDS", + ) + if status_fn is not None: + print("FINAL STATUS:") + status_fn() + finally: + # always restore the original binary! + restore_executable(executable, executable_code) diff --git a/fuzzers/aflplusplus_muttfuzz/mutate.py b/fuzzers/aflplusplus_muttfuzz/mutate.py new file mode 100644 index 000000000..e5e388a90 --- /dev/null +++ b/fuzzers/aflplusplus_muttfuzz/mutate.py @@ -0,0 +1,130 @@ +# 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. +"""Module to apply mutants at bytecode level""" +import random +import subprocess + +JUMP_OPCODES = ["je", "jne", "jl", "jle", "jg", "jge"] +SHORT_JUMPS = list( + map(bytes.fromhex, ["74", "75", "7C", "7D", "7E", "7F", "EB"])) +# no unconditional for near jumps, since changes opcode length, not worth it +NEAR_JUMPS = list( + map( + bytes.fromhex, + ["0F 84", "0F 85", "0F 8C", "0F 8D", "0F 8E", "0F 8F", "90 E9"], + )) + +# known markers for fuzzer/compiler injected instrumentation/etc. +INST_SET = ["__afl", "__asan", "__ubsan", "__sanitizer", "__lsan", "__sancov"] + + +def get_jumps(filename): # pylint: disable=too-many-locals + """Method to get all jumps in file""" + jumps = {} + + proc = subprocess.Popen( + ["objdump", "-d", "--file-offsets", filename], + stdout=subprocess.PIPE, + stderr=subprocess.PIPE, + ) + out, _ = proc.communicate() + output = str(out, encoding="utf-8") + + for line in output.split("\n"): + try: + if "File Offset" in line and line[-1] == ":": + section_base = int(line.split()[0], 16) + offset_hex = line.split("File Offset:")[1].split(")")[0] + section_offset = int(offset_hex, 16) - section_base + continue + found_inst = False + for i in INST_SET: + if i in line: + found_inst = True + break + if found_inst: + continue # Don't mutate these things + fields = line.split("\t") + if len(fields) > 1: + opcode = fields[2].split()[0] + if opcode in JUMP_OPCODES: + loc_bytes = fields[0].split(":")[0] + loc = int(loc_bytes, 16) + section_offset + jumps[loc] = (opcode, bytes.fromhex(fields[1])) + # pylint: disable=bare-except + except: # If we can't parse some line in the objdump, just skip it + pass + + return jumps + + +def different_jump(hexdata): + """Method to select a different jump""" + # NEAR JUMP BYTE CHECK + if hexdata[0] == 15: # pylint: disable=no-else-return + # Have a high chance of just changing near JE and JNE to a + # forced JMP, "removing" a branch + if ((hexdata[1] == NEAR_JUMPS[0][1]) or + (hexdata[1] == NEAR_JUMPS[1][1])) and (random.random() <= 0.75): + return NEAR_JUMPS[-1] + return random.choice( + list(filter(lambda j: j[1] != hexdata[1], NEAR_JUMPS))) + else: + # Have a high chance of just changing short JE and + # JNE to a forced JMP, "removing" a branch + if ((hexdata[0] == SHORT_JUMPS[0][0]) or + (hexdata[0] == SHORT_JUMPS[1][0])) and (random.random() <= 0.75): + return SHORT_JUMPS[-1] + return random.choice( + list(filter(lambda j: j[0] != hexdata[0], SHORT_JUMPS))) + + +def pick_and_change(jumps): + """Randomly change jumps""" + loc = random.choice(list(jumps.keys())) + return (loc, different_jump(jumps[loc][1])) + + +def get_code(filename): + """Read code as array of bytes""" + with open(filename, "rb") as f_name: + return bytearray(f_name.read()) + + +def mutant_from(code, jumps, order=1): + """Get new code from code and jumps""" + new_code = bytearray(code) + for _ in range( + order): # allows higher-order mutants, though can undo mutations + (loc, new_data) = pick_and_change(jumps) + for offset in range(0, len(new_data)): # pylint: disable=consider-using-enumerate + new_code[loc + offset] = new_data[offset] + return new_code + + +def mutant(filename, order=1): + """Write mutant to file""" + return mutant_from(get_code(filename), get_jumps(filename), order=order) + + +def mutate_from(code, jumps, new_filename, order=1): + """Wrap mutant_from wth order to write to new_filename""" + with open(new_filename, "wb") as f_name: + f_name.write(mutant_from(code, jumps, order=order)) + + +def mutate(filename, new_filename, order=1): + """Write mutant to new file""" + with open(new_filename, "wb") as f_name: + f_name.write(mutant(filename, order=order)) diff --git a/fuzzers/aflplusplus_muttfuzz/runner.Dockerfile b/fuzzers/aflplusplus_muttfuzz/runner.Dockerfile new file mode 100644 index 000000000..21504f934 --- /dev/null +++ b/fuzzers/aflplusplus_muttfuzz/runner.Dockerfile @@ -0,0 +1,29 @@ +# 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 install -y unzip git gdb joe + +RUN apt-get update && apt-get install -y python3 + +RUN pip3 install --upgrade --force pip +RUN pip install muttfuzz \ No newline at end of file diff --git a/fuzzers/aflsmart_muttfuzz/README.md b/fuzzers/aflsmart_muttfuzz/README.md new file mode 100644 index 000000000..df780998f --- /dev/null +++ b/fuzzers/aflsmart_muttfuzz/README.md @@ -0,0 +1,18 @@ +# Supported benchmarks + +[AFLSmart](https://github.com/aflsmart/aflsmart) is a structure-aware greybox-fuzzer and it is designed to work best for programs taking chunk-based file formats (e.g., JPEG, PNG and many others) as inputs. To fully enable its structure-aware mode, AFLSmart requires input models (e.g., grammar). So if you evaluate AFLSmart on FuzzBench, please focus on the results for the following benchmarks. We keep trying to include more input models so that more benchmarks will be supported. + +1. libpng-1.2.56 + +2. libjpeg-turbo-07-2017 + +3. libpcap_fuzz_both + +4. freetype2-2017 + +5. vorbis-2017-12-11 + +6. bloaty_fuzz_target + +Since the experiment summary diagram of the default FuzzBench report is automatically generated based on the results of all benchmarks, many of them have not been supported by AFLSmart, the ranking of AFLSmart in that diagram may not be correct. + diff --git a/fuzzers/aflsmart_muttfuzz/builder.Dockerfile b/fuzzers/aflsmart_muttfuzz/builder.Dockerfile new file mode 100644 index 000000000..a9f56fed3 --- /dev/null +++ b/fuzzers/aflsmart_muttfuzz/builder.Dockerfile @@ -0,0 +1,75 @@ +# 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 + +# Install gcc-4.4 & g++-4.4 required by Peach while running on Ubuntu 16.04. +# Install Python2 and Pip2 required by AFLSmart on Ubuntu:20.04. +RUN echo 'deb http://dk.archive.ubuntu.com/ubuntu/ trusty main' >> \ + /etc/apt/sources.list && \ + echo 'deb http://dk.archive.ubuntu.com/ubuntu/ trusty universe' >> \ + /etc/apt/sources.list && \ + apt-get update && \ + apt-get install -y \ + gcc-4.4 \ + g++-4.4 \ + unzip \ + wget \ + tzdata \ + python2 && \ + curl https://bootstrap.pypa.io/pip/2.7/get-pip.py --output get-pip.py && \ + python2 get-pip.py && \ + rm /usr/bin/python && \ + ln -s /usr/bin/python2.7 /usr/bin/python + +# Install AFLSmart dependencies. +RUN dpkg --add-architecture i386 && \ + apt-get update && \ + apt-get install -y \ + apt-utils \ + libc6-dev-i386 \ + g++-multilib \ + mono-complete \ + software-properties-common + +# Download and compile AFLSmart. +RUN git clone https://github.com/aflsmart/aflsmart /afl && \ + cd /afl && \ + git checkout 4286ae47e0e5d8c412f91aae94ef9d11fb97dfd8 && \ + AFL_NO_X86=1 make + +# Setup Peach. +# Set CFLAGS="" so that we don't use the CFLAGS defined in OSS-Fuzz images. +# Use a copy of +# https://sourceforge.net/projects/peachfuzz/files/Peach/3.0/peach-3.0.202-source.zip +# to avoid network flakiness. +RUN cd /afl && \ + wget https://storage.googleapis.com/fuzzbench-files/peach-3.0.202-source.zip && \ + unzip peach-3.0.202-source.zip && \ + patch -p1 < peach-3.0.202.patch && \ + cd peach-3.0.202-source && \ + CC=gcc-4.4 CXX=g++-4.4 CFLAGS="" CXXFLAGS="-std=c++0x" ./waf configure && \ + CC=gcc-4.4 CXX=g++-4.4 CFLAGS="" CXXFLAGS="-std=c++0x" ./waf install + +# Use afl_driver.cpp from LLVM as our fuzzing library. +RUN 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 + +RUN apt-get update && apt-get install -y python3 + +RUN pip3 install --upgrade --force pip +RUN pip install muttfuzz \ No newline at end of file diff --git a/fuzzers/aflsmart_muttfuzz/fuzzer.py b/fuzzers/aflsmart_muttfuzz/fuzzer.py new file mode 100755 index 000000000..88ad49327 --- /dev/null +++ b/fuzzers/aflsmart_muttfuzz/fuzzer.py @@ -0,0 +1,69 @@ +# 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 AFLSmart fuzzer.""" + +import glob +import os +import shutil + +from fuzzers.aflplusplus_muttfuzz import fuzzutil +from fuzzers.aflsmart import fuzzer as aflsmart_fuzzer + + +def build(): + """Build benchmark.""" + aflsmart_fuzzer.build() + + +def restore_out(input_corpus, output_corpus, crashes_storage): + """Restores output dir and copies crashes after mutant is done running""" + # os.system(f"rm -rf {input_corpus}/*") + # os.system( + # f"cp {output_corpus}/default/crashes/crashes.*/id* {crashes_storage}/") + # os.system( + # f"cp {output_corpus}/default/crashes/crashes.*/id* {input_corpus}/") + # os.system(f"cp {output_corpus}/default/queue/* {input_corpus}/") + # os.system(f"rm -rf {output_corpus}/*") + pass + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run afl-fuzz on target.""" + os.environ["AFL_SKIP_CRASHES"] = "1" + os.environ["AFL_AUTORESUME"] = "1" + print(f"{input_corpus} {output_corpus} {target_binary}") + + crashes_storage = "/storage" + os.makedirs(crashes_storage, exist_ok=True) + + aflsmart_fuzzer_fn = lambda: aflsmart_fuzzer.fuzz( + input_corpus, output_corpus, target_binary) + + budget = 86_400 + fraction_mutant = 0.5 + time_per_mutant = 300 + initial_budget = 1_800 + post_mutant_fn = lambda: restore_out(input_corpus, output_corpus, + crashes_storage) + fuzzutil.fuzz_with_mutants_via_function( + aflsmart_fuzzer_fn, + target_binary, + budget, + time_per_mutant, + fraction_mutant, + initial_fn=aflsmart_fuzzer_fn, + initial_budget=initial_budget, + post_initial_fn=post_mutant_fn, + post_mutant_fn=post_mutant_fn, + ) diff --git a/fuzzers/aflsmart_muttfuzz/runner.Dockerfile b/fuzzers/aflsmart_muttfuzz/runner.Dockerfile new file mode 100644 index 000000000..1e9046888 --- /dev/null +++ b/fuzzers/aflsmart_muttfuzz/runner.Dockerfile @@ -0,0 +1,21 @@ +# 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-get update -y && \ + DEBIAN_FRONTEND=noninteractive TZ=Etc/UTC \ + apt-get install -y \ + mono-complete \ + tzdata diff --git a/fuzzers/honggfuzz_muttfuzz/builder.Dockerfile b/fuzzers/honggfuzz_muttfuzz/builder.Dockerfile new file mode 100644 index 000000000..11a483288 --- /dev/null +++ b/fuzzers/honggfuzz_muttfuzz/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_muttfuzz/fuzzer.py b/fuzzers/honggfuzz_muttfuzz/fuzzer.py new file mode 100644 index 000000000..dbffb86b1 --- /dev/null +++ b/fuzzers/honggfuzz_muttfuzz/fuzzer.py @@ -0,0 +1,67 @@ +# 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 AFLSmart fuzzer.""" + +import glob +import os +import shutil + +from fuzzers.aflplusplus_muttfuzz import fuzzutil +from fuzzers.honggfuzz import fuzzer as honggfuzz_fuzzer + + +def build(): + """Build benchmark.""" + honggfuzz_fuzzer.build() + + +def restore_out(input_corpus, output_corpus, crashes_storage): + """Restores output dir and copies crashes after mutant is done running""" + # os.system(f"rm -rf {input_corpus}/*") + # os.system(f"cp {output_corpus}/crashes/* {crashes_storage}/") + # os.system(f"cp {output_corpus}/crashes/* {input_corpus}/") + # os.system(f"cp {output_corpus}/corpus/* {input_corpus}/") + # os.system(f"rm -rf {output_corpus}/*") + pass + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run afl-fuzz on target.""" + os.environ["AFL_SKIP_CRASHES"] = "1" + os.environ["AFL_AUTORESUME"] = "1" + print(f"{input_corpus} {output_corpus} {target_binary}") + + crashes_storage = "/storage" + os.makedirs(crashes_storage, exist_ok=True) + + honggfuzz_fuzzer_fn = lambda: honggfuzz_fuzzer.fuzz( + input_corpus, output_corpus, target_binary) + + budget = 86_400 + fraction_mutant = 0.5 + time_per_mutant = 300 + initial_budget = 1_800 + post_mutant_fn = lambda: restore_out(input_corpus, output_corpus, + crashes_storage) + fuzzutil.fuzz_with_mutants_via_function( + honggfuzz_fuzzer_fn, + target_binary, + budget, + time_per_mutant, + fraction_mutant, + initial_fn=honggfuzz_fuzzer_fn, + initial_budget=initial_budget, + post_initial_fn=post_mutant_fn, + post_mutant_fn=post_mutant_fn, + ) diff --git a/fuzzers/honggfuzz_muttfuzz/runner.Dockerfile b/fuzzers/honggfuzz_muttfuzz/runner.Dockerfile new file mode 100644 index 000000000..f3eb30039 --- /dev/null +++ b/fuzzers/honggfuzz_muttfuzz/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_muttfuzz/builder.Dockerfile b/fuzzers/libafl_muttfuzz/builder.Dockerfile new file mode 100644 index 000000000..3f726cfec --- /dev/null +++ b/fuzzers/libafl_muttfuzz/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_muttfuzz/description.md b/fuzzers/libafl_muttfuzz/description.md new file mode 100644 index 000000000..ea9b947d6 --- /dev/null +++ b/fuzzers/libafl_muttfuzz/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_muttfuzz/fuzzer.py b/fuzzers/libafl_muttfuzz/fuzzer.py new file mode 100755 index 000000000..3770ac7c6 --- /dev/null +++ b/fuzzers/libafl_muttfuzz/fuzzer.py @@ -0,0 +1,65 @@ +# 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 AFLSmart fuzzer.""" + +import glob +import os +import shutil + +from fuzzers.aflplusplus_muttfuzz import fuzzutil +from fuzzers.libafl import fuzzer as libafl_fuzzer + + +def build(): + """Build benchmark.""" + libafl_fuzzer.build() + + +def restore_out(input_corpus, output_corpus, crashes_storage): + """Restores output dir and copies crashes after mutant is done running""" + # os.system(f"rm -rf {input_corpus}/*") + # os.system(f"cp {output_corpus}/crashes/* {crashes_storage}/") + # os.system(f"cp {output_corpus}/crashes/* {input_corpus}/") + # os.system(f"cp {output_corpus}/queue/* {input_corpus}/") + # os.system(f"rm -rf {output_corpus}/*") + pass + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run afl-fuzz on target.""" + print(f"{input_corpus} {output_corpus} {target_binary}") + + crashes_storage = "/storage" + os.makedirs(crashes_storage, exist_ok=True) + + libafl_fuzzer_fn = lambda: libafl_fuzzer.fuzz(input_corpus, output_corpus, + target_binary) + + budget = 86_400 + fraction_mutant = 0.5 + time_per_mutant = 300 + initial_budget = 1_800 + post_mutant_fn = lambda: restore_out(input_corpus, output_corpus, + crashes_storage) + fuzzutil.fuzz_with_mutants_via_function( + libafl_fuzzer_fn, + target_binary, + budget, + time_per_mutant, + fraction_mutant, + initial_fn=libafl_fuzzer_fn, + initial_budget=initial_budget, + post_initial_fn=post_mutant_fn, + post_mutant_fn=post_mutant_fn, + ) diff --git a/fuzzers/libafl_muttfuzz/runner.Dockerfile b/fuzzers/libafl_muttfuzz/runner.Dockerfile new file mode 100644 index 000000000..f0c5eb6cc --- /dev/null +++ b/fuzzers/libafl_muttfuzz/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_muttfuzz/builder.Dockerfile b/fuzzers/libfuzzer_muttfuzz/builder.Dockerfile new file mode 100644 index 000000000..7fe80447e --- /dev/null +++ b/fuzzers/libfuzzer_muttfuzz/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_muttfuzz/fuzzer.py b/fuzzers/libfuzzer_muttfuzz/fuzzer.py new file mode 100755 index 000000000..b768c8d19 --- /dev/null +++ b/fuzzers/libfuzzer_muttfuzz/fuzzer.py @@ -0,0 +1,65 @@ +# 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 AFLSmart fuzzer.""" + +import glob +import os +import shutil + +from fuzzers.aflplusplus_muttfuzz import fuzzutil +from fuzzers.libfuzzer import fuzzer as libfuzzer_fuzzer + + +def build(): + """Build benchmark.""" + libfuzzer_fuzzer.build() + + +def restore_out(input_corpus, output_corpus, crashes_storage): + """Restores output dir and copies crashes after mutant is done running""" + # os.system(f"rm -rf {input_corpus}/*") + # os.system(f"cp {output_corpus}/crashes/* {crashes_storage}/") + # os.system(f"cp {output_corpus}/crashes/* {input_corpus}/") + # os.system(f"cp {output_corpus}/corpus/* {input_corpus}/") + # os.system(f"rm -rf {output_corpus}/*") + pass + + +def fuzz(input_corpus, output_corpus, target_binary): + """Run afl-fuzz on target.""" + print(f"{input_corpus} {output_corpus} {target_binary}") + + crashes_storage = "/storage" + os.makedirs(crashes_storage, exist_ok=True) + + libfuzzer_fuzzer_fn = lambda: libfuzzer_fuzzer.fuzz( + input_corpus, output_corpus, target_binary) + + budget = 86_400 + fraction_mutant = 0.5 + time_per_mutant = 300 + initial_budget = 1_800 + post_mutant_fn = lambda: restore_out(input_corpus, output_corpus, + crashes_storage) + fuzzutil.fuzz_with_mutants_via_function( + libfuzzer_fuzzer_fn, + target_binary, + budget, + time_per_mutant, + fraction_mutant, + initial_fn=libfuzzer_fuzzer_fn, + initial_budget=initial_budget, + post_initial_fn=post_mutant_fn, + post_mutant_fn=post_mutant_fn, + ) diff --git a/fuzzers/libfuzzer_muttfuzz/patch.diff b/fuzzers/libfuzzer_muttfuzz/patch.diff new file mode 100644 index 000000000..a31cc301e --- /dev/null +++ b/fuzzers/libfuzzer_muttfuzz/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_muttfuzz/runner.Dockerfile b/fuzzers/libfuzzer_muttfuzz/runner.Dockerfile new file mode 100644 index 000000000..0d6cf004e --- /dev/null +++ b/fuzzers/libfuzzer_muttfuzz/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/service/gcbrun_experiment.py b/service/gcbrun_experiment.py index f19ab493d..642702d2c 100644 --- a/service/gcbrun_experiment.py +++ b/service/gcbrun_experiment.py @@ -16,6 +16,7 @@ """Entrypoint for gcbrun into run_experiment. This script will get the command from the last PR comment containing "/gcbrun" and pass it to run_experiment.py which will run an experiment.""" +# a dummy comment! import logging import os