39
39
#include "alloc-inl.h"
40
40
#include "hash.h"
41
41
#include "sharedmem.h"
42
+ #include "forkserver.h"
42
43
#include "common.h"
43
44
44
45
#include <stdio.h>
58
59
#include <sys/types.h>
59
60
#include <sys/resource.h>
60
61
61
- static s32 child_pid ; /* PID of the tested program */
62
+ u8 * trace_bits ; /* SHM with instrumentation bitmap */
63
+
64
+ s32 forksrv_pid , /* PID of the fork server */
65
+ child_pid ; /* PID of the tested program */
66
+
67
+ s32 fsrv_ctl_fd , /* Fork server control pipe (write) */
68
+ fsrv_st_fd ; /* Fork server status pipe (read) */
69
+
70
+ s32 out_fd ; /* Persistent fd for out_file */
71
+ s32 dev_null_fd = -1 ; /* FD to /dev/null */
72
+
73
+ s32 out_fd = -1 , out_dir_fd = -1 , dev_urandom_fd = -1 ;
74
+ FILE * plot_file ;
75
+ u8 uses_asan ;
62
76
63
77
u8 * trace_bits ; /* SHM with instrumentation bitmap */
64
78
65
- static u8 * out_file , /* Trace output file */
79
+ u8 * out_file , /* Trace output file */
80
+ * in_dir , /* input folder */
66
81
* doc_path , /* Path to docs */
67
82
* at_file ; /* Substitution string for @@ */
68
83
69
- static u32 exec_tmout ; /* Exec timeout (ms) */
84
+ static u8 * in_data ; /* Input data */
85
+
86
+ u32 exec_tmout ; /* Exec timeout (ms) */
70
87
71
88
static u32 total , highest ; /* tuple content information */
72
89
73
- static u64 mem_limit = MEM_LIMIT ; /* Memory limit (MB) */
90
+ static u32 in_len , /* Input data length */
91
+ arg_offset ,
92
+ total_execs ; /* Total number of execs */
93
+
94
+ u64 mem_limit = MEM_LIMIT ; /* Memory limit (MB) */
74
95
75
96
u8 quiet_mode , /* Hide non-essential messages? */
76
97
edges_only , /* Ignore hit counts? */
@@ -139,7 +160,7 @@ static void classify_counts(u8* mem, const u8* map) {
139
160
140
161
/* Write results. */
141
162
142
- static u32 write_results ( void ) {
163
+ static u32 write_results_to_file ( u8 * out_file ) {
143
164
144
165
s32 fd ;
145
166
u32 i , ret = 0 ;
@@ -208,15 +229,172 @@ static u32 write_results(void) {
208
229
209
230
}
210
231
211
- /* Handle timeout signal . */
232
+ /* Write results . */
212
233
213
- static void handle_timeout ( int sig ) {
234
+ static u32 write_results ( void ) {
214
235
215
- child_timed_out = 1 ;
216
- if (child_pid > 0 ) kill (child_pid , SIGKILL );
236
+ return write_results_to_file (out_file );
237
+
238
+ }
239
+
240
+ /* Write output file. */
241
+
242
+ static s32 write_to_file (u8 * path , u8 * mem , u32 len ) {
243
+
244
+ s32 ret ;
245
+
246
+ unlink (path ); /* Ignore errors */
247
+
248
+ ret = open (path , O_RDWR | O_CREAT | O_EXCL , 0600 );
249
+
250
+ if (ret < 0 ) PFATAL ("Unable to create '%s'" , path );
251
+
252
+ ck_write (ret , mem , len , path );
253
+
254
+ lseek (ret , 0 , SEEK_SET );
255
+
256
+ return ret ;
257
+
258
+ }
259
+
260
+ /* Write modified data to file for testing. If use_stdin is clear, the old file
261
+ is unlinked and a new one is created. Otherwise, out_fd is rewound and
262
+ truncated. */
263
+
264
+ static void write_to_testcase (void * mem , u32 len ) {
265
+
266
+ if (use_stdin ) {
267
+
268
+ lseek (0 , 0 , SEEK_SET );
269
+
270
+ ck_write (0 , mem , len , out_file );
271
+
272
+ if (ftruncate (0 , len )) PFATAL ("ftruncate() failed" );
273
+ lseek (0 , 0 , SEEK_SET );
274
+
275
+ }
217
276
218
277
}
219
278
279
+ /* Execute target application. Returns 0 if the changes are a dud, or
280
+ 1 if they should be kept. */
281
+
282
+ static u8 run_target_forkserver (char * * argv , u8 * mem , u32 len ) {
283
+
284
+ static struct itimerval it ;
285
+ static u32 prev_timed_out = 0 ;
286
+ int status = 0 ;
287
+
288
+ memset (trace_bits , 0 , MAP_SIZE );
289
+ MEM_BARRIER ();
290
+
291
+ write_to_testcase (mem , len );
292
+
293
+ s32 res ;
294
+
295
+ /* we have the fork server up and running, so simply
296
+ tell it to have at it, and then read back PID. */
297
+
298
+ if ((res = write (fsrv_ctl_fd , & prev_timed_out , 4 )) != 4 ) {
299
+
300
+ if (stop_soon ) return 0 ;
301
+ RPFATAL (res , "Unable to request new process from fork server (OOM?)" );
302
+
303
+ }
304
+
305
+ if ((res = read (fsrv_st_fd , & child_pid , 4 )) != 4 ) {
306
+
307
+ if (stop_soon ) return 0 ;
308
+ RPFATAL (res , "Unable to request new process from fork server (OOM?)" );
309
+
310
+ }
311
+
312
+ if (child_pid <= 0 ) FATAL ("Fork server is misbehaving (OOM?)" );
313
+
314
+ /* Configure timeout, wait for child, cancel timeout. */
315
+
316
+ if (exec_tmout ) {
317
+
318
+ it .it_value .tv_sec = (exec_tmout / 1000 );
319
+ it .it_value .tv_usec = (exec_tmout % 1000 ) * 1000 ;
320
+
321
+ }
322
+
323
+ setitimer (ITIMER_REAL , & it , NULL );
324
+
325
+ if ((res = read (fsrv_st_fd , & status , 4 )) != 4 ) {
326
+
327
+ if (stop_soon ) return 0 ;
328
+ RPFATAL (res , "Unable to communicate with fork server (OOM?)" );
329
+
330
+ }
331
+
332
+ child_pid = 0 ;
333
+ it .it_value .tv_sec = 0 ;
334
+ it .it_value .tv_usec = 0 ;
335
+
336
+ setitimer (ITIMER_REAL , & it , NULL );
337
+
338
+ MEM_BARRIER ();
339
+
340
+ /* Clean up bitmap, analyze exit condition, etc. */
341
+
342
+ if (* (u32 * )trace_bits == EXEC_FAIL_SIG )
343
+ FATAL ("Unable to execute '%s'" , argv [0 ]);
344
+
345
+ classify_counts (trace_bits ,
346
+ binary_mode ? count_class_binary : count_class_human );
347
+ total_execs ++ ;
348
+
349
+ if (stop_soon ) {
350
+
351
+ SAYF (cRST cLRD "\n+++ afl-showmap folder mode aborted by user +++\n" cRST );
352
+ close (write_to_file (out_file , in_data , in_len ));
353
+ exit (1 );
354
+
355
+ }
356
+
357
+ /* Always discard inputs that time out. */
358
+
359
+ if (child_timed_out ) { return 0 ; }
360
+
361
+ /* Handle crashing inputs depending on current mode. */
362
+
363
+ if (WIFSIGNALED (status ) ||
364
+ (WIFEXITED (status ) && WEXITSTATUS (status ) == MSAN_ERROR ) ||
365
+ (WIFEXITED (status ) && WEXITSTATUS (status ))) {
366
+
367
+ return 0 ;
368
+
369
+ }
370
+
371
+ return 0 ;
372
+
373
+ }
374
+
375
+ /* Read initial file. */
376
+
377
+ u32 read_file (u8 * in_file ) {
378
+
379
+ struct stat st ;
380
+ s32 fd = open (in_file , O_RDONLY );
381
+
382
+ if (fd < 0 ) WARNF ("Unable to open '%s'" , in_file );
383
+
384
+ if (fstat (fd , & st ) || !st .st_size ) WARNF ("Zero-sized input file '%s'." , in_file );
385
+
386
+ in_len = st .st_size ;
387
+ in_data = ck_alloc_nozero (in_len );
388
+
389
+ ck_read (fd , in_data , in_len , in_file );
390
+
391
+ close (fd );
392
+
393
+ //OKF("Read %u byte%s from '%s'.", in_len, in_len == 1 ? "" : "s", in_file);
394
+
395
+ return in_len ;
396
+ }
397
+
220
398
/* Execute target application. */
221
399
222
400
static void run_target (char * * argv ) {
@@ -456,6 +634,8 @@ static void usage(u8* argv0) {
456
634
457
635
"Other settings:\n\n"
458
636
637
+ " -i dir - process all files in this directory, -o most be a directory\n"
638
+ " and each bitmap will be written there individually.\n"
459
639
" -q - sink program's output and don't show messages\n"
460
640
" -e - show edge coverage only, ignore hit counts\n"
461
641
" -r - show real tuple values instead of AFL filter values\n"
@@ -536,10 +716,15 @@ int main(int argc, char** argv) {
536
716
537
717
doc_path = access (DOC_PATH , F_OK ) ? "docs" : DOC_PATH ;
538
718
539
- while ((opt = getopt (argc , argv , "+o:f:m:t:A:eqZQUWbcrh" )) > 0 )
719
+ while ((opt = getopt (argc , argv , "+i: o:f:m:t:A:eqZQUWbcrh" )) > 0 )
540
720
541
721
switch (opt ) {
542
722
723
+ case 'i' :
724
+ if (in_dir ) FATAL ("Multiple -i options not supported" );
725
+ in_dir = optarg ;
726
+ break ;
727
+
543
728
case 'o' :
544
729
545
730
if (out_file ) FATAL ("Multiple -o options not supported" );
@@ -707,7 +892,13 @@ int main(int argc, char** argv) {
707
892
708
893
}
709
894
895
+ if (in_dir ) at_file = "@@" ;
896
+
710
897
detect_file_args (argv + optind , at_file );
898
+
899
+ for (int i = optind ; i < argc ; i ++ )
900
+ if (strcmp (argv [i ], "@@" ) == 0 )
901
+ arg_offset = i ;
711
902
712
903
if (qemu_mode ) {
713
904
@@ -720,9 +911,48 @@ int main(int argc, char** argv) {
720
911
721
912
use_argv = argv + optind ;
722
913
723
- run_target (use_argv );
914
+ if (in_dir ) {
915
+
916
+ DIR * dir_in , * dir_out ;
917
+ struct dirent * dir_ent ;
918
+ int done = 0 ;
919
+ u8 infile [4096 ], outfile [4096 ];
920
+
921
+ dev_null_fd = open ("/dev/null" , O_RDWR );
922
+ if (dev_null_fd < 0 ) PFATAL ("Unable to open /dev/null" );
724
923
725
- tcnt = write_results ();
924
+ if (!(dir_in = opendir (in_dir ))) PFATAL ("cannot open directory %s" , in_dir );
925
+
926
+ if (!(dir_out = opendir (out_file )))
927
+ if (mkdir (out_file , 0700 ))
928
+ PFATAL ("cannot create output directory %s" , out_file );
929
+
930
+ if (arg_offset ) argv [arg_offset ] = infile ;
931
+
932
+ init_forkserver (use_argv );
933
+
934
+ while (done == 0 && (dir_ent = readdir (dir_in ))) {
935
+
936
+ if (dir_ent -> d_name [0 ] == '.' ) continue ; // skip anything that starts with '.'
937
+ if (dir_ent -> d_type != DT_REG ) continue ; // only regular files
938
+
939
+ snprintf (infile , sizeof (infile ), "%s/%s" , in_dir , dir_ent -> d_name );
940
+ snprintf (outfile , sizeof (outfile ), "%s/%s" , out_file , dir_ent -> d_name );
941
+
942
+ if (read_file (infile )) {
943
+ run_target_forkserver (use_argv , in_data , in_len );
944
+ ck_free (in_data );
945
+ tcnt = write_results_to_file (outfile );
946
+ }
947
+
948
+ }
949
+
950
+ } else {
951
+
952
+ run_target (use_argv );
953
+ tcnt = write_results ();
954
+
955
+ }
726
956
727
957
if (!quiet_mode ) {
728
958
@@ -735,4 +965,3 @@ int main(int argc, char** argv) {
735
965
exit (child_crashed * 2 + child_timed_out );
736
966
737
967
}
738
-
0 commit comments