github.com/prysmaticlabs/prysm@v1.4.4/third_party/afl/afl_driver.cpp (about)

     1  //===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
     2  //
     3  // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
     4  // See https://llvm.org/LICENSE.txt for license information.
     5  // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
     6  //===----------------------------------------------------------------------===//
     7  
     8  /* This file allows to fuzz libFuzzer-style target functions
     9   (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
    10  
    11  Usage:
    12  ################################################################################
    13  cat << EOF > test_fuzzer.cc
    14  #include <stddef.h>
    15  #include <stdint.h>
    16  extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
    17    if (size > 0 && data[0] == 'H')
    18      if (size > 1 && data[1] == 'I')
    19         if (size > 2 && data[2] == '!')
    20         __builtin_trap();
    21    return 0;
    22  }
    23  EOF
    24  # Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.
    25  clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c
    26  # Build afl-llvm-rt.o.c from the AFL distribution.
    27  clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
    28  # Build this file, link it with afl-llvm-rt.o.o and the target code.
    29  clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
    30  # Run AFL:
    31  rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
    32  $AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
    33  ################################################################################
    34  AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
    35  specified. If the file does not exist, it is created. This is useful for getting
    36  stack traces (when using ASAN for example) or original error messages on hard
    37  to reproduce bugs. Note that any content written to stderr will be written to
    38  this file instead of stderr's usual location.
    39  
    40  AFL_DRIVER_CLOSE_FD_MASK: Similar to libFuzzer's -close_fd_mask behavior option.
    41  If 1, close stdout at startup. If 2 close stderr; if 3 close both.
    42  
    43  */
    44  #include <assert.h>
    45  #include <errno.h>
    46  #include <stdarg.h>
    47  #include <stdint.h>
    48  #include <stdio.h>
    49  #include <stdlib.h>
    50  #include <string.h>
    51  #include <unistd.h>
    52  
    53  #include <fstream>
    54  #include <iostream>
    55  #include <vector>
    56  
    57  // Platform detection. Copied from FuzzerInternal.h
    58  #ifdef __linux__
    59  #define LIBFUZZER_LINUX 1
    60  #define LIBFUZZER_APPLE 0
    61  #define LIBFUZZER_NETBSD 0
    62  #define LIBFUZZER_FREEBSD 0
    63  #define LIBFUZZER_OPENBSD 0
    64  #elif __APPLE__
    65  #define LIBFUZZER_LINUX 0
    66  #define LIBFUZZER_APPLE 1
    67  #define LIBFUZZER_NETBSD 0
    68  #define LIBFUZZER_FREEBSD 0
    69  #define LIBFUZZER_OPENBSD 0
    70  #elif __NetBSD__
    71  #define LIBFUZZER_LINUX 0
    72  #define LIBFUZZER_APPLE 0
    73  #define LIBFUZZER_NETBSD 1
    74  #define LIBFUZZER_FREEBSD 0
    75  #define LIBFUZZER_OPENBSD 0
    76  #elif __FreeBSD__
    77  #define LIBFUZZER_LINUX 0
    78  #define LIBFUZZER_APPLE 0
    79  #define LIBFUZZER_NETBSD 0
    80  #define LIBFUZZER_FREEBSD 1
    81  #define LIBFUZZER_OPENBSD 0
    82  #elif __OpenBSD__
    83  #define LIBFUZZER_LINUX 0
    84  #define LIBFUZZER_APPLE 0
    85  #define LIBFUZZER_NETBSD 0
    86  #define LIBFUZZER_FREEBSD 0
    87  #define LIBFUZZER_OPENBSD 1
    88  #else
    89  #error "Support for your platform has not been implemented"
    90  #endif
    91  
    92  // libFuzzer interface is thin, so we don't include any libFuzzer headers.
    93  extern "C" {
    94  int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
    95  __attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
    96  }
    97  
    98  // Notify AFL about persistent mode.
    99  static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
   100  extern "C" int __afl_persistent_loop(unsigned int);
   101  static volatile char suppress_warning2 = AFL_PERSISTENT[0];
   102  
   103  // Notify AFL about deferred forkserver.
   104  static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
   105  extern "C" void __afl_manual_init();
   106  static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
   107  
   108  // Input buffer.
   109  static const size_t kMaxAflInputSize = 1 << 20;
   110  static uint8_t AflInputBuf[kMaxAflInputSize];
   111  
   112  // Use this optionally defined function to output sanitizer messages even if
   113  // user asks to close stderr.
   114  __attribute__((weak)) extern "C" void __sanitizer_set_report_fd(void *);
   115  
   116  // Keep track of where stderr content is being written to, so that
   117  // dup_and_close_stderr can use the correct one.
   118  static FILE *output_file = stderr;
   119  
   120  // Experimental feature to use afl_driver without AFL's deferred mode.
   121  // Needs to run before __afl_auto_init.
   122  __attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {
   123    if (getenv("AFL_DRIVER_DONT_DEFER")) {
   124      if (unsetenv("__AFL_DEFER_FORKSRV")) {
   125        perror("Failed to unset __AFL_DEFER_FORKSRV");
   126        abort();
   127      }
   128    }
   129  }
   130  
   131  // If the user asks us to duplicate stderr, then do it.
   132  static void maybe_duplicate_stderr() {
   133    char *stderr_duplicate_filename =
   134        getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
   135  
   136    if (!stderr_duplicate_filename)
   137      return;
   138  
   139    FILE *stderr_duplicate_stream =
   140        freopen(stderr_duplicate_filename, "a+", stderr);
   141  
   142    if (!stderr_duplicate_stream) {
   143      fprintf(
   144          stderr,
   145          "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
   146      abort();
   147    }
   148    output_file = stderr_duplicate_stream;
   149  }
   150  
   151  // Most of these I/O functions were inspired by/copied from libFuzzer's code.
   152  static void discard_output(int fd) {
   153    FILE *temp = fopen("/dev/null", "w");
   154    if (!temp)
   155      abort();
   156    dup2(fileno(temp), fd);
   157    fclose(temp);
   158  }
   159  
   160  static void close_stdout() { discard_output(STDOUT_FILENO); }
   161  
   162  // Prevent the targeted code from writing to "stderr" but allow sanitizers and
   163  // this driver to do so.
   164  static void dup_and_close_stderr() {
   165    int output_fileno = fileno(output_file);
   166    int output_fd = dup(output_fileno);
   167    if (output_fd <= 0)
   168      abort();
   169    FILE *new_output_file = fdopen(output_fd, "w");
   170    if (!new_output_file)
   171      abort();
   172    if (!__sanitizer_set_report_fd)
   173      return;
   174    __sanitizer_set_report_fd(reinterpret_cast<void *>(output_fd));
   175    discard_output(output_fileno);
   176  }
   177  
   178  static void Printf(const char *Fmt, ...) {
   179    va_list ap;
   180    va_start(ap, Fmt);
   181    vfprintf(output_file, Fmt, ap);
   182    va_end(ap);
   183    fflush(output_file);
   184  }
   185  
   186  // Close stdout and/or stderr if user asks for it.
   187  static void maybe_close_fd_mask() {
   188    char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK");
   189    if (!fd_mask_str)
   190      return;
   191    int fd_mask = atoi(fd_mask_str);
   192    if (fd_mask & 2)
   193      dup_and_close_stderr();
   194    if (fd_mask & 1)
   195      close_stdout();
   196  }
   197  
   198  // Define LLVMFuzzerMutate to avoid link failures for targets that use it
   199  // with libFuzzer's LLVMFuzzerCustomMutator.
   200  extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {
   201    assert(false && "LLVMFuzzerMutate should not be called from afl_driver");
   202    return 0;
   203  }
   204  
   205  // Execute any files provided as parameters.
   206  static int ExecuteFilesOnyByOne(int argc, char **argv) {
   207    for (int i = 1; i < argc; i++) {
   208      std::ifstream in(argv[i], std::ios::binary);
   209      in.seekg(0, in.end);
   210      size_t length = in.tellg();
   211      in.seekg (0, in.beg);
   212      std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;
   213      // Allocate exactly length bytes so that we reliably catch buffer overflows.
   214      std::vector<char> bytes(length);
   215      in.read(bytes.data(), bytes.size());
   216      assert(in);
   217      LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),
   218                             bytes.size());
   219      std::cout << "Execution successful" << std::endl;
   220    }
   221    return 0;
   222  }
   223  
   224  int main(int argc, char **argv) {
   225    Printf(
   226        "======================= INFO =========================\n"
   227        "This binary is built for AFL-fuzz.\n"
   228        "To run the target function on individual input(s) execute this:\n"
   229        "  %s < INPUT_FILE\n"
   230        "or\n"
   231        "  %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"
   232        "To fuzz with afl-fuzz execute this:\n"
   233        "  afl-fuzz [afl-flags] %s [-N]\n"
   234        "afl-fuzz will run N iterations before "
   235        "re-spawning the process (default: 1000)\n"
   236        "======================================================\n",
   237            argv[0], argv[0], argv[0]);
   238  
   239    maybe_duplicate_stderr();
   240    maybe_close_fd_mask();
   241    if (LLVMFuzzerInitialize)
   242      LLVMFuzzerInitialize(&argc, &argv);
   243    // Do any other expensive one-time initialization here.
   244  
   245    if (!getenv("AFL_DRIVER_DONT_DEFER"))
   246      __afl_manual_init();
   247  
   248    int N = 1000;
   249    if (argc == 2 && argv[1][0] == '-')
   250        N = atoi(argv[1] + 1);
   251    else if(argc == 2 && (N = atoi(argv[1])) > 0)
   252        Printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
   253    else if (argc > 1)
   254      return ExecuteFilesOnyByOne(argc, argv);
   255  
   256    assert(N > 0);
   257  
   258    // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization
   259    // on the first execution of LLVMFuzzerTestOneInput is ignored.
   260    uint8_t dummy_input[1] = {0};
   261    LLVMFuzzerTestOneInput(dummy_input, 1);
   262  
   263    int num_runs = 0;
   264    while (__afl_persistent_loop(N)) {
   265      ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
   266      if (n_read > 0) {
   267        // Copy AflInputBuf into a separate buffer to let asan find buffer
   268        // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
   269        uint8_t *copy = new uint8_t[n_read];
   270        memcpy(copy, AflInputBuf, n_read);
   271        num_runs++;
   272        LLVMFuzzerTestOneInput(copy, n_read);
   273        delete[] copy;
   274      }
   275    }
   276    Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);
   277  }