| 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 | |