summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonathan Metzman <metzman@chromium.org>2019-04-18 18:49:11 +0000
committerJonathan Metzman <metzman@chromium.org>2019-04-18 18:49:11 +0000
commit9b65419587ed0457016be511619dcb94a21fe5ff (patch)
tree73aa941761130bdc11e0b91c68a06a1c390126b0
parent80bfad5126fd9e41dd3aa03f8cde6642789c5962 (diff)
downloadcompiler-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
-rw-r--r--lib/fuzzer/afl/afl_driver.cpp90
-rw-r--r--test/fuzzer/AFLDriverTest.cpp19
-rw-r--r--test/fuzzer/afl-driver-close-fd-mask.test31
-rw-r--r--test/fuzzer/afl-driver.test18
4 files changed, 125 insertions, 33 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);
}
diff --git a/test/fuzzer/AFLDriverTest.cpp b/test/fuzzer/AFLDriverTest.cpp
index d2937d004..84b5f9f6b 100644
--- a/test/fuzzer/AFLDriverTest.cpp
+++ b/test/fuzzer/AFLDriverTest.cpp
@@ -2,28 +2,33 @@
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
-// Contains dummy functions used to avoid dependency on AFL.
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
+// Dummy functions used to avoid dependency on AFL.
extern "C" void __afl_manual_init() {}
extern "C" int __afl_persistent_loop(unsigned int N) {
static int Count = N;
- fprintf(stderr, "__afl_persistent_loop calle, Count = %d\n", Count);
- if (Count--) return 1;
- return 0;
+ fprintf(stderr, "__afl_persistent_loop called, Count = %d\n", Count);
+ return Count--;
}
// This declaration exists to prevent the Darwin linker
// from complaining about this being a missing weak symbol.
extern "C" int LLVMFuzzerInitialize(int *argc, char ***argv) {
- fprintf(stderr, "LLVMFuzzerInitialize called\n");
return 0;
}
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
- fprintf(stderr, "LLVMFuzzerTestOneInput called; Size = %zd\n", Size);
- return 0;
+ puts("STDOUT MESSAGE");
+ fflush(stdout);
+ fprintf(stderr, "STDERR MESSAGE\n"
+ "LLVMFuzzerTestOneInput called; Size = %zd\n",
+ Size);
+ if (Size < 4)
+ return 0;
+
+ return Data[Size];
}
diff --git a/test/fuzzer/afl-driver-close-fd-mask.test b/test/fuzzer/afl-driver-close-fd-mask.test
new file mode 100644
index 000000000..71f74e27e
--- /dev/null
+++ b/test/fuzzer/afl-driver-close-fd-mask.test
@@ -0,0 +1,31 @@
+REQUIRES: linux
+RUN: %no_fuzzer_cpp_compiler %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest
+
+; Test that not specifying AFL_DRIVER_CLOSE_FD_MASK works as intended.
+RUN: echo -n "abc" > %t.file3
+RUN: unset AFL_DRIVER_CLOSE_FD_MASK
+RUN: %run %t-AFLDriverTest < %t.file3 2>&1 | FileCheck %s --check-prefixes=STDERR,STDOUT
+STDOUT: STDOUT MESSAGE
+STDERR: STDERR MESSAGE
+
+; Test that stdout is closed properly.
+RUN: AFL_DRIVER_CLOSE_FD_MASK=1 %run %t-AFLDriverTest < %t.file3 2>&1 | FileCheck %s --check-prefixes=NOT_STDOUT,STDERR
+NOT_STDOUT-NOT: STDOUT MESSAGE
+
+; Test that stderr is closed properly.
+RUN: AFL_DRIVER_CLOSE_FD_MASK=2 %run %t-AFLDriverTest < %t.file3 2>&1 | FileCheck %s --check-prefixes=NOT_STDERR,STDOUT
+NOT_STDERR-NOT: STDERR MESSAGE
+
+; Test that both are closed properly.
+RUN: AFL_DRIVER_CLOSE_FD_MASK=3 %run %t-AFLDriverTest < %t.file3 2>&1 | FileCheck %s --check-prefixes=NOT_STDERR,NOT_STDOUT
+
+; Test that a stack is printed when we close stderr
+RUN: echo -n "abcd" > %t.file4
+RUN: AFL_DRIVER_CLOSE_FD_MASK=2 not %run %t-AFLDriverTest < %t.file4 2>&1 | FileCheck %s --check-prefixes=ASAN_CRASH,STDOUT,NOT_STDERR
+ASAN_CRASH: ERROR: AddressSanitizer
+
+; Test that a stack is written to the stderr duplicate file when we close stderr
+; and specify a duplicate.
+RUN: rm -f %t.stderr
+RUN: AFL_DRIVER_STDERR_DUPLICATE_FILENAME=%t.stderr AFL_DRIVER_CLOSE_FD_MASK=2 not %run %t-AFLDriverTest < %t.file4
+RUN: cat %t.stderr | FileCheck %s --check-prefixes=ASAN_CRASH,NOT_STDERR
diff --git a/test/fuzzer/afl-driver.test b/test/fuzzer/afl-driver.test
index 552bafb0b..58f422f1e 100644
--- a/test/fuzzer/afl-driver.test
+++ b/test/fuzzer/afl-driver.test
@@ -3,27 +3,23 @@ REQUIRES: linux
RUN: %no_fuzzer_cpp_compiler %S/AFLDriverTest.cpp %libfuzzer_src/afl/afl_driver.cpp -o %t-AFLDriverTest
RUN: echo -n "abc" > %t.file3
-RUN: echo -n "abcd" > %t.file4
-
RUN: %run %t-AFLDriverTest < %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK1
-CHECK1: __afl_persistent_loop calle, Count = 1000
+CHECK1: __afl_persistent_loop called, Count = 1000
CHECK1: LLVMFuzzerTestOneInput called; Size = 3
-
RUN: %run %t-AFLDriverTest < %t.file3 -42 2>&1 | FileCheck %s --check-prefix=CHECK2
-CHECK2: __afl_persistent_loop calle, Count = 42
+CHECK2: __afl_persistent_loop called, Count = 42
CHECK2: LLVMFuzzerTestOneInput called; Size = 3
-
RUN: %run %t-AFLDriverTest < %t.file3 666 2>&1 | FileCheck %s --check-prefix=CHECK3
CHECK3: WARNING: using the deprecated call style
-CHECK3: __afl_persistent_loop calle, Count = 666
+CHECK3: __afl_persistent_loop called, Count = 666
CHECK3: LLVMFuzzerTestOneInput called; Size = 3
-
RUN: %run %t-AFLDriverTest %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK4
CHECK4: LLVMFuzzerTestOneInput called; Size = 3
-RUN: %run %t-AFLDriverTest %t.file3 %t.file4 2>&1 | FileCheck %s --check-prefix=CHECK5
-CHECK5: LLVMFuzzerTestOneInput called; Size = 3
-CHECK5: LLVMFuzzerTestOneInput called; Size = 4
+RUN: echo -n "ab" > %t.file2
+RUN: %run %t-AFLDriverTest %t.file2 %t.file3 2>&1 | FileCheck %s --check-prefix=CHECK5
+CHECK5: LLVMFuzzerTestOneInput called; Size = 2
+CHECK5: LLVMFuzzerTestOneInput called; Size = 3 \ No newline at end of file