ImageIO fuzzing target example
This directory contains an example harness for fuzzing image parsers on macOS.
Build Jackalope as explained in the main README. To start a fuzzing session, run
./fuzzer -in in -out out -t 200 -t1 5000 -delivery shmem -instrument_module ImageIO -target_module test_imageio -target_method _fuzz -nargs 1 -iterations 1000 -persist -loop -cmp_coverage -generate_unwind -- ../examples/ImageIO/Release/test_imageio -m @@
Explanation of the flags
-inand-outare the input corpus directory and the output directory.-tis the sample processing timeout in milliseconds, while-t1is the initialization timeout. Separating these allows us to give the process plenty of time to reach the desired functionality, but filter out samples that take too long to process.-delivery shmemmeans we are passing a sample to the target over shared memory.-instrument_module ImageIOmeans we will be collecting coverage from theImageIOmodule. This can be replaced according to the format being fuzzed. More on that later.-target_module test_imageio -target_method _fuzz -nargs 1 -iterations 1000 -persist -loopflags configure Jackalope's persistent fuzzing mode. In combination, these flags mean that Jackalope is going to run the functionfuzzin moduletest_imageioin a loop for every fuzzing iteration without restarting the process. The process is going to be periodically restarted after 1000 iteration (if not sooner due to other events).-cmp_coverageenables TinyInst's cmp coverage, which enables the fuzzer to bruteforce through multibyte comparisons.-generate_unwindis needed if the target throws C++ exceptions (which is going to be the case here).
test_imageio -m @@ is the command line of the target. As you can see in the source code of the imageio harness, -m means the harness is going to read the sample from shared memory whose name is in the next parameter. @@ is the special parameter which Jackalope is going to replace with the name of the shared memory object.
If you want to test a sample from a file (e.g. if you find a crash), you can invoke the target as test_imageio -f <filename>
Parsers for different image formats are implemented in different modules. The example above uses -instrument_module ImageIO and ImageIO indeed implements some image format parsers, but you should select a format, find out which module handles its parsing and use that instead. To find out which modules are loaded for a particular input file, you can run
../TinyInst/Release/litecov -trace_debug_events -- ../examples/ImageIO/Release/test_imageio -f <filename>
which will print the module names when they get loaded.
Other useful flags:
-nthreads <number>speeds up your fuzzing session by running on multiple threads in parallel.-mem_limit <megabytes>. Sometimes, fuzzing image files produces images with large dimensions that require a lot of memory and cause slowdowns. You can avoid saving those to the fuzzing corpus by setting a memory limit for the target process.-target_env DYLD_INSERT_LIBRARIES=/usr/lib/libgmalloc.dylibto fuzz witg Guard Malloc. Slower, but enables catching memory issues that might not cause a (reliable) crash otherwise.