aboutsummaryrefslogtreecommitdiff
path: root/lib/Fuzzer/afl/afl_driver.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Fuzzer/afl/afl_driver.cpp')
-rw-r--r--lib/Fuzzer/afl/afl_driver.cpp335
1 files changed, 0 insertions, 335 deletions
diff --git a/lib/Fuzzer/afl/afl_driver.cpp b/lib/Fuzzer/afl/afl_driver.cpp
deleted file mode 100644
index 15bceb896e17..000000000000
--- a/lib/Fuzzer/afl/afl_driver.cpp
+++ /dev/null
@@ -1,335 +0,0 @@
-//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//===----------------------------------------------------------------------===//
-
-/* This file allows to fuzz libFuzzer-style target functions
- (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
-
-Usage:
-################################################################################
-cat << EOF > test_fuzzer.cc
-#include <stddef.h>
-#include <stdint.h>
-extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
- if (size > 0 && data[0] == 'H')
- if (size > 1 && data[1] == 'I')
- if (size > 2 && data[2] == '!')
- __builtin_trap();
- return 0;
-}
-EOF
-# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
-clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c
-# Build afl-llvm-rt.o.c from the AFL distribution.
-clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
-# Build this file, link it with afl-llvm-rt.o.o and the target code.
-clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
-# Run AFL:
-rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
-$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
-################################################################################
-Environment Variables:
-There are a few environment variables that can be set to use features that
-afl-fuzz doesn't have.
-
-AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
-specified. If the file does not exist, it is created. This is useful for getting
-stack traces (when using ASAN for example) or original error messages on hard to
-reproduce bugs.
-
-AFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra
-statistics to the file specified. Currently these are peak_rss_mb
-(the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If
-the file does not exist it is created. If the file does exist then
-afl_driver assumes it was restarted by afl-fuzz and will try to read old
-statistics from the file. If that fails then the process will quit.
-
-*/
-#include <assert.h>
-#include <errno.h>
-#include <signal.h>
-#include <stdint.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/resource.h>
-#include <sys/time.h>
-#include <unistd.h>
-
-#include <fstream>
-#include <iostream>
-#include <vector>
-
-// Platform detection. Copied from FuzzerInternal.h
-#ifdef __linux__
-#define LIBFUZZER_LINUX 1
-#define LIBFUZZER_APPLE 0
-#elif __APPLE__
-#define LIBFUZZER_LINUX 0
-#define LIBFUZZER_APPLE 1
-#else
-#error "Support for your platform has not been implemented"
-#endif
-
-// Used to avoid repeating error checking boilerplate. If cond is false, a
-// fatal error has occured in the program. In this event print error_message
-// to stderr and abort(). Otherwise do nothing. Note that setting
-// AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended
-// to the file as well, if the error occurs after the duplication is performed.
-#define CHECK_ERROR(cond, error_message) \
- if (!(cond)) { \
- fprintf(stderr, (error_message)); \
- abort(); \
- }
-
-// libFuzzer interface is thin, so we don't include any libFuzzer headers.
-extern "C" {
-int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
-__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
-}
-
-// Notify AFL about persistent mode.
-static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
-extern "C" int __afl_persistent_loop(unsigned int);
-static volatile char suppress_warning2 = AFL_PERSISTENT[0];
-
-// Notify AFL about deferred forkserver.
-static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
-extern "C" void __afl_manual_init();
-static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
-
-// Input buffer.
-static const size_t kMaxAflInputSize = 1 << 20;
-static uint8_t AflInputBuf[kMaxAflInputSize];
-
-// Variables we need for writing to the extra stats file.
-static FILE *extra_stats_file = NULL;
-static uint32_t previous_peak_rss = 0;
-static time_t slowest_unit_time_secs = 0;
-static const int kNumExtraStats = 2;
-static const char *kExtraStatsFormatString = "peak_rss_mb : %u\n"
- "slowest_unit_time_sec : %u\n";
-
-// Copied from FuzzerUtil.cpp.
-size_t GetPeakRSSMb() {
- struct rusage usage;
- if (getrusage(RUSAGE_SELF, &usage))
- return 0;
- if (LIBFUZZER_LINUX) {
- // ru_maxrss is in KiB
- return usage.ru_maxrss >> 10;
- } else if (LIBFUZZER_APPLE) {
- // ru_maxrss is in bytes
- return usage.ru_maxrss >> 20;
- }
- assert(0 && "GetPeakRSSMb() is not implemented for your platform");
- return 0;
-}
-
-// Based on SetSigaction in FuzzerUtil.cpp
-static void SetSigaction(int signum,
- void (*callback)(int, siginfo_t *, void *)) {
- struct sigaction sigact;
- memset(&sigact, 0, sizeof(sigact));
- sigact.sa_sigaction = callback;
- if (sigaction(signum, &sigact, 0)) {
- fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno);
- exit(1);
- }
-}
-
-// Write extra stats to the file specified by the user. If none is specified
-// this function will never be called.
-static void write_extra_stats() {
- uint32_t peak_rss = GetPeakRSSMb();
-
- if (peak_rss < previous_peak_rss)
- peak_rss = previous_peak_rss;
-
- int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString,
- peak_rss, slowest_unit_time_secs);
-
- CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file");
-
- CHECK_ERROR(fclose(extra_stats_file) == 0,
- "Failed to close extra_stats_file");
-}
-
-// Call write_extra_stats before we exit.
-static void crash_handler(int, siginfo_t *, void *) {
- // Make sure we don't try calling write_extra_stats again if we crashed while
- // trying to call it.
- static bool first_crash = true;
- CHECK_ERROR(first_crash,
- "Crashed in crash signal handler. This is a bug in the fuzzer.");
-
- first_crash = false;
- write_extra_stats();
-}
-
-// If the user has specified an extra_stats_file through the environment
-// variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up
-// to write stats to it on exit. If no file is specified, do nothing. Otherwise
-// install signal and exit handlers to write to the file when the process exits.
-// Then if the file doesn't exist create it and set extra stats to 0. But if it
-// does exist then read the initial values of the extra stats from the file
-// and check that the file is writable.
-static void maybe_initialize_extra_stats() {
- // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do.
- char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME");
- if (!extra_stats_filename)
- return;
-
- // Open the file and find the previous peak_rss_mb value.
- // This is necessary because the fuzzing process is restarted after N
- // iterations are completed. So we may need to get this value from a previous
- // process to be accurate.
- extra_stats_file = fopen(extra_stats_filename, "r");
-
- // If extra_stats_file already exists: read old stats from it.
- if (extra_stats_file) {
- int matches = fscanf(extra_stats_file, kExtraStatsFormatString,
- &previous_peak_rss, &slowest_unit_time_secs);
-
- // Make sure we have read a real extra stats file and that we have used it
- // to set slowest_unit_time_secs and previous_peak_rss.
- CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt");
-
- CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file");
-
- // Now open the file for writing.
- extra_stats_file = fopen(extra_stats_filename, "w");
- CHECK_ERROR(extra_stats_file,
- "Failed to open extra stats file for writing");
- } else {
- // Looks like this is the first time in a fuzzing job this is being called.
- extra_stats_file = fopen(extra_stats_filename, "w+");
- CHECK_ERROR(extra_stats_file, "failed to create extra stats file");
- }
-
- // Make sure that crash_handler gets called on any kind of fatal error.
- int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE, SIGINT,
- SIGTERM};
-
- const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]);
-
- for (size_t idx = 0; idx < num_signals; idx++)
- SetSigaction(crash_signals[idx], crash_handler);
-
- // Make sure it gets called on other kinds of exits.
- atexit(write_extra_stats);
-}
-
-// If the user asks us to duplicate stderr, then do it.
-static void maybe_duplicate_stderr() {
- char* stderr_duplicate_filename =
- getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
-
- if (!stderr_duplicate_filename)
- return;
-
- FILE* stderr_duplicate_stream =
- freopen(stderr_duplicate_filename, "a+", stderr);
-
- if (!stderr_duplicate_stream) {
- fprintf(
- stderr,
- "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
- abort();
- }
-}
-
-// Define LLVMFuzzerMutate to avoid link failures for targets that use it
-// with libFuzzer's LLVMFuzzerCustomMutator.
-extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
- assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
- return 0;
-}
-
-// Execute any files provided as parameters.
-int ExecuteFilesOnyByOne(int argc, char **argv) {
- for (int i = 1; i < argc; i++) {
- std::ifstream in(argv[i]);
- in.seekg(0, in.end);
- size_t length = in.tellg();
- in.seekg (0, in.beg);
- std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
- // Allocate exactly length bytes so that we reliably catch buffer overflows.
- std::vector<char> bytes(length);
- in.read(bytes.data(), bytes.size());
- assert(in);
- LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
- bytes.size());
- std::cout << "Execution successfull" << std::endl;
- }
- return 0;
-}
-
-int main(int argc, char **argv) {
- fprintf(stderr,
- "======================= INFO =========================\n"
- "This binary is built for AFL-fuzz.\n"
- "To run the target function on individual input(s) execute this:\n"
- " %s < INPUT_FILE\n"
- "or\n"
- " %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
- "To fuzz with afl-fuzz execute this:\n"
- " afl-fuzz [afl-flags] %s [-N]\n"
- "afl-fuzz will run N iterations before "
- "re-spawning the process (default: 1000)\n"
- "======================================================\n",
- argv[0], argv[0], argv[0]);
- if (LLVMFuzzerInitialize)
- LLVMFuzzerInitialize(&argc, &argv);
- // Do any other expensive one-time initialization here.
-
- maybe_duplicate_stderr();
- maybe_initialize_extra_stats();
-
- __afl_manual_init();
-
- int N = 1000;
- if (argc == 2 && argv[1][0] == '-')
- N = atoi(argv[1] + 1);
- else if(argc == 2 && (N = atoi(argv[1])) > 0)
- fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n",
- argv[0], N);
- else if (argc > 1)
- return ExecuteFilesOnyByOne(argc, argv);
-
- assert(N > 0);
- time_t unit_time_secs;
- int num_runs = 0;
- while (__afl_persistent_loop(N)) {
- ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
- if (n_read > 0) {
- // Copy AflInputBuf into a separate buffer to let asan find buffer
- // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
- uint8_t *copy = new uint8_t[n_read];
- memcpy(copy, AflInputBuf, n_read);
-
- struct timeval unit_start_time;
- CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0,
- "Calling gettimeofday failed");
-
- num_runs++;
- LLVMFuzzerTestOneInput(copy, n_read);
-
- struct timeval unit_stop_time;
- CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0,
- "Calling gettimeofday failed");
-
- // Update slowest_unit_time_secs if we see a new max.
- unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec;
- if (slowest_unit_time_secs < unit_time_secs)
- slowest_unit_time_secs = unit_time_secs;
-
- delete[] copy;
- }
- }
- fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);
-}