From 58d43607862096aeb32d72173911c9df244a30f1 Mon Sep 17 00:00:00 2001 From: Chandler Carruth Date: Sat, 19 Jan 2019 08:50:56 +0000 Subject: Update the file headers across all of the LLVM projects in the monorepo to reflect the new license. We understand that people may be surprised that we're moving the header entirely to discuss the new license. We checked this carefully with the Foundation's lawyer and we believe this is the correct approach. Essentially, all code in the project is now made available by the LLVM project under our new license, so you will see that the license headers include that license only. Some of our contributors have contributed code under our old license, and accordingly, we have retained a copy of our old license notice in the top-level files in each project and repository. git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@351636 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/afl/afl_driver.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) (limited to 'lib/fuzzer/afl') diff --git a/lib/fuzzer/afl/afl_driver.cpp b/lib/fuzzer/afl/afl_driver.cpp index 5a10c0d27..37f47b0c8 100644 --- a/lib/fuzzer/afl/afl_driver.cpp +++ b/lib/fuzzer/afl/afl_driver.cpp @@ -1,9 +1,8 @@ //===- 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. +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception //===----------------------------------------------------------------------===// /* This file allows to fuzz libFuzzer-style target functions -- cgit v1.2.1 From 28bdb808f5c1c2aef1a2925ac6562dda1f77e016 Mon Sep 17 00:00:00 2001 From: Jonathan Metzman Date: Mon, 28 Jan 2019 17:15:49 +0000 Subject: [fuzzer][afl] Remove AFL_DRIVER_EXTRA_STATS_FILENAME Summary: Remove this feature as it is unused, buggy, and not worth correcting since the forkserver makes it difficult. Reviewers: morehouse, jfb Reviewed By: morehouse Differential Revision: https://reviews.llvm.org/D57308 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@352392 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/afl/afl_driver.cpp | 169 +----------------------------------------- 1 file changed, 4 insertions(+), 165 deletions(-) (limited to 'lib/fuzzer/afl') diff --git a/lib/fuzzer/afl/afl_driver.cpp b/lib/fuzzer/afl/afl_driver.cpp index 37f47b0c8..18101aa4d 100644 --- a/lib/fuzzer/afl/afl_driver.cpp +++ b/lib/fuzzer/afl/afl_driver.cpp @@ -31,32 +31,18 @@ clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o 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. +AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this environment variable +*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. */ #include #include -#include #include #include #include #include -#include -#include #include #include @@ -98,17 +84,6 @@ statistics from the file. If that fails then the process will quit. #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 occurred 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, "%s\n", (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); @@ -129,14 +104,6 @@ static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0]; 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"; - // Experimental feature to use afl_driver without AFL's deferred mode. // Needs to run before __afl_auto_init. __attribute__((constructor(0))) void __decide_deferred_forkserver(void) { @@ -148,117 +115,6 @@ __attribute__((constructor(0))) void __decide_deferred_forkserver(void) { } } -// Copied from FuzzerUtil.cpp. -size_t GetPeakRSSMb() { - struct rusage usage; - if (getrusage(RUSAGE_SELF, &usage)) - return 0; - if (LIBFUZZER_LINUX || LIBFUZZER_NETBSD || LIBFUZZER_FREEBSD || - LIBFUZZER_OPENBSD) { - // 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 = @@ -323,7 +179,6 @@ int main(int argc, char **argv) { // Do any other expensive one-time initialization here. maybe_duplicate_stderr(); - maybe_initialize_extra_stats(); if (!getenv("AFL_DRIVER_DONT_DEFER")) __afl_manual_init(); @@ -344,7 +199,6 @@ int main(int argc, char **argv) { uint8_t dummy_input[1] = {0}; LLVMFuzzerTestOneInput(dummy_input, 1); - time_t unit_time_secs; int num_runs = 0; while (__afl_persistent_loop(N)) { ssize_t n_read = read(0, AflInputBuf, kMaxAflInputSize); @@ -353,23 +207,8 @@ int main(int argc, char **argv) { // 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; } } -- cgit v1.2.1 From 9b65419587ed0457016be511619dcb94a21fe5ff Mon Sep 17 00:00:00 2001 From: Jonathan Metzman Date: Thu, 18 Apr 2019 18:49:11 +0000 Subject: Summary: Add close_fd_mask functionality to AFL driver. Summary: Add support for env var AFL_DRIVER_CLOSE_FD_MASK which behaves the same as libFuzzer's -close_fd_mask=1. Also add tests. Reviewers: kcc, vitalybuka, morehouse Reviewed By: morehouse Subscribers: #sanitizers, llvm-commits Tags: #sanitizers, #llvm Differential Revision: https://reviews.llvm.org/D60334 git-svn-id: https://llvm.org/svn/llvm-project/compiler-rt/trunk@358703 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/fuzzer/afl/afl_driver.cpp | 90 +++++++++++++++++++++++++++++++++++-------- 1 file changed, 75 insertions(+), 15 deletions(-) (limited to 'lib/fuzzer/afl') diff --git a/lib/fuzzer/afl/afl_driver.cpp b/lib/fuzzer/afl/afl_driver.cpp index 18101aa4d..f21dfc58f 100644 --- a/lib/fuzzer/afl/afl_driver.cpp +++ b/lib/fuzzer/afl/afl_driver.cpp @@ -31,10 +31,14 @@ clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o rm -rf IN OUT; mkdir IN OUT; echo z > IN/z; $AFL_HOME/afl-fuzz -i IN -o OUT ./a.out ################################################################################ -AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this environment variable -*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_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. Note that any content written to stderr will be written to +this file instead of stderr's usual location. + +AFL_DRIVER_CLOSE_FD_MASK: Similar to libFuzzer's -close_fd_mask behavior option. +If 1, close stdout at startup. If 2 close stderr; if 3 close both. */ #include @@ -97,16 +101,24 @@ 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(); +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]; +// Use this optionally defined function to output sanitizer messages even if +// user asks to close stderr. +__attribute__((weak)) extern "C" void __sanitizer_set_report_fd(void *); + +// Keep track of where stderr content is being written to, so that +// dup_and_close_stderr can use the correct one. +static FILE *output_file = stderr; + // Experimental feature to use afl_driver without AFL's deferred mode. // Needs to run before __afl_auto_init. -__attribute__((constructor(0))) void __decide_deferred_forkserver(void) { +__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) { if (getenv("AFL_DRIVER_DONT_DEFER")) { if (unsetenv("__AFL_DEFER_FORKSRV")) { perror("Failed to unset __AFL_DEFER_FORKSRV"); @@ -117,13 +129,13 @@ __attribute__((constructor(0))) void __decide_deferred_forkserver(void) { // If the user asks us to duplicate stderr, then do it. static void maybe_duplicate_stderr() { - char* stderr_duplicate_filename = + char *stderr_duplicate_filename = getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); if (!stderr_duplicate_filename) return; - FILE* stderr_duplicate_stream = + FILE *stderr_duplicate_stream = freopen(stderr_duplicate_filename, "a+", stderr); if (!stderr_duplicate_stream) { @@ -132,6 +144,54 @@ static void maybe_duplicate_stderr() { "Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME"); abort(); } + output_file = stderr_duplicate_stream; +} + +// Most of these I/O functions were inspired by/copied from libFuzzer's code. +static void discard_output(int fd) { + FILE *temp = fopen("/dev/null", "w"); + if (!temp) + abort(); + dup2(fileno(temp), fd); + fclose(temp); +} + +static void close_stdout() { discard_output(STDOUT_FILENO); } + +// Prevent the targeted code from writing to "stderr" but allow sanitizers and +// this driver to do so. +static void dup_and_close_stderr() { + int output_fileno = fileno(output_file); + int output_fd = dup(output_fileno); + if (output_fd <= 0) + abort(); + FILE *new_output_file = fdopen(output_fd, "w"); + if (!new_output_file) + abort(); + if (!__sanitizer_set_report_fd) + return; + __sanitizer_set_report_fd(reinterpret_cast(output_fd)); + discard_output(output_fileno); +} + +static void Printf(const char *Fmt, ...) { + va_list ap; + va_start(ap, Fmt); + vfprintf(output_file, Fmt, ap); + va_end(ap); + fflush(output_file); +} + +// Close stdout and/or stderr if user asks for it. +static void maybe_close_fd_mask() { + char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK"); + if (!fd_mask_str) + return; + int fd_mask = atoi(fd_mask_str); + if (fd_mask & 2) + dup_and_close_stderr(); + if (fd_mask & 1) + close_stdout(); } // Define LLVMFuzzerMutate to avoid link failures for targets that use it @@ -142,7 +202,7 @@ extern "C" size_t LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize) { } // Execute any files provided as parameters. -int ExecuteFilesOnyByOne(int argc, char **argv) { +static int ExecuteFilesOnyByOne(int argc, char **argv) { for (int i = 1; i < argc; i++) { std::ifstream in(argv[i], std::ios::binary); in.seekg(0, in.end); @@ -161,7 +221,7 @@ int ExecuteFilesOnyByOne(int argc, char **argv) { } int main(int argc, char **argv) { - fprintf(stderr, + Printf( "======================= INFO =========================\n" "This binary is built for AFL-fuzz.\n" "To run the target function on individual input(s) execute this:\n" @@ -174,12 +234,13 @@ int main(int argc, char **argv) { "re-spawning the process (default: 1000)\n" "======================================================\n", argv[0], argv[0], argv[0]); + + maybe_duplicate_stderr(); + maybe_close_fd_mask(); if (LLVMFuzzerInitialize) LLVMFuzzerInitialize(&argc, &argv); // Do any other expensive one-time initialization here. - maybe_duplicate_stderr(); - if (!getenv("AFL_DRIVER_DONT_DEFER")) __afl_manual_init(); @@ -187,8 +248,7 @@ int main(int argc, char **argv) { 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); + Printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N); else if (argc > 1) return ExecuteFilesOnyByOne(argc, argv); @@ -212,5 +272,5 @@ int main(int argc, char **argv) { delete[] copy; } } - fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs); + Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs); } -- cgit v1.2.1