Joe Gregorio | 02f7202 | 2021-03-27 10:12:45 -0400 | [diff] [blame^] | 1 | |
| 2 | --- |
| 3 | title: "Fuzzing" |
| 4 | linkTitle: "Fuzzing" |
| 5 | |
| 6 | --- |
| 7 | |
| 8 | |
| 9 | Reproducing using `fuzz` |
| 10 | ------------------------ |
| 11 | |
| 12 | We assume that you can [build Skia](/user/build). Many fuzzes only reproduce |
| 13 | when building with ASAN or MSAN; see [those instructions for more details](./xsan). |
| 14 | |
| 15 | When building, you should add the following args to BUILD.gn to make reproducing |
| 16 | less machine- and platform- dependent: |
| 17 | |
| 18 | skia_use_fontconfig=false |
| 19 | skia_use_freetype=true |
| 20 | skia_use_system_freetype2=false |
| 21 | skia_use_wuffs=true |
| 22 | skia_enable_skottie=true |
| 23 | skia_enable_fontmgr_custom_directory=false |
| 24 | skia_enable_fontmgr_custom_embedded=false |
| 25 | skia_enable_fontmgr_custom_empty=true |
| 26 | |
| 27 | All that is needed to reproduce a fuzz downloaded from ClusterFuzz or oss-fuzz is to |
| 28 | run something like: |
| 29 | |
| 30 | out/ASAN/fuzz -b /path/to/downloaded/testcase |
| 31 | |
| 32 | The fuzz binary will try its best to guess what the type/name should be based on |
| 33 | the name of the testcase. Manually providing type and name is also supported, like: |
| 34 | |
| 35 | out/ASAN/fuzz -t filter_fuzz -b /path/to/downloaded/testcase |
| 36 | out/ASAN/fuzz -t api -n RasterN32Canvas -b /path/to/downloaded/testcase |
| 37 | |
| 38 | To enumerate all supported types and names, run the following: |
| 39 | |
| 40 | out/ASAN/fuzz --help # will list all types |
| 41 | out/ASAN/fuzz -t api # will list all names |
| 42 | |
| 43 | If the crash does not show up, try to add the flag --loops: |
| 44 | |
| 45 | out/ASAN/fuzz -b /path/to/downloaded/testcase --loops <times-to-run> |
| 46 | |
| 47 | Writing fuzzers with libfuzzer |
| 48 | ------------------------------ |
| 49 | |
| 50 | libfuzzer is an easy way to write new fuzzers, and how we run them on oss-fuzz. |
| 51 | Your fuzzer entry point should implement this API: |
| 52 | |
| 53 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t*, size_t); |
| 54 | |
| 55 | First install Clang and libfuzzer, e.g. |
| 56 | |
| 57 | sudo apt install clang-10 libc++-10-dev libfuzzer-10-dev |
| 58 | |
| 59 | You should now be able to use `-fsanitize=fuzzer` with Clang. |
| 60 | |
| 61 | Set up GN args to use libfuzzer: |
| 62 | |
| 63 | cc = "clang-10" |
| 64 | cxx = "clang++-10" |
| 65 | sanitize = "fuzzer" |
| 66 | extra_cflags = [ "-O1" ] # Or whatever you want. |
| 67 | ... |
| 68 | |
| 69 | Build Skia and your fuzzer entry point: |
| 70 | |
| 71 | ninja -C out/libfuzzer skia |
| 72 | clang++-10 -I. -O1 -fsanitize=fuzzer fuzz/oss_fuzz/whatever.cpp out/libfuzzer/libskia.a |
| 73 | |
| 74 | Run your new fuzzer binary |
| 75 | |
| 76 | ./a.out |
| 77 | |
| 78 | |
| 79 | Fuzzing Defines |
| 80 | --------------- |
| 81 | There are some defines that can help guide a fuzzer to be more productive (e.g. avoid OOMs, avoid |
| 82 | unnecessarily slow code). |
| 83 | |
| 84 | // Required for fuzzing with afl-fuzz to prevent OOMs from adding noise. |
| 85 | SK_BUILD_FOR_AFL_FUZZ |
| 86 | |
| 87 | // Required for fuzzing with libfuzzer |
| 88 | SK_BUILD_FOR_LIBFUZZER |
| 89 | |
| 90 | // This define adds in guards to abort when we think some code path will take a long time or |
| 91 | // use a lot of RAM. It is set by default when either of the above defines are set. |
| 92 | SK_BUILD_FOR_FUZZER |
| 93 | |