#!/usr/bin/tclsh # # Run this script in order to rebuild the fuzzdata1.txt file containing # fuzzer data for the fuzzershell utility that is create by afl-fuzz. # # This script gathers all of the test cases identified by afl-fuzz and # runs afl-cmin and afl-tmin over them all to try to generate a mimimum # set of tests that cover all observed behavior. # # Options: # # --afl-bin DIR1 DIR1 contains the AFL binaries # --fuzzershell PATH Full pathname of instrumented fuzzershell # --afl-data DIR3 DIR3 is the "-o" directory from afl-fuzz # -o FILE Write results into FILE # set AFLBIN {} set FUZZERSHELL {} set AFLDATA {} set OUTFILE {} proc usage {} { puts stderr "Usage: $::argv0 --afl-bin DIR --fuzzershell PATH\ --afl-data DIR -o FILE" exit 1 } proc cmdlineerr {msg} { puts stderr $msg usage } for {set i 0} {$i<[llength $argv]} {incr i} { set x [lindex $argv $i] if {[string index $x 0]!="-"} {cmdlineerr "illegal argument: $x"} set x [string trimleft $x -] incr i if {$i>=[llength $argv]} {cmdlineerr "no argument on --$x"} set a [lindex $argv $i] switch -- $x { afl-bin {set AFLBIN $a} afl-data {set AFLDATA $a} fuzzershell {set FUZZERSHELL $a} o {set OUTFILE $a} default {cmdlineerr "unknown option: --$x"} } } proc checkarg {varname option} { set val [set ::$varname] if {$val==""} {cmdlineerr "required option missing: --$option"} } checkarg AFLBIN afl-bin checkarg AFLDATA afl-data checkarg FUZZERSHELL fuzzershell checkarg OUTFILE o proc checkexec {x} { if {![file exec $x]} {cmdlineerr "cannot find $x"} } checkexec $AFLBIN/afl-cmin checkexec $AFLBIN/afl-tmin checkexec $FUZZERSHELL proc checkdir {x} { if {![file isdir $x]} {cmdlineerr "no such directory: $x"} } checkdir $AFLDATA/queue proc progress {msg} { puts "******** $msg" flush stdout } progress "mkdir tmp1 tmp2" file mkdir tmp1 tmp2 progress "copying test cases from $AFLDATA into tmp1..." set n 0 foreach file [glob -nocomplain $AFLDATA/queue/id:*] { incr n file copy $file tmp1/$n } foreach file [glob -nocomplain $AFLDATA/crash*/id:*] { incr n file copy $file tmp1/$n } progress "total $n files copied." progress "running: $AFLBIN/afl-cmin -i tmp1 -o tmp2 $FUZZERSHELL" exec $AFLBIN/afl-cmin -i tmp1 -o tmp2 $FUZZERSHELL >&@ stdout progress "afl-cmin complete." # # Experiments show that running afl-tmin is too slow for this application. # And it doesn't really make the test cases that much smaller. So let's # just skip it. # # foreach file [glob tmp2/*] { # progress "$AFLBIN/afl-tmin -i $file -o tmp3/[file tail $file] $FUZZERSHELL" # exec $AFLBIN/afl-tmin -i $file -o tmp3/[file tail $file] \ # $FUZZERSHELL >&@ stdout # } progress "generating final output into $OUTFILE" set out [open $OUTFILE wb] puts $out "# Test data for use with fuzzershell. Automatically # generated using $argv0. This file contains binary data #" set n 0 foreach file [glob tmp2/*] { incr n puts -nonewline $out "/****<$n>****/" set in [open $file rb] puts -nonewline $out [read $in] close $in } close $out progress "done. $n test cases written to $OUTFILE" progress "clean-up..." file delete -force tmp1 progress "culled test cases left in the tmp2 directory"