microsoft/openvmm
Publicmirrored fromhttps://github.com/microsoft/openvmmAvailable
Guide/src/dev_guide/tests/fuzzing/running.md
169lines · modecode
| 1 | # Running Fuzzers Locally |
| 2 | |
| 3 | ## Installing Dependencies |
| 4 | |
| 5 | To begin fuzzing in OpenVMM, you'll need to install `cargo-fuzz` and a nightly |
| 6 | rust compiler. |
| 7 | |
| 8 | Installation should be as simple as: |
| 9 | |
| 10 | ```bash |
| 11 | rustup install nightly |
| 12 | cargo install cargo-fuzz |
| 13 | ``` |
| 14 | |
| 15 | ```admonish info |
| 16 | `cargo-fuzz` requires a nightly toolchain as it compiles targets with |
| 17 | [ASAN](https://learn.microsoft.com/en-us/cpp/sanitizers/asan?view=msvc-170) to |
| 18 | improve the likelihood of finding bugs and the reproducibility of testcases. |
| 19 | ``` |
| 20 | |
| 21 | ## Running |
| 22 | |
| 23 | While its entirely possible to run the various fuzzers in the OpenVMM repo using |
| 24 | `cargo fuzz` directly, the OpenVMM repo includes additional tooling to streamline |
| 25 | working with fuzzers at "OpenVMM scale": `cargo xtask fuzz` |
| 26 | |
| 27 | `cargo xtask fuzz` bridges the gap between `cargo fuzz`'s "crate-oriented" |
| 28 | tooling, and OpenVMM's "repo-oriented" tooling. |
| 29 | |
| 30 | e.g: instead of manually navigating to each individual `crate/fuzz` directory in |
| 31 | order to use `cargo fuzz`, with `cargo xtask fuzz`, you can list/run/build _any_ |
| 32 | fuzzer in the OpenVMM repo, regardless where it happens to be in the repo! |
| 33 | |
| 34 | Before you can run a fuzzer, you need to know its name. To see a list of all |
| 35 | fuzzers currently in the OpenVMM tree, you can run: |
| 36 | |
| 37 | ```bash |
| 38 | cargo xtask fuzz list |
| 39 | ``` |
| 40 | |
| 41 | The output will be a list of available "fuzz targets": |
| 42 | |
| 43 | ``` |
| 44 | $ cargo xtask fuzz list |
| 45 | fuzz_chipset_battery |
| 46 | fuzz_ide |
| 47 | fuzz_scsi_buffers |
| 48 | ``` |
| 49 | |
| 50 | Once you've got a fuzzer you're interested in running (e.g: `fuzz_ide`), |
| 51 | starting a fuzzing session is as easy as running: |
| 52 | |
| 53 | ```bash |
| 54 | cargo xtask fuzz run fuzz_ide |
| 55 | ``` |
| 56 | |
| 57 | And you're off! If you see a whole bunch of terminal spew, congrats, you're |
| 58 | fuzzing! |
| 59 | |
| 60 | When run locally using the above command, the fuzzer will run indefinitely until |
| 61 | a crash is discovered. |
| 62 | |
| 63 | If you need to tweak the runtime behavior of the command, all of libFuzzer's |
| 64 | [commandline options][cli-opts] are at your disposal. Alternatively you can |
| 65 | print the help of the fuzzer like so: |
| 66 | |
| 67 | ```bash |
| 68 | # NOTE: The "-- --" is required to differentiate between `xtask fuzz`'s |
| 69 | # extra-args, and `cargo fuzz`'s extra-args |
| 70 | cargo xtask fuzz run fuzz_ide -- -- -help=1 |
| 71 | ``` |
| 72 | |
| 73 | [cli-opts]: https://www.llvm.org/docs/LibFuzzer.html#options |
| 74 | [toolchain-overrides-url]: https://rust-lang.github.io/rustup/overrides.html |
| 75 | |
| 76 | ## Other Fuzzing Commands |
| 77 | |
| 78 | The `cargo xtask fuzz` CLI includes plenty of docs via `--help` text. Don't be |
| 79 | afraid to dig into all the tools available via `cargo xtask fuzz` by using |
| 80 | `--help` at both the top-level, and for more details regarding the various |
| 81 | subcommands. |
| 82 | |
| 83 | Note that most `cargo xtask fuzz` commands mirror those from `cargo fuzz`, so |
| 84 | for additional information on how certain commands work, check out the |
| 85 | [cargo-fuzz book](https://rust-fuzz.github.io/book/cargo-fuzz.html). |
| 86 | |
| 87 | ## Coverage |
| 88 | |
| 89 | The effectiveness of fuzzing can be measured with code coverage. |
| 90 | |
| 91 | Code coverage can be analyzed to determine which branches in the target were |
| 92 | exercised and which were missed by the fuzzer. This can be used to determine if |
| 93 | the fuzzer needs improvements or is doing an adequate job. |
| 94 | |
| 95 | Before you begin you'll need some additional dependencies to generate an html |
| 96 | report: |
| 97 | |
| 98 | ```bash |
| 99 | rustup +nightly component add llvm-tools |
| 100 | apt install lcov |
| 101 | ``` |
| 102 | |
| 103 | To generate a report with "sane defaults", you can simply run: |
| 104 | |
| 105 | ```bash |
| 106 | cargo xtask fuzz coverage fuzz_ide --with-html-report |
| 107 | ``` |
| 108 | |
| 109 | Simply navigate to the `html/report/dir/index.html`` on your machine and inspect the coverage! |
| 110 | |
| 111 |  |
| 112 | |
| 113 | ```admonish note |
| 114 | `--with-html-report` offers a quick-and-easy way for an individual user |
| 115 | generate a coverage report locally, but it may not be entirely appropriate for |
| 116 | more "industrial scale" fuzzing pipelines. |
| 117 | ``` |
| 118 | |
| 119 | ### Manual Coverage Generation (Advanced) |
| 120 | |
| 121 | The basic way this is done is by running all the discovered input testcases |
| 122 | through the fuzzer and merging all the coverage events together (remember, the |
| 123 | fuzzers only save testcases which generate new coverage). Cargo-fuzz provides a |
| 124 | way to do this with the `coverage` subcommand. This step generates a |
| 125 | `coverage.profdata` file which can be turned into a human-readable HTML report: |
| 126 | |
| 127 | ```bash |
| 128 | # cargo xtask fuzz coverage <fuzzer name> |
| 129 | cargo xtask fuzz coverage fuzz_ide |
| 130 | # confirm coverage.profdata was created |
| 131 | ls -l coverage.profdata |
| 132 | ``` |
| 133 | |
| 134 | OR if you have a large number of inputs (5k+) the below will collect and merge |
| 135 | coverage significantly faster: |
| 136 | |
| 137 | ```bash |
| 138 | # rebuild the fuzzer with coverage instrumentation |
| 139 | RUSTFLAGS="-C instrument-coverage" cargo +nightly fuzz build |
| 140 | # set env var to rustup's llvm-preview tools |
| 141 | LLVM_TOOLS_PATH=$(dirname $(find $(rustc +nightly --print sysroot) -name 'llvm-profdata')) |
| 142 | # make an output directory for corups minimation |
| 143 | mkdir min_corp |
| 144 | # run the minimizer putting the raw cov data into coverage.profraw |
| 145 | LLVM_PROFILE_FILE="coverage.profraw" ./fuzz/targets/<target-path>/release/fuzz_ide min_corp <path to input corpus directory> -merge=1 |
| 146 | # merge the raw data into coverage.profdata |
| 147 | $LLVM_TOOLS_PATH/llvm-profdata merge -sparse coverage.profraw -o coverage.profdata |
| 148 | ``` |
| 149 | |
| 150 | Next find the location of the llvm-tools you installed with rustup |
| 151 | (NOTE: rustup is used to install the LLVM tools to ensure that rust's llvm |
| 152 | version and the tool version are in sync), and convert the coverage data into |
| 153 | a report: |
| 154 | |
| 155 | ```bash |
| 156 | # set env var to rustup's llvm-preview tools |
| 157 | LLVM_TOOLS_PATH=$(dirname $(find $(rustc +nightly --print sysroot) -name 'llvm-profdata')) |
| 158 | # covert the coverage data into an lcov format |
| 159 | $LLVM_TOOLS_PATH/llvm-cov export -instr-profile=coverage.profdata \ |
| 160 | -format=lcov \ |
| 161 | -object ./fuzz/targets/<target-triple>/coverage/<target-triple>/release/fuzz_ide \ |
| 162 | --ignore-filename-regex "rustc" > coverage.lcov |
| 163 | # summarize the coverage information |
| 164 | lcov --summary ./coverage.lcov |
| 165 | # make an output directory for the html report |
| 166 | mkdir -p lcov_html |
| 167 | # generate the html report |
| 168 | genhtml -o lcov_html --legend --highlight ./coverage.lcov |
| 169 | ``` |
| 170 | |