brintos

brintos / llvm-project-archived public Read only

0
0
Text · 8.7 KiB · 52aede7 Raw
268 lines · cpp
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-exception6//===----------------------------------------------------------------------===//7 8/* This file allows to fuzz libFuzzer-style target functions9 (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.10 11Usage:12################################################################################13cat << EOF > test_fuzzer.cc14#include <stddef.h>15#include <stdint.h>16extern "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}23EOF24# Build your target with -fsanitize-coverage=trace-pc-guard using fresh clang.25clang -g -fsanitize-coverage=trace-pc-guard test_fuzzer.cc -c26# Build afl-llvm-rt.o.c from the AFL distribution.27clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c28# Build this file, link it with afl-llvm-rt.o.o and the target code.29clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o30# Run AFL:31rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;32$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out33################################################################################34AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file35specified. If the file does not exist, it is created. This is useful for getting36stack traces (when using ASAN for example) or original error messages on hard37to reproduce bugs. Note that any content written to stderr will be written to38this file instead of stderr's usual location.39 40AFL_DRIVER_CLOSE_FD_MASK: Similar to libFuzzer's -close_fd_mask behavior option.41If 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.h58#ifdef __linux__59#define LIBFUZZER_LINUX 160#define LIBFUZZER_APPLE 061#define LIBFUZZER_NETBSD 062#define LIBFUZZER_FREEBSD 063#elif __APPLE__64#define LIBFUZZER_LINUX 065#define LIBFUZZER_APPLE 166#define LIBFUZZER_NETBSD 067#define LIBFUZZER_FREEBSD 068#elif __NetBSD__69#define LIBFUZZER_LINUX 070#define LIBFUZZER_APPLE 071#define LIBFUZZER_NETBSD 172#define LIBFUZZER_FREEBSD 073#elif __FreeBSD__74#define LIBFUZZER_LINUX 075#define LIBFUZZER_APPLE 076#define LIBFUZZER_NETBSD 077#define LIBFUZZER_FREEBSD 178#else79#error "Support for your platform has not been implemented"80#endif81 82// libFuzzer interface is thin, so we don't include any libFuzzer headers.83extern "C" {84int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);85__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);86}87 88// Notify AFL about persistent mode.89static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";90extern "C" int __afl_persistent_loop(unsigned int);91static volatile char suppress_warning2 = AFL_PERSISTENT[0];92 93// Notify AFL about deferred forkserver.94static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";95extern "C" void __afl_manual_init();96static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];97 98// Input buffer.99static const size_t kMaxAflInputSize = 1 << 20;100static uint8_t AflInputBuf[kMaxAflInputSize];101 102// Use this optionally defined function to output sanitizer messages even if103// user asks to close stderr.104extern "C" __attribute__((weak)) void __sanitizer_set_report_fd(void *);105 106// Keep track of where stderr content is being written to, so that107// dup_and_close_stderr can use the correct one.108static FILE *output_file = stderr;109 110// Experimental feature to use afl_driver without AFL's deferred mode.111// Needs to run before __afl_auto_init.112__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {113  if (getenv("AFL_DRIVER_DONT_DEFER")) {114    if (unsetenv("__AFL_DEFER_FORKSRV")) {115      perror("Failed to unset __AFL_DEFER_FORKSRV");116      abort();117    }118  }119}120 121// If the user asks us to duplicate stderr, then do it.122static void maybe_duplicate_stderr() {123  char *stderr_duplicate_filename =124      getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");125 126  if (!stderr_duplicate_filename)127    return;128 129  FILE *stderr_duplicate_stream =130      freopen(stderr_duplicate_filename, "a+", stderr);131 132  if (!stderr_duplicate_stream) {133    fprintf(134        stderr,135        "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");136    abort();137  }138  output_file = stderr_duplicate_stream;139}140 141// Most of these I/O functions were inspired by/copied from libFuzzer's code.142static void discard_output(int fd) {143  FILE *temp = fopen("/dev/null", "w");144  if (!temp)145    abort();146  dup2(fileno(temp), fd);147  fclose(temp);148}149 150static void close_stdout() { discard_output(STDOUT_FILENO); }151 152// Prevent the targeted code from writing to "stderr" but allow sanitizers and153// this driver to do so.154static void dup_and_close_stderr() {155  int output_fileno = fileno(output_file);156  int output_fd = dup(output_fileno);157  if (output_fd <= 0)158    abort();159  FILE *new_output_file = fdopen(output_fd, "w");160  if (!new_output_file)161    abort();162  if (!__sanitizer_set_report_fd)163    return;164  __sanitizer_set_report_fd(reinterpret_cast<void *>(output_fd));165  discard_output(output_fileno);166}167 168static void Printf(const char *Fmt, ...) {169  va_list ap;170  va_start(ap, Fmt);171  vfprintf(output_file, Fmt, ap);172  va_end(ap);173  fflush(output_file);174}175 176// Close stdout and/or stderr if user asks for it.177static void maybe_close_fd_mask() {178  char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK");179  if (!fd_mask_str)180    return;181  int fd_mask = atoi(fd_mask_str);182  if (fd_mask & 2)183    dup_and_close_stderr();184  if (fd_mask & 1)185    close_stdout();186}187 188// Define LLVMFuzzerMutate to avoid link failures for targets that use it189// with libFuzzer's LLVMFuzzerCustomMutator.190extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) {191  assert(false && "LLVMFuzzerMutate should not be called from afl_driver");192  return 0;193}194 195// Execute any files provided as parameters.196static int ExecuteFilesOnyByOne(int argc, char **argv) {197  for (int i = 1; i < argc; i++) {198    std::ifstream in(argv[i], std::ios::binary);199    in.seekg(0, in.end);200    size_t length = in.tellg();201    in.seekg (0, in.beg);202    std::cout << "Reading " << length << " bytes from " << argv[i] << std::endl;203    // Allocate exactly length bytes so that we reliably catch buffer overflows.204    std::vector<char> bytes(length);205    in.read(bytes.data(), bytes.size());206    assert(in);207    LLVMFuzzerTestOneInput(reinterpret_cast<const uint8_t *>(bytes.data()),208                           bytes.size());209    std::cout << "Execution successful" << std::endl;210  }211  return 0;212}213 214int main(int argc, char **argv) {215  Printf(216      "======================= INFO =========================\n"217      "This binary is built for AFL-fuzz.\n"218      "To run the target function on individual input(s) execute this:\n"219      "  %s < INPUT_FILE\n"220      "or\n"221      "  %s INPUT_FILE1 [INPUT_FILE2 ... ]\n"222      "To fuzz with afl-fuzz execute this:\n"223      "  afl-fuzz [afl-flags] %s [-N]\n"224      "afl-fuzz will run N iterations before "225      "re-spawning the process (default: 1000)\n"226      "======================================================\n",227          argv[0], argv[0], argv[0]);228 229  maybe_duplicate_stderr();230  maybe_close_fd_mask();231  if (LLVMFuzzerInitialize)232    LLVMFuzzerInitialize(&argc, &argv);233  // Do any other expensive one-time initialization here.234 235  if (!getenv("AFL_DRIVER_DONT_DEFER"))236    __afl_manual_init();237 238  int N = 1000;239  if (argc == 2 && argv[1][0] == '-')240      N = atoi(argv[1] + 1);241  else if(argc == 2 && (N = atoi(argv[1])) > 0)242      Printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);243  else if (argc > 1)244    return ExecuteFilesOnyByOne(argc, argv);245 246  assert(N > 0);247 248  // Call LLVMFuzzerTestOneInput here so that coverage caused by initialization249  // on the first execution of LLVMFuzzerTestOneInput is ignored.250  uint8_t dummy_input[1] = {0};251  LLVMFuzzerTestOneInput(dummy_input, 1);252 253  int num_runs = 0;254  while (__afl_persistent_loop(N)) {255    ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);256    if (n_read > 0) {257      // Copy AflInputBuf into a separate buffer to let asan find buffer258      // overflows. Don't use unique_ptr/etc to avoid extra dependencies.259      uint8_t *copy = new uint8_t[n_read];260      memcpy(copy, AflInputBuf, n_read);261      num_runs++;262      LLVMFuzzerTestOneInput(copy, n_read);263      delete[] copy;264    }265  }266  Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);267}268