Skip to content

Commit 1e30c3a

Browse files
committed
afl-tmin hang mode added
1 parent 2287534 commit 1e30c3a

File tree

3 files changed

+82
-11
lines changed

3 files changed

+82
-11
lines changed

docs/Changelog.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ sending a mail to <[email protected]>.
1616
- afl-fuzz basic tools now report on the environment variables picked up
1717
- more tools get environment variable usage info in the help output
1818
- AFL_AUTORESUME will resume execution without the need to specify `-i -`
19+
- afl-tmin now supports hang mode `-H` to minimize hangs
20+
- fixed potential afl-tmin missbehavior for targets with multiple hangs
1921

2022

2123
### Version ++2.62c (release):

docs/technical_details.md

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -286,8 +286,9 @@ operation of `afl-tmin` is as follows.
286286

287287
First, the tool automatically selects the operating mode. If the initial input
288288
crashes the target binary, afl-tmin will run in non-instrumented mode, simply
289-
keeping any tweaks that produce a simpler file but still crash the target. If
290-
the target is non-crashing, the tool uses an instrumented mode and keeps only
289+
keeping any tweaks that produce a simpler file but still crash the target.
290+
The same mode is used for hangs, if `-H` (hang mode) is specified.
291+
If the target is non-crashing, the tool uses an instrumented mode and keeps only
291292
the tweaks that produce exactly the same execution path.
292293

293294
The actual minimization algorithm is:

src/afl-tmin.c

Lines changed: 77 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -89,6 +89,7 @@ u64 mem_limit = MEM_LIMIT; /* Memory limit (MB) */
8989
s32 dev_null_fd = -1; /* FD to /dev/null */
9090

9191
u8 crash_mode, /* Crash-centric mode? */
92+
hang_mode, /* Minimize as long as it hangs */
9293
exit_crash, /* Treat non-zero exit as crash? */
9394
edges_only, /* Ignore hit counts? */
9495
exact_mode, /* Require path match for crashes? */
@@ -98,6 +99,7 @@ static volatile u8 stop_soon; /* Ctrl-C pressed? */
9899

99100
static u8 qemu_mode;
100101

102+
101103
/*
102104
* forkserver section
103105
*/
@@ -427,6 +429,8 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
427429

428430
u32 cksum;
429431

432+
child_timed_out = 0;
433+
430434
memset(trace_bits, 0, MAP_SIZE);
431435
MEM_BARRIER();
432436

@@ -484,8 +488,13 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
484488
if (*(u32*)trace_bits == EXEC_FAIL_SIG)
485489
FATAL("Unable to execute '%s'", argv[0]);
486490

487-
classify_counts(trace_bits);
488-
apply_mask((u32*)trace_bits, (u32*)mask_bitmap);
491+
if (!hang_mode) {
492+
493+
classify_counts(trace_bits);
494+
apply_mask((u32*)trace_bits, (u32*)mask_bitmap);
495+
496+
}
497+
489498
total_execs++;
490499

