blob: 63aebab469cb1d73dd1d47a43810f95f72493718 [file] [log] [blame]
Kostya Serebryanyc8bc8822016-05-24 19:05:25 +00001//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//===----------------------------------------------------------------------===//
8
Kostya Serebryany781e8da2016-05-10 23:46:50 +00009/* This file allows to fuzz libFuzzer-style target functions
10 (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
11
12Usage:
13################################################################################
14cat << EOF > test_fuzzer.cc
15#include <stdint.h>
16#include <stddef.h>
17extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
18 if (size > 0 && data[0] == 'H')
19 if (size > 1 && data[1] == 'I')
20 if (size > 2 && data[2] == '!')
21 __builtin_trap();
22 return 0;
23}
24EOF
25# Build your target with -fsanitize-coverage=trace-pc using fresh clang.
26clang -g -fsanitize-coverage=trace-pc test_fuzzer.cc -c
27# Build afl-llvm-rt.o.c from the AFL distribution.
28clang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
29# Build this file, link it with afl-llvm-rt.o.o and the target code.
30clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
31# Run AFL:
32rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
33$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
34################################################################################
35*/
36#include <assert.h>
37#include <stdio.h>
38#include <stdint.h>
39#include <stdlib.h>
40#include <string.h>
41#include <unistd.h>
42
43// libFuzzer interface is thin, so we don't include any libFuzzer headers.
44extern "C" {
45int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
46__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
47}
48
49// Notify AFL about persistent mode.
50static volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
51extern "C" int __afl_persistent_loop(unsigned int);
52static volatile char suppress_warning2 = AFL_PERSISTENT[0];
53
54// Notify AFL about deferred forkserver.
55static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
56extern "C" void __afl_manual_init();
57static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
58
59// Input buffer.
60static const size_t kMaxAflInputSize = 1 << 20;
61static uint8_t AflInputBuf[kMaxAflInputSize];
62
63int main(int argc, char **argv) {
64 fprintf(stderr, "Running in AFl-fuzz mode\nUsage:\n"
65 "afl-fuzz [afl-flags] %s [N] "
66 "-- run N fuzzing iterations before "
67 "re-spawning the process (default: 1000)\n",
68 argv[0]);
69 if (LLVMFuzzerInitialize)
70 LLVMFuzzerInitialize(&argc, &argv);
71 // Do any other expensive one-time initialization here.
72
73 __afl_manual_init();
74
75 int N = 1000;
76 if (argc >= 2)
77 N = atoi(argv[1]);
78 assert(N > 0);
79 while (__afl_persistent_loop(N)) {
80 ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
81 if (n_read > 0) {
82 // Copy AflInputBuf into a separate buffer to let asan find buffer
83 // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
84 uint8_t *copy = new uint8_t[n_read];
85 memcpy(copy, AflInputBuf, n_read);
86 LLVMFuzzerTestOneInput(copy, n_read);
87 delete[] copy;
88 }
89 }
90}