SUT patching: Overcoming obstacles #
Codebases are often not fuzzing-friendly. This can happen if, for example, the code uses checksums or depends on a global state like a system-time seeded PRNG (i.e., from the rand) that causes the code to behave differently for the same input. Refer to Practical harness rules to learn more about potential problems in your SUT. If you encounter checksums or a global state in your SUT, you may want to apply fuzzing-specific patches to change the behavior of the program during fuzzing, as shown in the following paragraphs.
Rust fuzzers define a configuration option that is set during compilation of your Rust project. Similar to the
cfg!(test)
config option, the cfg!(fuzzing)
option is enabled during fuzzing. You can use conditional compilation to overcome obstacles in your code, like hash checks that often hinder fuzzers at covering deeper code paths. The following figure shows an example.
Note that this means that your SUT is behaving differently during fuzzing and production. Carelessly skipping checks can lead to false positives during fuzzing. For example, skipping the validation of a config file might lead to crashes in the SUT because the code expects config values to have a certain format. If the validation ensures that the config contains non-zero integers, then code called after the validation could misbehave when zero values are encountered. See the following example for an illustration.
For instance, the ogg crate uses a cfg!(fuzzing)
check to
perform checksum checks only if the project is not being fuzzed. Adding a cfg!(fuzzing)
check can increase fuzzing coverage greatly, but requires source code modifications.