491500
if (stop_soon) {
@@ -496,15 +505,35 @@ static u8 run_target(char** argv, u8* mem, u32 len, u8 first_run) {
496505

497506
}
498507

499-
/* Always discard inputs that time out. */
508+
/* Always discard inputs that time out, unless we are in hang mode */
509+
510+
if (hang_mode) {
511+
512+
if (child_timed_out) return 1;
513+
514+
if (WIFSIGNALED(status) ||
515+
(WIFEXITED(status) && WEXITSTATUS(status) == MSAN_ERROR) ||
516+
(WIFEXITED(status) && WEXITSTATUS(status) && exit_crash)) {
517+
518+
missed_crashes++;
519+
520+
} else {
521+
522+
missed_hangs++;
523+
524+
}
525+
526+
return 0;
527+
528+
}
500529

501530
if (child_timed_out) {
502531

503532
missed_hangs++;
504533
return 0;
505534

506535
}
507-
536+
508537
/* Handle crashing inputs depending on current mode. */
509538

510539
if (WIFSIGNALED(status) ||
@@ -791,6 +820,19 @@ static void minimize(char** argv) {
791820

792821
finalize_all:
793822

823+
if (hang_mode) {
824+
825+
SAYF("\n" cGRA " File size reduced by : " cRST
826+
"%0.02f%% (to %u byte%s)\n" cGRA " Characters simplified : " cRST
827+
"%0.02f%%\n" cGRA " Number of execs done : " cRST "%u\n" cGRA
828+
" Fruitless execs : " cRST "termination=%u crash=%u\n\n",
829+
100 - ((double)in_len) * 100 / orig_len, in_len, in_len == 1 ? "" : "s",
830+
((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), total_execs,
831+
missed_paths, missed_crashes);
832+
return;
833+
834+
}
835+
794836
SAYF("\n" cGRA " File size reduced by : " cRST
795837
"%0.02f%% (to %u byte%s)\n" cGRA " Characters simplified : " cRST
796838
"%0.02f%%\n" cGRA " Number of execs done : " cRST "%u\n" cGRA
@@ -799,7 +841,7 @@ static void minimize(char** argv) {
799841
((double)(alpha_d_total)) * 100 / (in_len ? in_len : 1), total_execs,
800842
missed_paths, missed_crashes, missed_hangs ? cLRD : "", missed_hangs);
801843

802-
if (total_execs > 50 && missed_hangs * 10 > total_execs)
844+
if (total_execs > 50 && missed_hangs * 10 > total_execs && !hang_mode)
803845
WARNF(cLRD "Frequent timeouts - results may be skewed." cRST);
804846

805847
}
@@ -978,6 +1020,7 @@ static void usage(u8* argv0) {
9781020

9791021
" -e - solve for edge coverage only, ignore hit counts\n"
9801022
" -x - treat non-zero exit codes as crashes\n\n"
1023+
" -H - minimize a hang (hang mode)\n"
9811024

9821025
"For additional tips, please consult %s/README.md.\n\n"
9831026

@@ -1077,7 +1120,7 @@ int main(int argc, char** argv, char** envp) {
10771120

10781121
SAYF(cCYA "afl-tmin" VERSION cRST " by Michal Zalewski\n");
10791122

1080-
while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeQUWh")) > 0)
1123+
while ((opt = getopt(argc, argv, "+i:o:f:m:t:B:xeQUWHh")) > 0)
10811124

10821125
switch (opt) {
10831126

@@ -1103,6 +1146,7 @@ int main(int argc, char** argv, char** envp) {
11031146
case 'e':
11041147

11051148
if (edges_only) FATAL("Multiple -e options not supported");
1149+
if (hang_mode) FATAL("Edges only and hang mode are mutually exclusive.");
11061150
edges_only = 1;
11071151
break;
11081152

@@ -1188,6 +1232,15 @@ int main(int argc, char** argv, char** envp) {
11881232

11891233
break;
11901234

1235+
case 'H': /* Hang Mode */
1236+
1237+
/* Minimizes a testcase to the minimum that still times out */
1238+
1239+
if (hang_mode) FATAL("Multipe -H options not supported");
1240+
if (edges_only) FATAL("Edges only and hang mode are mutually exclusive.");
1241+
hang_mode = 1;
1242+
break;
1243+
11911244
case 'B': /* load bitmap */
11921245

11931246
/* This is a secret undocumented option! It is speculated to be useful
@@ -1242,6 +1295,13 @@ int main(int argc, char** argv, char** envp) {
12421295

12431296
exact_mode = !!get_afl_env("AFL_TMIN_EXACT");
12441297

1298+
if (hang_mode && exact_mode) {
1299+
1300+
SAYF("AFL_TMIN_EXACT won't work for loops in hang mode, ignoring.");
1301+
exact_mode = 0;
1302+
1303+
}
1304+
12451305
SAYF("\n");
12461306

12471307
read_initial_file();
@@ -1253,10 +1313,18 @@ int main(int argc, char** argv, char** envp) {
12531313

12541314
run_target(use_argv, in_data, in_len, 1);
12551315

1256-
if (child_timed_out)
1257-
FATAL("Target binary times out (adjusting -t may help).");
1316+
if (hang_mode && !child_timed_out)
1317+
FATAL("Target binary did not time out but hang minimization mode "
1318+
"(-H) was set (-t %u).", exec_tmout);
1319+
1320+
if (child_timed_out && !hang_mode)
1321+
FATAL("Target binary times out (adjusting -t may help). Use -H to minimize a hang.");
1322+
1323+
if (hang_mode) {
1324+
1325+
OKF("Program hangs as expected, minimizing in " cCYA "hang" cRST " mode.");
12581326

1259-
if (!crash_mode) {
1327+
} else if (!crash_mode) {
12601328

12611329
OKF("Program terminates normally, minimizing in " cCYA "instrumented" cRST
12621330
" mode.");

0 commit comments

Comments
 (0)