xref: /openbmc/libpldm/docs/fuzzing.md (revision abe9b37f49a1ccda64a728e79858d9eae2d2edd3)
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