diff options
author | Jonathan Metzman <metzman@chromium.org> | 2019-04-18 18:49:11 +0000 |
---|---|---|
committer | Jonathan Metzman <metzman@chromium.org> | 2019-04-18 18:49:11 +0000 |
commit | 9b65419587ed0457016be511619dcb94a21fe5ff (patch) | |
tree | 73aa941761130bdc11e0b91c68a06a1c390126b0 /lib/fuzzer/afl/afl_driver.cpp | |
parent | 80bfad5126fd9e41dd3aa03f8cde6642789c5962 (diff) | |
download | compiler-rt-9b65419587ed0457016be511619dcb94a21fe5ff.tar.gz |
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
Diffstat (limited to 'lib/fuzzer/afl/afl_driver.cpp')
-rw-r--r-- | lib/fuzzer/afl/afl_driver.cpp | 90 |
1 files changed, 75 insertions, 15 deletions
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 <assert.h> @@ -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<void *>(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); } |