1c5f01b2fSopenharmony_ci//===- afl_driver.cpp - a glue between AFL and libFuzzer --------*- C++ -* ===//
2c5f01b2fSopenharmony_ci//
3c5f01b2fSopenharmony_ci//                     The LLVM Compiler Infrastructure
4c5f01b2fSopenharmony_ci//
5c5f01b2fSopenharmony_ci// This file is distributed under the University of Illinois Open Source
6c5f01b2fSopenharmony_ci// License. See LICENSE.TXT for details.
7c5f01b2fSopenharmony_ci//===----------------------------------------------------------------------===//
8c5f01b2fSopenharmony_ci
9c5f01b2fSopenharmony_ci/* This file allows to fuzz libFuzzer-style target functions
10c5f01b2fSopenharmony_ci (LLVMFuzzerTestOneInput) with AFL using AFL's persistent (in-process) mode.
11c5f01b2fSopenharmony_ci
12c5f01b2fSopenharmony_ciUsage:
13c5f01b2fSopenharmony_ci################################################################################
14c5f01b2fSopenharmony_cicat << EOF > test_fuzzer.cc
15c5f01b2fSopenharmony_ci#include <stdint.h>
16c5f01b2fSopenharmony_ci#include <stddef.h>
17c5f01b2fSopenharmony_ciextern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) {
18c5f01b2fSopenharmony_ci  if (size > 0 && data[0] == 'H')
19c5f01b2fSopenharmony_ci    if (size > 1 && data[1] == 'I')
20c5f01b2fSopenharmony_ci       if (size > 2 && data[2] == '!')
21c5f01b2fSopenharmony_ci       __builtin_trap();
22c5f01b2fSopenharmony_ci  return 0;
23c5f01b2fSopenharmony_ci}
24c5f01b2fSopenharmony_ciEOF
25c5f01b2fSopenharmony_ci# Build your target with -fsanitize-coverage=trace-pc using fresh clang.
26c5f01b2fSopenharmony_ciclang -g -fsanitize-coverage=trace-pc test_fuzzer.cc -c
27c5f01b2fSopenharmony_ci# Build afl-llvm-rt.o.c from the AFL distribution.
28c5f01b2fSopenharmony_ciclang -c -w $AFL_HOME/llvm_mode/afl-llvm-rt.o.c
29c5f01b2fSopenharmony_ci# Build this file, link it with afl-llvm-rt.o.o and the target code.
30c5f01b2fSopenharmony_ciclang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
31c5f01b2fSopenharmony_ci# Run AFL:
32c5f01b2fSopenharmony_cirm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
33c5f01b2fSopenharmony_ci$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
34c5f01b2fSopenharmony_ci################################################################################
35c5f01b2fSopenharmony_ciEnvironment Variables:
36c5f01b2fSopenharmony_ciThere are a few environment variables that can be set to use features that
37c5f01b2fSopenharmony_ciafl-fuzz doesn't have.
38c5f01b2fSopenharmony_ci
39c5f01b2fSopenharmony_ciAFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
40c5f01b2fSopenharmony_cispecified. If the file does not exist, it is created. This is useful for getting
41c5f01b2fSopenharmony_cistack traces (when using ASAN for example) or original error messages on hard to
42c5f01b2fSopenharmony_cireproduce bugs.
43c5f01b2fSopenharmony_ci
44c5f01b2fSopenharmony_ciAFL_DRIVER_EXTRA_STATS_FILENAME: Setting this causes afl_driver to write extra
45c5f01b2fSopenharmony_cistatistics to the file specified. Currently these are peak_rss_mb
46c5f01b2fSopenharmony_ci(the peak amount of virtual memory used in MB) and slowest_unit_time_secs. If
47c5f01b2fSopenharmony_cithe file does not exist it is created. If the file does exist then
48c5f01b2fSopenharmony_ciafl_driver assumes it was restarted by afl-fuzz and will try to read old
49c5f01b2fSopenharmony_cistatistics from the file. If that fails then the process will quit.
50c5f01b2fSopenharmony_ci
51c5f01b2fSopenharmony_ci*/
52c5f01b2fSopenharmony_ci#include <assert.h>
53c5f01b2fSopenharmony_ci#include <stdio.h>
54c5f01b2fSopenharmony_ci#include <stdint.h>
55c5f01b2fSopenharmony_ci#include <stdlib.h>
56c5f01b2fSopenharmony_ci#include <string.h>
57c5f01b2fSopenharmony_ci#include <unistd.h>
58c5f01b2fSopenharmony_ci#include <errno.h>
59c5f01b2fSopenharmony_ci#include <signal.h>
60c5f01b2fSopenharmony_ci#include <sys/resource.h>
61c5f01b2fSopenharmony_ci#include <sys/time.h>
62c5f01b2fSopenharmony_ci// Platform detection. Copied from FuzzerInternal.h
63c5f01b2fSopenharmony_ci#ifdef __linux__
64c5f01b2fSopenharmony_ci#define LIBFUZZER_LINUX 1
65c5f01b2fSopenharmony_ci#define LIBFUZZER_APPLE 0
66c5f01b2fSopenharmony_ci#elif __APPLE__
67c5f01b2fSopenharmony_ci#define LIBFUZZER_LINUX 0
68c5f01b2fSopenharmony_ci#define LIBFUZZER_APPLE 1
69c5f01b2fSopenharmony_ci#else
70c5f01b2fSopenharmony_ci#error "Support for your platform has not been implemented"
71c5f01b2fSopenharmony_ci#endif
72c5f01b2fSopenharmony_ci
73c5f01b2fSopenharmony_ci// Used to avoid repeating error checking boilerplate. If cond is false, a
74c5f01b2fSopenharmony_ci// fatal error has occured in the program. In this event print error_message
75c5f01b2fSopenharmony_ci// to stderr and abort(). Otherwise do nothing. Note that setting
76c5f01b2fSopenharmony_ci// AFL_DRIVER_STDERR_DUPLICATE_FILENAME may cause error_message to be appended
77c5f01b2fSopenharmony_ci// to the file as well, if the error occurs after the duplication is performed.
78c5f01b2fSopenharmony_ci#define CHECK_ERROR(cond, error_message)                                       \
79c5f01b2fSopenharmony_ci  if (!(cond)) {                                                               \
80c5f01b2fSopenharmony_ci    fprintf(stderr, (error_message));                                          \
81c5f01b2fSopenharmony_ci    abort();                                                                   \
82c5f01b2fSopenharmony_ci  }
83c5f01b2fSopenharmony_ci
84c5f01b2fSopenharmony_ci// libFuzzer interface is thin, so we don't include any libFuzzer headers.
85c5f01b2fSopenharmony_ciextern "C" {
86c5f01b2fSopenharmony_ciint LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size);
87c5f01b2fSopenharmony_ci__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
88c5f01b2fSopenharmony_ci}
89c5f01b2fSopenharmony_ci
90c5f01b2fSopenharmony_ci// Notify AFL about persistent mode.
91c5f01b2fSopenharmony_cistatic volatile char AFL_PERSISTENT[] = "##SIG_AFL_PERSISTENT##";
92c5f01b2fSopenharmony_ciextern "C" int __afl_persistent_loop(unsigned int);
93c5f01b2fSopenharmony_cistatic volatile char suppress_warning2 = AFL_PERSISTENT[0];
94c5f01b2fSopenharmony_ci
95c5f01b2fSopenharmony_ci// Notify AFL about deferred forkserver.
96c5f01b2fSopenharmony_cistatic volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
97c5f01b2fSopenharmony_ciextern "C" void  __afl_manual_init();
98c5f01b2fSopenharmony_cistatic volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
99c5f01b2fSopenharmony_ci
100c5f01b2fSopenharmony_ci// Input buffer.
101c5f01b2fSopenharmony_cistatic const size_t kMaxAflInputSize = 1 << 20;
102c5f01b2fSopenharmony_cistatic uint8_t AflInputBuf[kMaxAflInputSize];
103c5f01b2fSopenharmony_ci
104c5f01b2fSopenharmony_ci// Variables we need for writing to the extra stats file.
105c5f01b2fSopenharmony_cistatic FILE *extra_stats_file = NULL;
106c5f01b2fSopenharmony_cistatic uint32_t previous_peak_rss = 0;
107c5f01b2fSopenharmony_cistatic time_t slowest_unit_time_secs = 0;
108c5f01b2fSopenharmony_cistatic const int kNumExtraStats = 2;
109c5f01b2fSopenharmony_cistatic const char *kExtraStatsFormatString = "peak_rss_mb            : %u\n"
110c5f01b2fSopenharmony_ci                                             "slowest_unit_time_sec  : %u\n";
111c5f01b2fSopenharmony_ci
112c5f01b2fSopenharmony_ci// Copied from FuzzerUtil.cpp.
113c5f01b2fSopenharmony_cisize_t GetPeakRSSMb() {
114c5f01b2fSopenharmony_ci  struct rusage usage;
115c5f01b2fSopenharmony_ci  if (getrusage(RUSAGE_SELF, &usage))
116c5f01b2fSopenharmony_ci    return 0;
117c5f01b2fSopenharmony_ci  if (LIBFUZZER_LINUX) {
118c5f01b2fSopenharmony_ci    // ru_maxrss is in KiB
119c5f01b2fSopenharmony_ci    return usage.ru_maxrss >> 10;
120c5f01b2fSopenharmony_ci  } else if (LIBFUZZER_APPLE) {
121c5f01b2fSopenharmony_ci    // ru_maxrss is in bytes
122c5f01b2fSopenharmony_ci    return usage.ru_maxrss >> 20;
123c5f01b2fSopenharmony_ci  }
124c5f01b2fSopenharmony_ci  assert(0 && "GetPeakRSSMb() is not implemented for your platform");
125c5f01b2fSopenharmony_ci  return 0;
126c5f01b2fSopenharmony_ci}
127c5f01b2fSopenharmony_ci
128c5f01b2fSopenharmony_ci// Based on SetSigaction in FuzzerUtil.cpp
129c5f01b2fSopenharmony_cistatic void SetSigaction(int signum,
130c5f01b2fSopenharmony_ci                         void (*callback)(int, siginfo_t *, void *)) {
131c5f01b2fSopenharmony_ci  struct sigaction sigact;
132c5f01b2fSopenharmony_ci  memset(&sigact, 0, sizeof(sigact));
133c5f01b2fSopenharmony_ci  sigact.sa_sigaction = callback;
134c5f01b2fSopenharmony_ci  if (sigaction(signum, &sigact, 0)) {
135c5f01b2fSopenharmony_ci    fprintf(stderr, "libFuzzer: sigaction failed with %d\n", errno);
136c5f01b2fSopenharmony_ci    exit(1);
137c5f01b2fSopenharmony_ci  }
138c5f01b2fSopenharmony_ci}
139c5f01b2fSopenharmony_ci
140c5f01b2fSopenharmony_ci// Write extra stats to the file specified by the user. If none is specified
141c5f01b2fSopenharmony_ci// this function will never be called.
142c5f01b2fSopenharmony_cistatic void write_extra_stats() {
143c5f01b2fSopenharmony_ci  uint32_t peak_rss = GetPeakRSSMb();
144c5f01b2fSopenharmony_ci
145c5f01b2fSopenharmony_ci  if (peak_rss < previous_peak_rss)
146c5f01b2fSopenharmony_ci    peak_rss = previous_peak_rss;
147c5f01b2fSopenharmony_ci
148c5f01b2fSopenharmony_ci  int chars_printed = fprintf(extra_stats_file, kExtraStatsFormatString,
149c5f01b2fSopenharmony_ci                              peak_rss, slowest_unit_time_secs);
150c5f01b2fSopenharmony_ci
151c5f01b2fSopenharmony_ci  CHECK_ERROR(chars_printed != 0, "Failed to write extra_stats_file");
152c5f01b2fSopenharmony_ci
153c5f01b2fSopenharmony_ci  CHECK_ERROR(fclose(extra_stats_file) == 0,
154c5f01b2fSopenharmony_ci              "Failed to close extra_stats_file");
155c5f01b2fSopenharmony_ci}
156c5f01b2fSopenharmony_ci
157c5f01b2fSopenharmony_ci// Call write_extra_stats before we exit.
158c5f01b2fSopenharmony_cistatic void crash_handler(int, siginfo_t *, void *) {
159c5f01b2fSopenharmony_ci  // Make sure we don't try calling write_extra_stats again if we crashed while
160c5f01b2fSopenharmony_ci  // trying to call it.
161c5f01b2fSopenharmony_ci  static bool first_crash = true;
162c5f01b2fSopenharmony_ci  CHECK_ERROR(first_crash,
163c5f01b2fSopenharmony_ci              "Crashed in crash signal handler. This is a bug in the fuzzer.");
164c5f01b2fSopenharmony_ci
165c5f01b2fSopenharmony_ci  first_crash = false;
166c5f01b2fSopenharmony_ci  write_extra_stats();
167c5f01b2fSopenharmony_ci}
168c5f01b2fSopenharmony_ci
169c5f01b2fSopenharmony_ci// If the user has specified an extra_stats_file through the environment
170c5f01b2fSopenharmony_ci// variable AFL_DRIVER_EXTRA_STATS_FILENAME, then perform necessary set up
171c5f01b2fSopenharmony_ci// to write stats to it on exit. If no file is specified, do nothing. Otherwise
172c5f01b2fSopenharmony_ci// install signal and exit handlers to write to the file when the process exits.
173c5f01b2fSopenharmony_ci// Then if the file doesn't exist create it and set extra stats to 0. But if it
174c5f01b2fSopenharmony_ci// does exist then read the initial values of the extra stats from the file
175c5f01b2fSopenharmony_ci// and check that the file is writable.
176c5f01b2fSopenharmony_cistatic void maybe_initialize_extra_stats() {
177c5f01b2fSopenharmony_ci  // If AFL_DRIVER_EXTRA_STATS_FILENAME isn't set then we have nothing to do.
178c5f01b2fSopenharmony_ci  char *extra_stats_filename = getenv("AFL_DRIVER_EXTRA_STATS_FILENAME");
179c5f01b2fSopenharmony_ci  if (!extra_stats_filename)
180c5f01b2fSopenharmony_ci    return;
181c5f01b2fSopenharmony_ci
182c5f01b2fSopenharmony_ci  // Open the file and find the previous peak_rss_mb value.
183c5f01b2fSopenharmony_ci  // This is necessary because the fuzzing process is restarted after N
184c5f01b2fSopenharmony_ci  // iterations are completed. So we may need to get this value from a previous
185c5f01b2fSopenharmony_ci  // process to be accurate.
186c5f01b2fSopenharmony_ci  extra_stats_file = fopen(extra_stats_filename, "r");
187c5f01b2fSopenharmony_ci
188c5f01b2fSopenharmony_ci  // If extra_stats_file already exists: read old stats from it.
189c5f01b2fSopenharmony_ci  if (extra_stats_file) {
190c5f01b2fSopenharmony_ci    int matches = fscanf(extra_stats_file, kExtraStatsFormatString,
191c5f01b2fSopenharmony_ci                         &previous_peak_rss, &slowest_unit_time_secs);
192c5f01b2fSopenharmony_ci
193c5f01b2fSopenharmony_ci    // Make sure we have read a real extra stats file and that we have used it
194c5f01b2fSopenharmony_ci    // to set slowest_unit_time_secs and previous_peak_rss.
195c5f01b2fSopenharmony_ci    CHECK_ERROR(matches == kNumExtraStats, "Extra stats file is corrupt");
196c5f01b2fSopenharmony_ci
197c5f01b2fSopenharmony_ci    CHECK_ERROR(fclose(extra_stats_file) == 0, "Failed to close file");
198c5f01b2fSopenharmony_ci
199c5f01b2fSopenharmony_ci    // Now open the file for writing.
200c5f01b2fSopenharmony_ci    extra_stats_file = fopen(extra_stats_filename, "w");
201c5f01b2fSopenharmony_ci    CHECK_ERROR(extra_stats_file,
202c5f01b2fSopenharmony_ci                "Failed to open extra stats file for writing");
203c5f01b2fSopenharmony_ci  } else {
204c5f01b2fSopenharmony_ci    // Looks like this is the first time in a fuzzing job this is being called.
205c5f01b2fSopenharmony_ci    extra_stats_file = fopen(extra_stats_filename, "w+");
206c5f01b2fSopenharmony_ci    CHECK_ERROR(extra_stats_file, "failed to create extra stats file");
207c5f01b2fSopenharmony_ci  }
208c5f01b2fSopenharmony_ci
209c5f01b2fSopenharmony_ci  // Make sure that crash_handler gets called on any kind of fatal error.
210c5f01b2fSopenharmony_ci  int crash_signals[] = {SIGSEGV, SIGBUS, SIGABRT, SIGILL, SIGFPE,  SIGINT,
211c5f01b2fSopenharmony_ci                         SIGTERM};
212c5f01b2fSopenharmony_ci
213c5f01b2fSopenharmony_ci  const size_t num_signals = sizeof(crash_signals) / sizeof(crash_signals[0]);
214c5f01b2fSopenharmony_ci
215c5f01b2fSopenharmony_ci  for (size_t idx = 0; idx < num_signals; idx++)
216c5f01b2fSopenharmony_ci    SetSigaction(crash_signals[idx], crash_handler);
217c5f01b2fSopenharmony_ci
218c5f01b2fSopenharmony_ci  // Make sure it gets called on other kinds of exits.
219c5f01b2fSopenharmony_ci  atexit(write_extra_stats);
220c5f01b2fSopenharmony_ci}
221c5f01b2fSopenharmony_ci
222c5f01b2fSopenharmony_ci// If the user asks us to duplicate stderr, then do it.
223c5f01b2fSopenharmony_cistatic void maybe_duplicate_stderr() {
224c5f01b2fSopenharmony_ci  char* stderr_duplicate_filename =
225c5f01b2fSopenharmony_ci      getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
226c5f01b2fSopenharmony_ci
227c5f01b2fSopenharmony_ci  if (!stderr_duplicate_filename)
228c5f01b2fSopenharmony_ci    return;
229c5f01b2fSopenharmony_ci
230c5f01b2fSopenharmony_ci  FILE* stderr_duplicate_stream =
231c5f01b2fSopenharmony_ci      freopen(stderr_duplicate_filename, "a+", stderr);
232c5f01b2fSopenharmony_ci
233c5f01b2fSopenharmony_ci  if (!stderr_duplicate_stream) {
234c5f01b2fSopenharmony_ci    fprintf(
235c5f01b2fSopenharmony_ci        stderr,
236c5f01b2fSopenharmony_ci        "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
237c5f01b2fSopenharmony_ci    abort();
238c5f01b2fSopenharmony_ci  }
239c5f01b2fSopenharmony_ci}
240c5f01b2fSopenharmony_ci
241c5f01b2fSopenharmony_ciint main(int argc, char **argv) {
242c5f01b2fSopenharmony_ci  fprintf(stderr, "======================= INFO =========================\n"
243c5f01b2fSopenharmony_ci                  "This binary is built for AFL-fuzz.\n"
244c5f01b2fSopenharmony_ci                  "To run the target function on a single input execute this:\n"
245c5f01b2fSopenharmony_ci                  "  %s < INPUT_FILE\n"
246c5f01b2fSopenharmony_ci                  "To run the fuzzing execute this:\n"
247c5f01b2fSopenharmony_ci                  "  afl-fuzz [afl-flags] %s [N] "
248c5f01b2fSopenharmony_ci                  "-- run N fuzzing iterations before "
249c5f01b2fSopenharmony_ci                  "re-spawning the process (default: 1000)\n"
250c5f01b2fSopenharmony_ci                  "======================================================\n",
251c5f01b2fSopenharmony_ci          argv[0], argv[0]);
252c5f01b2fSopenharmony_ci  if (LLVMFuzzerInitialize)
253c5f01b2fSopenharmony_ci    LLVMFuzzerInitialize(&argc, &argv);
254c5f01b2fSopenharmony_ci  // Do any other expensive one-time initialization here.
255c5f01b2fSopenharmony_ci
256c5f01b2fSopenharmony_ci  maybe_duplicate_stderr();
257c5f01b2fSopenharmony_ci  maybe_initialize_extra_stats();
258c5f01b2fSopenharmony_ci
259c5f01b2fSopenharmony_ci  __afl_manual_init();
260c5f01b2fSopenharmony_ci
261c5f01b2fSopenharmony_ci  int N = 1000;
262c5f01b2fSopenharmony_ci  if (argc >= 2)
263c5f01b2fSopenharmony_ci    N = atoi(argv[1]);
264c5f01b2fSopenharmony_ci  assert(N > 0);
265c5f01b2fSopenharmony_ci  time_t unit_time_secs;
266c5f01b2fSopenharmony_ci  int num_runs = 0;
267c5f01b2fSopenharmony_ci  while (__afl_persistent_loop(N)) {
268c5f01b2fSopenharmony_ci    ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize);
269c5f01b2fSopenharmony_ci    if (n_read > 0) {
270c5f01b2fSopenharmony_ci      // Copy AflInputBuf into a separate buffer to let asan find buffer
271c5f01b2fSopenharmony_ci      // overflows. Don't use unique_ptr/etc to avoid extra dependencies.
272c5f01b2fSopenharmony_ci      uint8_t *copy = new uint8_t[n_read];
273c5f01b2fSopenharmony_ci      memcpy(copy, AflInputBuf, n_read);
274c5f01b2fSopenharmony_ci
275c5f01b2fSopenharmony_ci      struct timeval unit_start_time;
276c5f01b2fSopenharmony_ci      CHECK_ERROR(gettimeofday(&unit_start_time, NULL) == 0,
277c5f01b2fSopenharmony_ci                  "Calling gettimeofday failed");
278c5f01b2fSopenharmony_ci
279c5f01b2fSopenharmony_ci      num_runs++;
280c5f01b2fSopenharmony_ci      LLVMFuzzerTestOneInput(copy, n_read);
281c5f01b2fSopenharmony_ci
282c5f01b2fSopenharmony_ci      struct timeval unit_stop_time;
283c5f01b2fSopenharmony_ci      CHECK_ERROR(gettimeofday(&unit_stop_time, NULL) == 0,
284c5f01b2fSopenharmony_ci                  "Calling gettimeofday failed");
285c5f01b2fSopenharmony_ci
286c5f01b2fSopenharmony_ci      // Update slowest_unit_time_secs if we see a new max.
287c5f01b2fSopenharmony_ci      unit_time_secs = unit_stop_time.tv_sec - unit_start_time.tv_sec;
288c5f01b2fSopenharmony_ci      if (slowest_unit_time_secs < unit_time_secs)
289c5f01b2fSopenharmony_ci        slowest_unit_time_secs = unit_time_secs;
290c5f01b2fSopenharmony_ci
291c5f01b2fSopenharmony_ci      delete[] copy;
292c5f01b2fSopenharmony_ci    }
293c5f01b2fSopenharmony_ci  }
294c5f01b2fSopenharmony_ci  fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);
295c5f01b2fSopenharmony_ci}
296