Skip to content

Commit 3992781

Browse files
author
metzman
committed
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/lib/fuzzer@358703 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent a3f5312 commit 3992781

File tree

1 file changed

+75
-15
lines changed

1 file changed

+75
-15
lines changed

afl/afl_driver.cpp

+75-15
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,14 @@ clang++ afl_driver.cpp test_fuzzer.o afl-llvm-rt.o.o
3131
rm -rf IN OUT; mkdir IN OUT; echo z > IN/z;
3232
$AFL_HOME/afl-fuzz -i IN -o OUT ./a.out
3333
################################################################################
34-
AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this environment variable
35-
*appends* stderr to the file specified. If the file does not exist, it is
36-
created. This is useful for getting stack traces (when using ASAN for example)
37-
or original error messages on hard to reproduce bugs.
34+
AFL_DRIVER_STDERR_DUPLICATE_FILENAME: Setting this *appends* stderr to the file
35+
specified. If the file does not exist, it is created. This is useful for getting
36+
stack traces (when using ASAN for example) or original error messages on hard
37+
to reproduce bugs. Note that any content written to stderr will be written to
38+
this file instead of stderr's usual location.
39+
40+
AFL_DRIVER_CLOSE_FD_MASK: Similar to libFuzzer's -close_fd_mask behavior option.
41+
If 1, close stdout at startup. If 2 close stderr; if 3 close both.
3842
3943
*/
4044
#include <assert.h>
@@ -97,16 +101,24 @@ static volatile char suppress_warning2 = AFL_PERSISTENT[0];
97101

98102
// Notify AFL about deferred forkserver.
99103
static volatile char AFL_DEFER_FORKSVR[] = "##SIG_AFL_DEFER_FORKSRV##";
100-
extern "C" void __afl_manual_init();
104+
extern "C" void __afl_manual_init();
101105
static volatile char suppress_warning1 = AFL_DEFER_FORKSVR[0];
102106

103107
// Input buffer.
104108
static const size_t kMaxAflInputSize = 1 << 20;
105109
static uint8_t AflInputBuf[kMaxAflInputSize];
106110

