1 | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. |
2 | // See https://llvm.org/LICENSE.txt for license information. |
3 | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception |
4 | |
5 | // A fuzz target that consumes a Zlib-compressed input. |
6 | // This test verifies that we can find this bug with a custom mutator. |
7 | #include <cstddef> |
8 | #include <cstdint> |
9 | #include <cstdio> |
10 | #include <cstdlib> |
11 | #include <zlib.h> |
12 | |
13 | // The fuzz target. |
14 | // Uncompress the data, crash on input starting with "FU". |
15 | // Good luck finding this w/o a custom mutator. :) |
16 | extern "C" int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { |
17 | uint8_t Uncompressed[100]; |
18 | size_t UncompressedLen = sizeof(Uncompressed); |
19 | if (Z_OK != uncompress(dest: Uncompressed, destLen: &UncompressedLen, source: Data, sourceLen: Size)) |
20 | return 0; |
21 | if (UncompressedLen < 2) return 0; |
22 | if (Uncompressed[0] == 'F' && Uncompressed[1] == 'U') |
23 | abort(); // Boom |
24 | return 0; |
25 | } |
26 | |
27 | #ifdef CUSTOM_MUTATOR |
28 | |
29 | // Forward-declare the libFuzzer's mutator callback. |
30 | extern "C" size_t |
31 | LLVMFuzzerMutate(uint8_t *Data, size_t Size, size_t MaxSize); |
32 | |
33 | // The custom mutator: |
34 | // * deserialize the data (in this case, uncompress). |
35 | // * If the data doesn't deserialize, create a properly serialized dummy. |
36 | // * Mutate the deserialized data (in this case, just call LLVMFuzzerMutate). |
37 | // * Serialize the mutated data (in this case, compress). |
38 | extern "C" size_t LLVMFuzzerCustomMutator(uint8_t *Data, size_t Size, |
39 | size_t MaxSize, unsigned int Seed) { |
40 | uint8_t Uncompressed[100]; |
41 | size_t UncompressedLen = sizeof(Uncompressed); |
42 | size_t CompressedLen = MaxSize; |
43 | if (Z_OK != uncompress(Uncompressed, &UncompressedLen, Data, Size)) { |
44 | // The data didn't uncompress. |
45 | // So, it's either a broken input and we want to ignore it, |
46 | // or we've started fuzzing from an empty corpus and we need to supply |
47 | // out first properly compressed input. |
48 | uint8_t Dummy[] = {'H', 'i'}; |
49 | if (Z_OK != compress(Data, &CompressedLen, Dummy, sizeof(Dummy))) |
50 | return 0; |
51 | // fprintf(stderr, "Dummy: max %zd res %zd\n", MaxSize, CompressedLen); |
52 | return CompressedLen; |
53 | } |
54 | UncompressedLen = |
55 | LLVMFuzzerMutate(Uncompressed, UncompressedLen, sizeof(Uncompressed)); |
56 | if (Z_OK != compress(Data, &CompressedLen, Uncompressed, UncompressedLen)) |
57 | return 0; |
58 | return CompressedLen; |
59 | } |
60 | |
61 | #endif // CUSTOM_MUTATOR |
62 | |