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