111+
// Use this optionally defined function to output sanitizer messages even if
112+
// user asks to close stderr.
113+
__attribute__((weak)) extern "C" void __sanitizer_set_report_fd(void *);
114+
115+
// Keep track of where stderr content is being written to, so that
116+
// dup_and_close_stderr can use the correct one.
117+
static FILE *output_file = stderr;
118+
107119
// Experimental feature to use afl_driver without AFL's deferred mode.
108120
// Needs to run before __afl_auto_init.
109-
__attribute__((constructor(0))) void __decide_deferred_forkserver(void) {
121+
__attribute__((constructor(0))) static void __decide_deferred_forkserver(void) {
110122
if (getenv("AFL_DRIVER_DONT_DEFER")) {
111123
if (unsetenv("__AFL_DEFER_FORKSRV")) {
112124
perror("Failed to unset __AFL_DEFER_FORKSRV");
@@ -117,13 +129,13 @@ __attribute__((constructor(0))) void __decide_deferred_forkserver(void) {
117129

118130
// If the user asks us to duplicate stderr, then do it.
119131
static void maybe_duplicate_stderr() {
120-
char* stderr_duplicate_filename =
132+
char *stderr_duplicate_filename =
121133
getenv("AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
122134

123135
if (!stderr_duplicate_filename)
124136
return;
125137

126-
FILE* stderr_duplicate_stream =
138+
FILE *stderr_duplicate_stream =
127139
freopen(stderr_duplicate_filename, "a+", stderr);
128140

129141
if (!stderr_duplicate_stream) {
@@ -132,6 +144,54 @@ static void maybe_duplicate_stderr() {
132144
"Failed to duplicate stderr to AFL_DRIVER_STDERR_DUPLICATE_FILENAME");
133145
abort();
134146
}
147+
output_file = stderr_duplicate_stream;
148+
}
149+
150+
// Most of these I/O functions were inspired by/copied from libFuzzer's code.
151+
static void discard_output(int fd) {
152+
FILE *temp = fopen("/dev/null", "w");
153+
if (!temp)
154+
abort();
155+
dup2(fileno(temp), fd);
156+
fclose(temp);
157+
}
158+
159+
static void close_stdout() { discard_output(STDOUT_FILENO); }
160+
161+
// Prevent the targeted code from writing to "stderr" but allow sanitizers and
162+
// this driver to do so.
163+
static void dup_and_close_stderr() {
164+
int output_fileno = fileno(output_file);
165+
int output_fd = dup(output_fileno);
166+
if (output_fd <= 0)
167+
abort();
168+
FILE *new_output_file = fdopen(output_fd, "w");
169+
if (!new_output_file)
170+
abort();
171+
if (!__sanitizer_set_report_fd)
172+
return;
173+
__sanitizer_set_report_fd(reinterpret_cast<void *>(output_fd));
174+
discard_output(output_fileno);
175+
}
176+
177+
static void Printf(const char *Fmt, ...) {
178+
va_list ap;
179+
va_start(ap, Fmt);
180+
vfprintf(output_file, Fmt, ap);
181+
va_end(ap);
182+
fflush(output_file);
183+
}
184+
185+
// Close stdout and/or stderr if user asks for it.
186+
static void maybe_close_fd_mask() {
187+
char *fd_mask_str = getenv("AFL_DRIVER_CLOSE_FD_MASK");
188+
if (!fd_mask_str)
189+
return;
190+
int fd_mask = atoi(fd_mask_str);
191+
if (fd_mask & 2)
192+
dup_and_close_stderr();
193+
if (fd_mask & 1)
194+
close_stdout();
135195
}
136196

137197
// 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) {
142202
}
143203

144204
// Execute any files provided as parameters.
145-
int ExecuteFilesOnyByOne(int argc, char **argv) {
205+
static int ExecuteFilesOnyByOne(int argc, char **argv) {
146206
for (int i = 1; i < argc; i++) {
147207
std::ifstream in(argv[i], std::ios::binary);
148208
in.seekg(0, in.end);
@@ -161,7 +221,7 @@ int ExecuteFilesOnyByOne(int argc, char **argv) {
161221
}
162222

163223
int main(int argc, char **argv) {
164-
fprintf(stderr,
224+
Printf(
165225
"======================= INFO =========================\n"
166226
"This binary is built for AFL-fuzz.\n"
167227
"To run the target function on individual input(s) execute this:\n"
@@ -174,21 +234,21 @@ int main(int argc, char **argv) {
174234
"re-spawning the process (default: 1000)\n"
175235
"======================================================\n",
176236
argv[0], argv[0], argv[0]);
237+
238+
maybe_duplicate_stderr();
239+
maybe_close_fd_mask();
177240
if (LLVMFuzzerInitialize)
178241
LLVMFuzzerInitialize(&argc, &argv);
179242
// Do any other expensive one-time initialization here.
180243

181-
maybe_duplicate_stderr();
182-
183244
if (!getenv("AFL_DRIVER_DONT_DEFER"))
184245
__afl_manual_init();
185246

186247
int N = 1000;
187248
if (argc == 2 && argv[1][0] == '-')
188249
N = atoi(argv[1] + 1);
189250
else if(argc == 2 && (N = atoi(argv[1])) > 0)
190-
fprintf(stderr, "WARNING: using the deprecated call style `%s %d`\n",
191-
argv[0], N);
251+
Printf("WARNING: using the deprecated call style `%s %d`\n", argv[0], N);
192252
else if (argc > 1)
193253
return ExecuteFilesOnyByOne(argc, argv);
194254

@@ -212,5 +272,5 @@ int main(int argc, char **argv) {
212272
delete[] copy;
213273
}
214274
}
215-
fprintf(stderr, "%s: successfully executed %d input(s)\n", argv[0], num_runs);
275+
Printf("%s: successfully executed %d input(s)\n", argv[0], num_runs);
216276
}

0 commit comments

Comments
 (0)