1*abe9b37fSMatt Johnston# Fuzzing libpldm 2*abe9b37fSMatt Johnston 3*abe9b37fSMatt Johnston## Firmware FD Responder 4*abe9b37fSMatt Johnston 5*abe9b37fSMatt Johnston`tests/fuzz/fd-fuzz.cpp` exercises the FD responder implementation. It can run 6*abe9b37fSMatt Johnstonwith various fuzzing engines - either AFL++, honggfuzz, or libfuzzer. 7*abe9b37fSMatt Johnston 8*abe9b37fSMatt JohnstonEach fuzz corpus input is split into two parts. The first 1024 bytes is a 9*abe9b37fSMatt Johnston"control" stream which used to randomise certain events in the fuzzer, such as 10*abe9b37fSMatt Johnstonreturning failure from callbacks, or choosing whether to receive a message or 11*abe9b37fSMatt Johnstonrun progress. 12*abe9b37fSMatt Johnston 13*abe9b37fSMatt JohnstonThe remainder of the fuzz input is taken as an stream of `length:data` PLDM 14*abe9b37fSMatt Johnstonpacket contents, as passed to `pldm_fd_handle_msg()`. 15*abe9b37fSMatt Johnston 16*abe9b37fSMatt Johnston## Build 17*abe9b37fSMatt Johnston 18*abe9b37fSMatt JohnstonFrom the top level libpldm directory, run `./tests/fuzz/fuzz-build.py`. That 19*abe9b37fSMatt Johnstonwill produce several build variants required for different fuzz engines/stages. 20*abe9b37fSMatt Johnston 21*abe9b37fSMatt Johnston## Honggfuzz 22*abe9b37fSMatt Johnston 23*abe9b37fSMatt Johnston[Honggfuzz](https://github.com/google/honggfuzz) handles running across multiple 24*abe9b37fSMatt Johnstonthreads itself with a single corpus directory, which is easy to work with. It 25*abe9b37fSMatt Johnstonneeds to be built from source. 26*abe9b37fSMatt Johnston 27*abe9b37fSMatt JohnstonRun with 28*abe9b37fSMatt Johnston 29*abe9b37fSMatt Johnston``` 30*abe9b37fSMatt Johnstonnice honggfuzz -i corpusdir --linux_perf_branch --dict tests/fuzz/fd.dict -- ./bhf/tests/fuzz/fd-fuzz 31*abe9b37fSMatt Johnston``` 32*abe9b37fSMatt Johnston 33*abe9b37fSMatt JohnstonThe `--linux_perf_branch` switch is optional, it requires permissions for perf 34*abe9b37fSMatt Johnstoncounters: 35*abe9b37fSMatt Johnston 36*abe9b37fSMatt Johnston``` 37*abe9b37fSMatt Johnstonecho 0 | sudo tee /proc/sys/kernel/perf_event_paranoid 38*abe9b37fSMatt Johnston``` 39*abe9b37fSMatt Johnston 40*abe9b37fSMatt JohnstonOptionally a thread count can be given, 24 threads on a 12 core system seems to 41*abe9b37fSMatt Johnstongive best utilisation (`--nthreads 24`). 42*abe9b37fSMatt Johnston 43*abe9b37fSMatt JohnstonThe corpus directory can be reused between runs with different fuzzers. For a 44*abe9b37fSMatt Johnstontotally fresh start, copy in `tests/fuzz/fd-fuzz-input1.dat`, a sample 45*abe9b37fSMatt Johnstonhandcrafted input. 46*abe9b37fSMatt Johnston 47*abe9b37fSMatt Johnston## AFL++ 48*abe9b37fSMatt Johnston 49*abe9b37fSMatt JohnstonRunning a single instance (just for testing): 50*abe9b37fSMatt Johnston 51*abe9b37fSMatt Johnston``` 52*abe9b37fSMatt Johnstonafl-fuzz -i fuzzrun/hf11/ -o fuzzrun/out12single ./bfuzz/tests/fuzz/fd-fuzz 53*abe9b37fSMatt Johnston``` 54*abe9b37fSMatt Johnston 55*abe9b37fSMatt JohnstonAFL++ requires a separate GUI instantiation for each CPU thread. The helper 56*abe9b37fSMatt Johnston[AFL Runner](https://github.com/0xricksanchez/afl_runner) makes that easier. 57*abe9b37fSMatt Johnston 58*abe9b37fSMatt JohnstonRunning with 20 threads: 59*abe9b37fSMatt Johnston 60*abe9b37fSMatt Johnston``` 61*abe9b37fSMatt Johnstonnice aflr run -t bfuzz/tests/fuzz/fd-fuzz -i workdir/out5/m_fd-fuzz/queue -o workdir/out6 -c bcmplog/tests/fuzz/fd-fuzz -s bfuzzasan/tests/fuzz/fd-fuzz -n 20 -x tests/fuzz/fd.dict --session-name fuzz 62*abe9b37fSMatt Johnston``` 63*abe9b37fSMatt Johnston 64*abe9b37fSMatt JohnstonKill it with `aflr kill fuzz`. 65*abe9b37fSMatt Johnston 66*abe9b37fSMatt Johnston`aflr tui workdir/out6` could be used to view progress, though its calculations 67*abe9b37fSMatt Johnstonmay be inaccurate if some runners are idle. Another option is 68*abe9b37fSMatt Johnston`afl-whatsup workdir/out6`. 69*abe9b37fSMatt Johnston 70*abe9b37fSMatt Johnston## Coverage 71*abe9b37fSMatt Johnston 72*abe9b37fSMatt JohnstonThe coverage provided by a corpus directory can be reported using 73*abe9b37fSMatt Johnston`tests/fuzz/fuzz-coverage.py`. 74*abe9b37fSMatt Johnston 75*abe9b37fSMatt JohnstonIt will: 76*abe9b37fSMatt Johnston 77*abe9b37fSMatt Johnston- Run a binary compiled with `--coverage` against each corpus file 78*abe9b37fSMatt Johnston- Use [grcov](https://github.com/mozilla/grcov) to aggregate the coverage traces 79*abe9b37fSMatt Johnston (much faster than lcov). 80*abe9b37fSMatt Johnston- Use `genhtml` to create a report 81*abe9b37fSMatt Johnston 82*abe9b37fSMatt JohnstonTypical usage, with corpus in `fuzzrun/corpus`: 83*abe9b37fSMatt Johnston 84*abe9b37fSMatt Johnston``` 85*abe9b37fSMatt Johnston./tests/fuzz/fuzz-coverage.py fuzzrun/corpus bnoopt/tests/fuzz/fd-fuzz . bnoopt/ coverage-output 86*abe9b37fSMatt Johnston``` 87*abe9b37fSMatt Johnston 88*abe9b37fSMatt Johnston## Reproducing crashes 89*abe9b37fSMatt Johnston 90*abe9b37fSMatt JohnstonWhen the fuzz run encounters a crash, the testcase can be run against the built 91*abe9b37fSMatt Johnstontarget manually, and stepped through with GDB etc. 92*abe9b37fSMatt Johnston 93*abe9b37fSMatt Johnston``` 94*abe9b37fSMatt Johnstonenv TRACEFWFD=1 ./bnoopt/tests/fuzz/fd-fuzz < crashing.bin 95*abe9b37fSMatt Johnston``` 96*abe9b37fSMatt Johnston 97*abe9b37fSMatt JohnstonThe `printf`s are disabled by default to improve normal fuzzing speed. 98