-
Notifications
You must be signed in to change notification settings - Fork 0
/
SQ-Fuzz.cpp
9623 lines (6227 loc) · 252 KB
/
SQ-Fuzz.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
#ifndef _GNU_SOURCE
#define _GNU_SOURCE
#endif
#define _FILE_OFFSET_BITS 64
#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <signal.h>
#include <fcntl.h>
#include <dirent.h>
#include <dlfcn.h>
#include <execinfo.h>
#include <string.h>
#include<bits/stdc++.h>
#include <random>
#include <string>
#include <cstdio>
#include <cstdlib>
#include <sys/ipc.h>
#include <sys/mman.h>
#include <sys/shm.h>
#include <sys/time.h>
#include <sys/resource.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/file.h>
#include <sys/wait.h>
#include "config.h"
#include "types.h"
#include "debug.h"
#include "alloc-inl.h"
#include "hash.h"
#include "parser.h"
/* A toggle to export some variables when building as a library. Not very
useful for the general public. */
#ifdef AFL_LIB
# define EXP_ST
#else
# define EXP_ST static
#endif /* ^AFL_LIB */
/* If the original file name conforms to the syntax and the recorded
ID matches the one we'd assign, just use the original file name.
This is valuable for resuming fuzzing runs. */
#ifndef SIMPLE_FILES
# define CASE_PREFIX "id:"
#else
# define CASE_PREFIX "id_"
#endif /* ^!SIMPLE_FILES */
#define CHK_FORMAT(_divisor, _limit_mult, _fmt, _cast) do { \
if (val < (_divisor) * (_limit_mult)) { \
sprintf(tmp[cur], _fmt, ((_cast)val) / (_divisor)); \
return tmp[cur]; \
} \
} while (0)
#define FF(_b) (0xff << ((_b) << 3))
/* Fuzzing stages */
enum {
/* 00 */ STAGE_FLIP1,
/* 01 */ STAGE_FLIP2,
/* 02 */ STAGE_FLIP4,
/* 03 */ STAGE_FLIP8,
/* 04 */ STAGE_FLIP16,
/* 05 */ STAGE_FLIP32,
/* 06 */ STAGE_ARITH8,
/* 07 */ STAGE_ARITH16,
/* 08 */ STAGE_ARITH32,
/* 09 */ STAGE_INTEREST8,
/* 10 */ STAGE_INTEREST16,
/* 11 */ STAGE_INTEREST32,
/* 12 */ STAGE_EXTRAS_UO,
/* 13 */ STAGE_EXTRAS_UI,
/* 14 */ STAGE_EXTRAS_AO,
/* 15 */ STAGE_HAVOC,
/* 16 */ STAGE_SPLICE
};
/* Execution status fault codes */
enum {
/* 00 */ FAULT_NONE,
/* 01 */ FAULT_TMOUT,
/* 02 */ FAULT_CRASH,
/* 03 */ FAULT_ERROR,
/* 04 */ FAULT_NOINST,
/* 05 */ FAULT_NOBITS
};
/* Stage value types */
enum {
/* 00 */ STAGE_VAL_NONE,
/* 01 */ STAGE_VAL_LE,
/* 02 */ STAGE_VAL_BE
};
/* Global variable */
enum {
/* 00 */ INPUT_FILE_NO,
/* 01 */ INT_NO,
/* 02 */ STRING_NO,
/* 03 */ UNSIINT_NO
};
const char *doc_path;
struct queue_entry {
char* fname; /* File name for the test case */
char** argv;
std::vector<bool> parameters;
u32 len; /* Input length */
u8 cal_failed, /* Calibration failed? */
trim_done, /* Trimmed? */
was_fuzzed, /* Had any fuzzing done yet? */
passed_det, /* Deterministic stages passed? */
has_new_cov, /* Triggers new coverage? */
var_behavior, /* Variable behavior? */
favored, /* Currently favored? */
fs_redundant; /* Marked as redundant in the fs? */
u32 bitmap_size, /* Number of bits set in bitmap */
exec_cksum; /* Checksum of the execution trace */
u64 exec_us, /* Execution time (us) */
handicap, /* Number of queue cycles behind */
depth; /* Path depth */
u8* trace_mini; /* Trace bytes, if kept */
u32 tc_ref; /* Trace bytes ref count */
struct queue_entry *next, /* Next element, if any */
*next_100; /* 100 elements ahead */
};
static struct queue_entry *queue, /* Fuzzing queue (linked list) */
*queue_cur, /* Current offset within the queue */
*queue_top, /* Top of the list */
*q_prev100; /* Previous 100 marker */
static struct queue_entry*
top_rated[MAP_SIZE]; /* Top entries for bitmap bytes */
struct extra_data {
u8* data; /* Dictionary token data */
u32 len; /* Dictionary token length */
u32 hit_cnt; /* Use count in the corpus */
};
static struct extra_data* extras; /* Extra tokens to fuzz with */
static u32 extras_cnt; /* Total number of tokens read */
static struct extra_data* a_extras; /* Automatically selected extras */
static u32 a_extras_cnt; /* Total number of tokens available */
/* Interesting values, as per config.h */
static s8 interesting_8[] = { INTERESTING_8 };
static s16 interesting_16[] = { INTERESTING_8, INTERESTING_16 };
static s32 interesting_32[] = { INTERESTING_8, INTERESTING_16, INTERESTING_32 };
char *in_dir = NULL; /* Input directory with test cases */
char *out_dir = NULL; /* Working & output directory */
char *sync_id = NULL; /* Fuzzer ID */
char *out_file = NULL; /* File to fuzz, if any */
char *extras_dir = NULL;
char *use_banner = NULL; /* Display banner */
char *sync_dir = NULL; /* Synchronization directory */
char *orig_cmdline; /* Original command line */
char *in_bitmap; /* Input bitmap */
char *target_path; /* Path to target binary */
static char *stage_name = (char *)"init", /* Name of the current fuzz stage */
*stage_short, /* Short stage name */
*syncing_party; /* Currently syncing with... */
static volatile u8 stop_soon, /* Ctrl-C pressed? */
clear_screen = 1, /* Window resized? */
child_timed_out; /* Traced process timed out? */
EXP_ST u8 in_place_resume = 0,
force_deterministic = 0, /* Force deterministic stages? */
timeout_given = 0, /* Specific timeout given? */
mem_limit_given = 0,
skip_deterministic = 0, /* Skip deterministic stages? */
use_splicing = 0, /* Recombine input files? */
crash_mode = 0, /* Crash mode! Yeah! */
dumb_mode = 0, /* Run in non-instrumented mode? */
qemu_mode = 0, /* Running in QEMU mode? */
skip_requested, /* Skip request, via SIGUSR1 */
no_forkserver, /* Disable forkserver? */
no_cpu_meter_red, /* Feng shui on the status screen */
term_too_small, /* terminal dimensions too small */
no_arith, /* Skip most arithmetic ops */
uses_asan, /* Target uses ASAN? */
persistent_mode, /* Running in persistent mode? */
deferred_mode, /* Deferred forkserver mode? */
fast_cal, /* Try to calibrate faster? */
run_over10m, /* Run time over 10 minutes? */
not_on_tty, /* stdout is not a tty */
score_changed, /* Scoring for favorites changed? */
auto_changed, /* Auto-generated tokens changed? */
kill_signal, /* Signal that killed the child */
resuming_fuzz = 0, /* Resuming an older fuzzing job? */
bitmap_changed = 1, /* Time to update bitmap? */
shuffle_queue; /* Shuffle input queue? */
static u8 stage_val_type; /* Value type (STAGE_VAL_*) */
EXP_ST u8 virgin_bits[MAP_SIZE], /* Regions yet untouched by fuzzing */
virgin_tmout[MAP_SIZE], /* Bits we haven't seen in tmouts */
virgin_crash[MAP_SIZE]; /* Bits we haven't seen in crashes */
static u8 var_bytes[MAP_SIZE]; /* Bytes that appear to be variable */
EXP_ST u8* trace_bits; /* SHM with instrumentation bitmap */
EXP_ST u32 exec_tmout = EXEC_TIMEOUT; /* Configurable exec timeout (ms) */
static u32 hang_tmout = EXEC_TIMEOUT; /* Timeout used for hang det (ms) */
static u32 seek_to;
EXP_ST u32 queued_paths, /* Total number of queued testcases */
queued_variable, /* Testcases with variable behavior */
queued_at_start, /* Total number of initial inputs */
queued_discovered, /* Items discovered during this run */
queued_imported, /* Items imported via -S */
queued_favored, /* Paths deemed favorable */
queued_with_cov, /* Paths with new coverage bytes */
pending_not_fuzzed, /* Queued but not done yet */
pending_favored, /* Pending favored paths */
cur_skipped_paths, /* Abandoned inputs in cur cycle */
cur_depth, /* Current path depth */
max_depth, /* Max path depth */
useless_at_start, /* Number of useless starting paths */
var_byte_count, /* Bitmap bytes with var behavior */
current_entry, /* Current queue entry ID */
havoc_div = 1; /* Cycle count divisor for havoc */
static u32 sync_interval_cnt = 0;
static u32 syncing_case; /* Syncing with case #... */
static u32 subseq_tmouts; /* Number of timeouts in a row */
static u32 stats_update_freq = 1; /* Stats update frequency (execs) */
static u32 master_id, master_max; /* Master instance job splitting */
static u32 rand_cnt; /* Random number counter */
static s32 forksrv_pid, /* PID of the fork server */
child_pid = -1, /* PID of the fuzzed program */
out_dir_fd = -1, /* FD of the lock file */
out_fd, /* Persistent fd for out_file */
dev_urandom_fd = -1, /* Persistent fd for /dev/urandom */
dev_null_fd = -1, /* Persistent fd for /dev/null */
fsrv_ctl_fd, /* Fork server control pipe (write) */
fsrv_st_fd; /* Fork server status pipe (read) */
static s32 stage_cur, stage_max; /* Stage progression */
static s32 splicing_with = -1; /* Splicing with which test case? */
static s32 cpu_core_count; /* CPU core count */
static s32 shm_id; /* ID of the SHM region */
static s32 stage_cur_byte, /* Byte offset of current stage op */
stage_cur_val; /* Value used for stage op */
EXP_ST u64 mem_limit = MEM_LIMIT; /* Memory cap for child (MB) */
EXP_ST u64 total_crashes, /* Total number of crashes */
unique_crashes, /* Crashes with unique signatures */
total_tmouts, /* Total number of timeouts */
unique_tmouts, /* Timeouts with unique signatures */
unique_hangs, /* Hangs with unique signatures */
total_execs, /* Total execve() calls */
slowest_exec_ms, /* Slowest testcase non hang in ms */
start_time, /* Unix start time (ms) */
last_path_time, /* Time for most recent path (ms) */
last_crash_time, /* Time for most recent crash (ms) */
last_hang_time, /* Time for most recent hang (ms) */
last_crash_execs, /* Exec counter at last crash */
queue_cycle, /* Queue round counter */
cycles_wo_finds, /* Cycles without any new paths */
trim_execs, /* Execs done to trim input files */
bytes_trim_in, /* Bytes coming into the trimmer */
bytes_trim_out, /* Bytes coming outa the trimmer */
blocks_eff_total, /* Blocks subject to effector maps */
blocks_eff_select; /* Blocks selected as fuzzable */
static u64 total_cal_us, /* Total calibration time (us) */
total_cal_cycles; /* Total calibration cycles */
static u64 total_bitmap_size, /* Total bit count for all bitmaps */
total_bitmap_entries; /* Number of bitmaps counted */
static u64 prev_queued = 0;
static u64 stage_finds[32], /* Patterns found per fuzz stage */
stage_cycles[32]; /* Execs per fuzz stage */
static FILE* plot_file; /* Gnuplot output file */
static char* (*post_handler)(char* buf, u32* len);
/* functions */
static void usage(u8* argv0); /* Display usage hints. */
static void handle_stop_sig(int sig);
static void handle_skipreq(int sig);
static void handle_timeout(int sig);
static void handle_resize(int sig);
static void handle_sigsegv(int sig);
static void check_asan_opts(void);
static void fix_up_sync(void);
static void save_cmdline(u32 argc, char** argv); /* Make a copy of the current command line. */
static void fix_up_banner(char* name); /* Trim and possibly create a banner for the run. */
static void check_if_tty(void); /* Check if we're on TTY. */
static void get_core_count(void); /* Count the number of logical CPU cores. */
static double get_runnable_processes(void); /* Get the number of runnable processes,
with some simple smoothing. */
static void bind_to_free_cpu(void); /* Build a list of processes bound to
specific cores. Returns -1 if
nothing can be found. Assumes an
upper bound of 4k CPUs. */
static void check_crash_handling(void); /* Make sure that core dumps don't
go to a program. */
static void check_cpu_governor(void); /* Check CPU governor. */
EXP_ST void setup_signal_handlers(void);
EXP_ST void setup_dirs_fds(void); /* Prepare output directories and fds. */
static void maybe_delete_out_dir(void); /* Delete fuzzer output directory
if we recognize it as ours,
if the fuzzer
is not currently running, and if
the last run time isn't too
great. */
static u8 delete_files(char* path, char* prefix); /* A helper function for maybe_delete_out_dir(),
deleting all prefixed files in a directory. */
static void read_testcases(void); /* Read all testcases from the input directory,
then queue them for testing.
Called at startup. */
static void shuffle_ptrs(void** ptrs, u32 cnt); /* Shuffle an array of pointers.
Might be slightly biased. */
static char* DMS(u64 val); /* Describe integer as memory size. */
static void add_to_queue(char* fname,
u32 len, u8 passed_det); /* Append new test case to the queue. */
static inline u32 UR(u32 limit); /* Generate a random number (from 0 to limit - 1).
This may have slight bias. */
static u64 get_cur_time(void); /* Get unix time in milliseconds */
static void load_auto(void); /* Load automatically generated extras. */
static void maybe_add_auto(u8* mem, u32 len); /* Maybe add automatic extra. */
static inline u8 memcmp_nocase(u8* m1,
u8* m2, u32 len); /* Helper function for maybe_add_auto() */
static int compare_extras_len(const void* p1, /* Helper function for load_extras. */
const void* p2);
static int compare_extras_use_d(const void* p1, /* Helper function for load_extras. */
const void* p2);
static void setup_post(void); /* Load postprocessor, if available. */
EXP_ST void setup_shm(void); /* Configure shared memory and virgin_bits.
This is called at startup. */
static void remove_shm(void); /* Get rid of shared memory (atexit handler). */
static void pivot_inputs(void); /* Create hard links for input test cases
in the output directory, choosing good names
and pivoting accordingly. */
static void link_or_copy(char* old_path,
char* new_path); /* Helper function: link() if possible,
copy otherwise. */
static void mark_as_det_done(struct queue_entry* q);/* Mark deterministic checks as done for
a particular queue entry. We use the .state
file to avoid repeating deterministic fuzzing
when resuming aborted scans. */
static void nuke_resume_dir(void); /* Delete the temporary directory used for
in-place session resume. */
static void load_extras_file(char* fname,
u32* min_len, u32* max_len,
u32 dict_level); /* Read extras from a file, sort by size. */
static void load_extras(char* dir); /* Read extras from the extras directory
and sort them by size. */
static void find_timeout(void); /* The same, but for timeouts. The idea is
that when resuming sessions without -t given,
we don't want to keep auto-scaling the timeout
over and over again to prevent it from growing
due to random flukes. */
EXP_ST void detect_file_args(char** argv); /* Detect @@ in args. */
EXP_ST void setup_stdio_file(void); /* Setup the output file for fuzzed data,
if not using -f. */
EXP_ST void check_binary(char* fname); /* Do a PATH search and find target binary
to see that it exists and isn't a shell
script -a common and painful mistake. We
also check for a valid ELF header and for
evidence of AFL instrumentation. */
static char** get_qemu_argv(char* own_loc,
char** argv, int argc); /* Rewrite argv for QEMU. */
static void perform_dry_run(char** argv); /* Perform dry run of all test cases
to confirm that the app is working as
expected. This is done only for the initial
inputs, and only once. */
static u8 calibrate_case(char** argv,
struct queue_entry* q, char* use_mem,
u32 handicap, u8 from_queue); /* Calibrate a new test case. This is done
when processing the input directory to
warn about flaky or otherwise problematic
test cases early on; and when new paths
are discovered to detect variable behavior
and so on. */
static void check_map_coverage(void); /* Examine map coverage. Called once,
for first test case. */
EXP_ST void init_forkserver(char** argv); /* Spin up fork server (instrumented mode only). */
static u64 get_cur_time_us(void); /* Get unix time in microseconds */
static void show_stats(void); /* A spiffy retro stats screen! This is
called every stats_update_freq execve()
calls, plus in several other circumstances. */
static void write_to_testcase(void* mem, u32 len); /* Write modified data to file for testing.
If out_file is set, the old file is unlinked
and a new one is created. Otherwise, out_fd
is rewound and truncated. */
static u8 run_target(char** argv, u32 timeout); /* Execute target application, monitoring for timeouts.
Return status information. The called program
will update trace_bits[]. */
static u32 count_bytes(char* mem); /* Count the number of bytes set in the bitmap.
Called fairly sporadically, mostly to update
the status screen or calibrate and examine
confirmed new paths. */
static inline u8 has_new_bits(u8* virgin_map); /* Check if the current execution path
brings anything new to the table. */
static void update_bitmap_score(struct queue_entry* q); /*When we bump into a new path,
we call this to see if the path
appears more "favorable" */
static void mark_as_variable(struct queue_entry* q);/* Mark as variable. Create symlinks
if possible to make it easier to examine
the files. */
static u32 count_non_255_bytes(u8* mem); /* Count the number of non-255 bytes
set in the bitmap. Used strictly for the
status screen, several calls per
second or so. */
static void write_stats_file(double bitmap_cvg,
double stability, double eps); /* Update stats file for unattended monitoring. */
static void save_auto(void); /* Save automatically generated extras. */
EXP_ST void write_bitmap(void); /* Write bitmap to file. The bitmap is
useful mostly for the secret -B option,
to focus a separate fuzzing session on
a particular interesting input without
rediscovering all the others. */
static void maybe_update_plot_file(
double bitmap_cvg, double eps); /* Update the plot file if there is a reason to. */
static u32 count_bits(u8* mem); /* Count the number of bits set in the
provided bitmap. Used for the status
screen several times every second,
does not have to be fast. */
static void check_term_size(void); /* Check terminal dimensions after resize. */
static u8* DTD(u64 cur_ms, u64 event_ms); /* Describe time delta. Returns
one static buffer, 34 chars of less. */
static u8* DI(u64 val); /* Describe integer. Uses 12 cyclic
static buffers for return values.
The value returned should be five
characters or less for all the integers
we reasonably expect to see. */
static u8* DF(double val); /* Describe float. Similar to the above,
except with a single static buffer. */
static void minimize_bits(u8* dst, u8* src); /* Compact trace bytes into a smaller
bitmap. We effectively just drop
the count information here.
This is called only sporadically,
for some new paths. */
static void cull_queue(void); /* The second part of the mechanism discussed
above is a routine that goes over top_rated[]
entries, and then sequentially grabs winners for
previously-unseen bytes (temp_v)
and marks them as favored */
static void show_init_stats(void); /* Display quick statistics at the end
of processing the input directory,
plus a bunch of warnings. Some
calibration stuff also ended up here,
along with several hardcoded constants.
Maybe clean up eventually. */
static u32 next_p2(u32 val); /* Find first power of two greater
or equal to val (assuming val under 2^31). */
static void mark_as_redundant(
struct queue_entry* q, u8 state); /* Mark / unmark as redundant (edge-only).
This is not used for restoring state,
but may be useful for post-processing datasets. */
static u32 find_start_position(void); /* When resuming, try to find the queue position
to start from. This makes sense only when resuming,
and when we can find the original fuzzer_stats. */
EXP_ST void destroy_queue(void); /* Destroy the entire queue. */
static void destroy_extras(void); /* Destroy extras. */
static void sync_fuzzers(char** argv); /* Grab interesting test cases
from other fuzzers. */
static u8 save_if_interesting(char** argv,
void* mem, u32 len, u8 fault); /* Check if the result of an execve()
during routine fuzzing is interesting,
save or queue the input test case for
further analysis if so. Returns 1 if
entry is saved, 0 otherwise. */
static u8 trim_case(char** argv,
struct queue_entry* q, u8* in_buf); /* Trim all new test cases to save cycles when
doing deterministic checks. The trimmer uses
power-of-two increments somewhere between 1/16
and 1/1024 of file size, to keep the stage short and sweet. */
static u32 calculate_score(
struct queue_entry* q); /* Calculate case desirability score to
adjust the length of havoc fuzzing.
A helper function for fuzz_one(). Maybe some
of these constants should go into config.h. */
static void write_with_gap(
void* mem, u32 len,
u32 skip_at, u32 skip_len); /* The same, but with an adjustable gap.
Used for trimming. */
EXP_ST u8 common_fuzz_stuff(char** argv,
u8* out_buf, u32 len); /* Write a modified test case, run program,
process results. Handle error conditions,
returning 1 if it's time to bail out.
This is a helper function for fuzz_one(). */
static u8 could_be_bitflip(u32 xor_val); /* Helper function to see if a particular
change (xor_val = old ^ new) could be a
product of deterministic bit flips with the
lengths and stepovers attempted by afl-fuzz.*/
static u8 could_be_arith(u32 old_val,
u32 new_val, u8 blen); /* Helper function to see if a particular value
is reachable through arithmetic operations.
Used for similar purposes. */
static u8 could_be_interest(u32 old_val,
u32 new_val, u8 blen, u8 check_le); /* Last but not least, a similar helper to see
if insertion of an interesting integer is
redundant given the insertions done for shorter blen.*/
static u32 choose_block_len(u32 limit); /* Helper to choose random block len for block operations
in fuzz_one(). Doesn't return zero,
provided that max_len is > 0. */
static u8* describe_op(u8 hnb); /* Construct a file name for a new test case,
capturing the operation that led to its
discovery. Uses a static buffer. */
static void locate_diffs(u8* ptr1,
u8* ptr2, u32 len,
s32* first, s32* last); /* Helper function to compare buffers;
returns first and last differing offset.
We use this to find reasonable locations
for splicing two files. */
static void write_crash_readme(void); /* Write a message accompanying
the crash directory :-) */
static u8 fuzz_one(char** argv); /* Take the current entry from the
queue, fuzz it for a while. This function
is a tad too long... returns 0 if fuzzed
successfully, 1 if skipped or bailed out. */
static void argv_pivot_inputs(void); /* Store queue_info for input test cases */
static void analyze_argvs(char **use_argv); /* Fill all the queue_entry's argv related
field */
static void check_argv_mutable(); /* Check if the argv is mutable */
static u8 argv_fuzz_one(char **argv);
static void reset_forkserv_argvs(char **new_argvs);
static u8 argv_common_fuzz_stuff(char **argv,
u8 *mem,
u32 len,
std::vector<bool> *bool_array_ptr);
static void argv_add_to_queue(char* fname, u32 len, u8 passed_det, char **argvs, std::vector<bool> *bool_array_ptr);
static u8 argv_save_if_interesting(char **argv,
void *mem,
u32 len,
u8 fault,
std::vector<bool> *bool_array_ptr);
static void random_gen_bool_array(std::vector<bool> *bool_array_ptr);
static void bool_array2new_argv(char **new_argv, std::vector<bool> *bool_array_ptr);
static int random_gen_INT(int min, int max);
static void random_gen_STRING(u32 min, u32 max, std::string *st_ptr);
static void randombytes(uint8_t *x, size_t how_much);
static void record_global_variables();
static char *variable_replace(char *source);
static u8 argv_fuzz_flag = 0;
static std::random_device rd;
static std::mt19937 mt(rd());
static char random_st[10000];
static std::map<std::string, std::vector<std::string>> VARIABLES;
static std::vector<std::vector<std::string>> PARAMETERS_MUST;
static std::vector<std::vector<std::string>> PARAMETERS_NOT_MUST;
static std::vector<int> PARA_MUST_IS_MUTABLE;
static std::vector<int> PARA_NOT_MUST_IS_MUTABLE;
static std::vector<std::string> IMPLICIT_VARIABLES;
/* Destructively simplify trace by eliminating hit count information
and replacing it with 0x80 or 0x01 depending on whether the tuple
is hit or not. Called on every new crash or timeout, should be
reasonably fast. */
static u8 simplify_lookup[256];
static u8 simplify_lookup_set = false;
#ifdef WORD_SIZE_64
static void simplify_trace(u64* mem) {
if(!simplify_lookup_set){
for(int i = 0;i < 256;i++){
if(i == 0){
simplify_lookup[i] = 1;
} else {
simplify_lookup[i] = 128;
}
}
}
simplify_lookup_set = true;
u32 i = MAP_SIZE >> 3;
while (i--) {
/* Optimize for sparse bitmaps. */
if (unlikely(*mem)) {
u8* mem8 = (u8*)mem;
mem8[0] = simplify_lookup[mem8[0]];
mem8[1] = simplify_lookup[mem8[1]];
mem8[2] = simplify_lookup[mem8[2]];
mem8[3] = simplify_lookup[mem8[3]];
mem8[4] = simplify_lookup[mem8[4]];
mem8[5] = simplify_lookup[mem8[5]];
mem8[6] = simplify_lookup[mem8[6]];
mem8[7] = simplify_lookup[mem8[7]];
} else *mem = 0x0101010101010101ULL;
mem++;
}
}
#else
static void simplify_trace(u32* mem) {
u32 i = MAP_SIZE >> 2;
while (i--) {
/* Optimize for sparse bitmaps. */
if (unlikely(*mem)) {
u8* mem8 = (u8*)mem;
mem8[0] = simplify_lookup[mem8[0]];
mem8[1] = simplify_lookup[mem8[1]];
mem8[2] = simplify_lookup[mem8[2]];
mem8[3] = simplify_lookup[mem8[3]];
} else *mem = 0x01010101;
mem++;
}
}
#endif /* ^WORD_SIZE_64 */
/* Destructively classify execution counts in a trace. This is used as a
preprocessing step for any newly acquired traces. Called on every exec,
must be fast. */
static u8 count_class_lookup8[256];
static u16 count_class_lookup16[65536];
EXP_ST void init_count_class8_and_class16(void) {
for(int i = 0;i < 256;i++){
if(i == 0){
count_class_lookup8[i] = 0;
} else if(i == 1){
count_class_lookup8[i] = 1;
} else if(i == 2){
count_class_lookup8[i] = 2;
} else if(i == 3){
count_class_lookup8[i] = 4;
} else if(i >= 4 && i <= 7){
count_class_lookup8[i] = 8;
} else if(i >= 8 && i <= 15){
count_class_lookup8[i] = 16;
} else if(i >= 16 && i <= 31){
count_class_lookup8[i] = 32;
} else if(i >= 32 && i <= 127){
count_class_lookup8[i] = 64;
} else if(i >= 128 && i <= 255){
count_class_lookup8[i] = 128;
}
}
u32 b1, b2;
for (b1 = 0; b1 < 256; b1++)
for (b2 = 0; b2 < 256; b2++)
count_class_lookup16[(b1 << 8) + b2] =
(count_class_lookup8[b1] << 8) |
count_class_lookup8[b2];
}
#ifdef WORD_SIZE_64
static inline void classify_counts(u64* mem) {
u32 i = MAP_SIZE >> 3;
while (i--) {
/* Optimize for sparse bitmaps. */
if (unlikely(*mem)) {
u16* mem16 = (u16*)mem;
mem16[0] = count_class_lookup16[mem16[0]];
mem16[1] = count_class_lookup16[mem16[1]];
mem16[2] = count_class_lookup16[mem16[2]];
mem16[3] = count_class_lookup16[mem16[3]];
}
mem++;
}
}
#else
static inline void classify_counts(u32* mem) {
u32 i = MAP_SIZE >> 2;
while (i--) {
/* Optimize for sparse bitmaps. */
if (unlikely(*mem)) {
u16* mem16 = (u16*)mem;
mem16[0] = count_class_lookup16[mem16[0]];
mem16[1] = count_class_lookup16[mem16[1]];
}
mem++;
}
}
#endif /* ^WORD_SIZE_64 */
int main(int argc, char *argv[]) {
SAYF(cCYA "afl-fuzz " cBRI VERSION cRST " by <lcamtuf@google.com>\n");
SAYF(cCYA " SQ-fuzz " cBRI SQVERSION cRST " by <fdgkhdkgh@gmail.com>\n");
doc_path = access(DOC_PATH, F_OK) ? "docs" : DOC_PATH;
SAYF("doc_path : %s\n", doc_path);
s32 opt;
char** use_argv;
u8 exit_1 = !!getenv("AFL_BENCH_JUST_ONE");
char *xml_position;
while((opt = getopt(argc, argv, "+i:o:s:f:m:t:T:dnCB:S:M:x:Q")) > 0) {
switch(opt) {
case 'i': /* input dir */
if(in_dir) FATAL("Multiple -i options not supported");
in_dir = optarg;
//假如in_dir只有"-"的話,表示要從上次的模糊測試復原,
//而不是進行全新的模糊測試
if (!strcmp(in_dir, "-")) in_place_resume = 1;
break;
case 'o': /* output dir */
if (out_dir) FATAL("Multiple -o options not supported");
out_dir = optarg;
break;
case 's': /* setting xml file */
xml_position = optarg;
if( access( xml_position, F_OK ) != -1 ) {
OKF("xml_position : %s", xml_position);
parseXML(xml_position, &VARIABLES, &PARAMETERS_MUST, &PARAMETERS_NOT_MUST);
} else {
FATAL("File doesn't exist!");
}
//printf("PARAMETERS_NOT_MUST.size() : %d\n", PARAMETERS_NOT_MUST.size());
argv_fuzz_flag = 1;
break;
case 'M': { /* master sync ID */
char* c;
if (sync_id) FATAL("Multiple -S or -M options not supported");
sync_id = (char *)ck_strdup((u8 *)optarg);
if ((c = strchr(sync_id, ':'))) {
*c = 0;
if (sscanf(c + 1, "%u/%u", &master_id, &master_max) != 2 ||
!master_id || !master_max || master_id > master_max ||
master_max > 1000000) FATAL("Bogus master ID passed to -M");
}
force_deterministic = 1;
}
break;
case 'S': /* slave sync ID */
if (sync_id) FATAL("Multiple -S or -M options not supported");
sync_id = (char *)ck_strdup((u8 *)optarg);
break;
case 'f': /* target file */
if (out_file) FATAL("Multiple -f options not supported");
out_file = optarg;
break;
case 'x': /* dictionary */
if (extras_dir) FATAL("Multiple -x options not supported");
extras_dir = optarg;
break;
case 't': { /* timeout */
u8 suffix = 0;
if (timeout_given) FATAL("Multiple -t options not supported");
if (sscanf(optarg, "%u%c", &exec_tmout, &suffix) < 1 ||
optarg[0] == '-') FATAL("Bad syntax used for -t");
if (exec_tmout < 5) FATAL("Dangerously low value of -t");
if (suffix == '+') timeout_given = 2; else timeout_given = 1;
break;
}
case 'm': { /* mem limit */
u8 suffix = 'M';
if (mem_limit_given) FATAL("Multiple -m options not supported");
mem_limit_given = 1;
if (!strcmp(optarg, "none")) {
mem_limit = 0;
break;
}
//這種suffix的處理方法很有趣,可以記下來
if (sscanf(optarg, "%llu%c", &mem_limit, &suffix) < 1 ||
optarg[0] == '-') FATAL("Bad syntax used for -m");
switch (suffix) {
case 'T': mem_limit *= 1024 * 1024; break;
case 'G': mem_limit *= 1024; break;
case 'k': mem_limit /= 1024; break;
case 'M': break;
default: FATAL("Unsupported suffix or bad syntax for -m");
}
if (mem_limit < 5) FATAL("Dangerously low value of -m");
//rlim_t : 我猜是用來判斷32-bit systems?
//rlim_t是一種type,而不是變數名稱
if (sizeof(rlim_t) == 4 && mem_limit > 2000)
FATAL("Value of -m out of range on 32-bit systems");
}
break;
case 'd': /* skip deterministic */
if (skip_deterministic) FATAL("Multiple -d options not supported");
skip_deterministic = 1;
use_splicing = 1;
break;
//case 'B': /* load bitmap */
/* This is a secret undocumented option! It is useful if you find
an interesting test case during a normal fuzzing process, and want
to mutate it without rediscovering any of the test cases already
found during an earlier run.
To use this mode, you need to point -B to the fuzz_bitmap produced
by an earlier run for the exact same binary... and that's it.
I only used this once or twice to get variants of a particular
file, so I'm not making this an official setting. */
/* if (in_bitmap) FATAL("Multiple -B options not supported");
in_bitmap = optarg;
read_bitmap(in_bitmap);
break;*/
case 'C': /* crash mode */
if (crash_mode) FATAL("Multiple -C options not supported");
crash_mode = FAULT_CRASH;
break;
case 'n': /* dumb mode */
if (dumb_mode) FATAL("Multiple -n options not supported");
if (getenv("AFL_DUMB_FORKSRV")) dumb_mode = 2; else dumb_mode = 1;
break;
case 'T': /* banner */
if (use_banner) FATAL("Multiple -T options not supported");
use_banner = optarg;
break;
case 'Q': /* QEMU mode */
if (qemu_mode) FATAL("Multiple -Q options not supported");
qemu_mode = 1;
if (!mem_limit_given) mem_limit = MEM_LIMIT_QEMU;
break;