1
1
use core:: ffi:: c_int;
2
+ #[ cfg( unix) ]
3
+ use std:: io:: Write ;
2
4
use std:: {
3
5
fmt:: Debug ,
4
6
fs:: File ,
5
7
net:: TcpListener ,
8
+ str:: FromStr ,
6
9
time:: { SystemTime , UNIX_EPOCH } ,
7
10
} ;
8
- #[ cfg( unix) ]
9
- use std:: {
10
- io:: Write ,
11
- os:: fd:: { AsRawFd , FromRawFd , IntoRawFd } ,
12
- } ;
13
11
14
12
use libafl:: {
15
13
corpus:: Corpus ,
@@ -37,6 +35,31 @@ use libafl_bolts::{
37
35
38
36
use crate :: { feedbacks:: LibfuzzerCrashCauseMetadata , fuzz_with, options:: LibfuzzerOptions } ;
39
37
38
+ fn destroy_output_fds ( options : & LibfuzzerOptions ) {
39
+ #[ cfg( unix) ]
40
+ {
41
+ use std:: os:: fd:: AsRawFd ;
42
+
43
+ if options. tui ( ) {
44
+ let file_null = File :: open ( "/dev/null" ) . unwrap ( ) ;
45
+ unsafe {
46
+ libc:: dup2 ( file_null. as_raw_fd ( ) , 1 ) ;
47
+ libc:: dup2 ( file_null. as_raw_fd ( ) , 2 ) ;
48
+ }
49
+ } else if options. close_fd_mask ( ) != 0 {
50
+ let file_null = File :: open ( "/dev/null" ) . unwrap ( ) ;
51
+ unsafe {
52
+ if options. close_fd_mask ( ) & 1 != 0 {
53
+ libc:: dup2 ( file_null. as_raw_fd ( ) , 1 ) ;
54
+ }
55
+ if options. close_fd_mask ( ) & 2 != 0 {
56
+ libc:: dup2 ( file_null. as_raw_fd ( ) , 2 ) ;
57
+ }
58
+ }
59
+ }
60
+ }
61
+ }
62
+
40
63
fn do_fuzz < F , ST , E , S , EM > (
41
64
options : & LibfuzzerOptions ,
42
65
fuzzer : & mut F ,
@@ -93,6 +116,7 @@ fn fuzz_single_forking<M>(
93
116
where
94
117
M : Monitor + Debug ,
95
118
{
119
+ destroy_output_fds ( options) ;
96
120
fuzz_with ! ( options, harness, do_fuzz, |fuzz_single| {
97
121
let ( state, mgr) : (
98
122
Option <StdState <_, _, _, _>>,
@@ -109,24 +133,13 @@ where
109
133
}
110
134
} ,
111
135
} ;
112
- #[ cfg( unix) ]
113
- {
114
- if options. close_fd_mask( ) != 0 {
115
- let file_null = File :: open( "/dev/null" ) ?;
116
- unsafe {
117
- if options. close_fd_mask( ) & 1 != 0 {
118
- libc:: dup2( file_null. as_raw_fd( ) , 1 ) ;
119
- }
120
- if options. close_fd_mask( ) & 2 != 0 {
121
- libc:: dup2( file_null. as_raw_fd( ) , 2 ) ;
122
- }
123
- }
124
- }
125
- }
126
136
crate :: start_fuzzing_single( fuzz_single, state, mgr)
127
137
} )
128
138
}
129
139
140
+ /// Communicate the selected port to subprocesses
141
+ const PORT_PROVIDER_VAR : & str = "_LIBAFL_LIBFUZZER_FORK_PORT" ;
142
+
130
143
fn fuzz_many_forking < M > (
131
144
options : & LibfuzzerOptions ,
132
145
harness : & extern "C" fn ( * const u8 , usize ) -> c_int ,
@@ -137,12 +150,19 @@ fn fuzz_many_forking<M>(
137
150
where
138
151
M : Monitor + Clone + Debug ,
139
152
{
153
+ destroy_output_fds ( options) ;
154
+ let broker_port = std:: env:: var ( PORT_PROVIDER_VAR )
155
+ . map_err ( Error :: from)
156
+ . and_then ( |s| u16:: from_str ( & s) . map_err ( Error :: from) )
157
+ . or_else ( |_| {
158
+ TcpListener :: bind ( "127.0.0.1:0" ) . map ( |sock| {
159
+ let port = sock. local_addr ( ) . unwrap ( ) . port ( ) ;
160
+ std:: env:: set_var ( PORT_PROVIDER_VAR , port. to_string ( ) ) ;
161
+ port
162
+ } )
163
+ } ) ?;
140
164
fuzz_with ! ( options, harness, do_fuzz, |mut run_client| {
141
165
let cores = Cores :: from( ( 0 ..forks) . collect:: <Vec <_>>( ) ) ;
142
- let broker_port = TcpListener :: bind( "127.0.0.1:0" ) ?
143
- . local_addr( )
144
- . unwrap( )
145
- . port( ) ;
146
166
147
167
match Launcher :: builder( )
148
168
. shmem_provider( shmem_provider)
@@ -164,6 +184,26 @@ where
164
184
} )
165
185
}
166
186
187
+ fn create_monitor_closure ( ) -> impl Fn ( String ) + Clone {
188
+ #[ cfg( unix) ]
189
+ let stderr_fd =
190
+ std:: os:: fd:: RawFd :: from_str ( & std:: env:: var ( crate :: STDERR_FD_VAR ) . unwrap ( ) ) . unwrap ( ) ; // set in main
191
+ move |s| {
192
+ #[ cfg( unix) ]
193
+ {
194
+ use std:: os:: fd:: FromRawFd ;
195
+
196
+ // unfortunate requirement to meet Clone... thankfully, this does not
197
+ // generate effectively any overhead (no allocations, calls get merged)
198
+ let mut stderr = unsafe { File :: from_raw_fd ( stderr_fd) } ;
199
+ writeln ! ( stderr, "{s}" ) . expect ( "Could not write to stderr???" ) ;
200
+ std:: mem:: forget ( stderr) ; // do not close the descriptor!
201
+ }
202
+ #[ cfg( not( unix) ) ]
203
+ eprintln ! ( "{s}" ) ;
204
+ }
205
+ }
206
+
167
207
pub fn fuzz (
168
208
options : & LibfuzzerOptions ,
169
209
harness : & extern "C" fn ( * const u8 , usize ) -> c_int ,
@@ -174,37 +214,14 @@ pub fn fuzz(
174
214
let monitor = TuiMonitor :: new ( TuiUI :: new ( options. fuzzer_name ( ) . to_string ( ) , true ) ) ;
175
215
fuzz_many_forking ( options, harness, shmem_provider, forks, monitor)
176
216
} else if forks == 1 {
177
- #[ cfg( unix) ]
178
- let mut stderr = unsafe {
179
- let new_fd = libc:: dup ( std:: io:: stderr ( ) . as_raw_fd ( ) ) ;
180
- File :: from_raw_fd ( new_fd)
181
- } ;
182
217
let monitor = MultiMonitor :: with_time (
183
- move |s| {
184
- #[ cfg( unix) ]
185
- writeln ! ( stderr, "{s}" ) . expect ( "Could not write to stderr???" ) ;
186
- #[ cfg( not( unix) ) ]
187
- eprintln ! ( "{s}" ) ;
188
- } ,
218
+ create_monitor_closure ( ) ,
189
219
SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . unwrap ( ) ,
190
220
) ;
191
221
fuzz_single_forking ( options, harness, shmem_provider, monitor)
192
222
} else {
193
- #[ cfg( unix) ]
194
- let stderr_fd = unsafe { libc:: dup ( std:: io:: stderr ( ) . as_raw_fd ( ) ) } ;
195
223
let monitor = MultiMonitor :: with_time (
196
- move |s| {
197
- #[ cfg( unix) ]
198
- {
199
- // unfortunate requirement to meet Clone... thankfully, this does not
200
- // generate effectively any overhead (no allocations, calls get merged)
201
- let mut stderr = unsafe { File :: from_raw_fd ( stderr_fd) } ;
202
- writeln ! ( stderr, "{s}" ) . expect ( "Could not write to stderr???" ) ;
203
- let _ = stderr. into_raw_fd ( ) ; // discard the file without closing
204
- }
205
- #[ cfg( not( unix) ) ]
206
- eprintln ! ( "{s}" ) ;
207
- } ,
224
+ create_monitor_closure ( ) ,
208
225
SystemTime :: now ( ) . duration_since ( UNIX_EPOCH ) . unwrap ( ) ,
209
226
) ;
210
227
fuzz_many_forking ( options, harness, shmem_provider, forks, monitor)
@@ -216,8 +233,9 @@ pub fn fuzz(
216
233
let monitor = TuiMonitor :: new ( TuiUI :: new ( options. fuzzer_name ( ) . to_string ( ) , true ) ) ;
217
234
fuzz_many_forking ( options, harness, shmem_provider, 1 , monitor)
218
235
} else {
236
+ destroy_output_fds ( options) ;
219
237
fuzz_with ! ( options, harness, do_fuzz, |fuzz_single| {
220
- let mgr = SimpleEventManager :: new( SimpleMonitor :: new( |s| eprintln! ( "{s}" ) ) ) ;
238
+ let mgr = SimpleEventManager :: new( SimpleMonitor :: new( create_monitor_closure ( ) ) ) ;
221
239
crate :: start_fuzzing_single( fuzz_single, None , mgr)
222
240
} )
223
241
}
0 commit comments