1 /* 2 * Copyright (c) Meta Platforms, Inc. and affiliates. 3 * All rights reserved. 4 * 5 * This source code is licensed under both the BSD-style license (found in the 6 * LICENSE file in the root directory of this source tree) and the GPLv2 (found 7 * in the COPYING file in the root directory of this source tree). 8 * You may select, at your option, one of the above-listed licenses. 9 */ 10 11 /** 12 * This fuzz target attempts to decompress the fuzzed data with the simple 13 * decompression function to ensure the decompressor never crashes. 14 */ 15 16 #define ZSTD_STATIC_LINKING_ONLY 17 18 #include <stddef.h> 19 #include <stdlib.h> 20 #include <stdio.h> 21 #include "fuzz_helpers.h" 22 #include "zstd.h" 23 #include "fuzz_data_producer.h" 24 25 static ZSTD_DStream *dstream = NULL; 26 uint32_t seed; 27 28 static ZSTD_outBuffer makeOutBuffer(FUZZ_dataProducer_t *producer, void* buf, size_t bufSize) 29 { 30 ZSTD_outBuffer buffer = { buf, 0, 0 }; 31 32 if (FUZZ_dataProducer_empty(producer)) { 33 buffer.size = bufSize; 34 } else { 35 buffer.size = (FUZZ_dataProducer_uint32Range(producer, 0, bufSize)); 36 } 37 FUZZ_ASSERT(buffer.size <= bufSize); 38 39 if (buffer.size == 0) { 40 buffer.dst = NULL; 41 } 42 43 return buffer; 44 } 45 46 static ZSTD_inBuffer makeInBuffer(const uint8_t **src, size_t *size, 47 FUZZ_dataProducer_t *producer) 48 { 49 ZSTD_inBuffer buffer = { *src, 0, 0 }; 50 51 FUZZ_ASSERT(*size > 0); 52 if (FUZZ_dataProducer_empty(producer)) { 53 buffer.size = *size; 54 } else { 55 buffer.size = (FUZZ_dataProducer_uint32Range(producer, 0, *size)); 56 } 57 FUZZ_ASSERT(buffer.size <= *size); 58 *src += buffer.size; 59 *size -= buffer.size; 60 61 if (buffer.size == 0) { 62 buffer.src = NULL; 63 } 64 65 return buffer; 66 } 67 68 int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) 69 { 70 /* Give a random portion of src data to the producer, to use for 71 parameter generation. The rest will be used for (de)compression */ 72 FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size); 73 int stableOutBuffer; 74 ZSTD_outBuffer out; 75 void* buf; 76 size_t bufSize; 77 size = FUZZ_dataProducer_reserveDataPrefix(producer); 78 bufSize = MAX(10 * size, ZSTD_BLOCKSIZE_MAX); 79 80 /* Allocate all buffers and contexts if not already allocated */ 81 buf = FUZZ_malloc(bufSize); 82 83 if (!dstream) { 84 dstream = ZSTD_createDStream(); 85 FUZZ_ASSERT(dstream); 86 } else { 87 FUZZ_ZASSERT(ZSTD_DCtx_reset(dstream, ZSTD_reset_session_only)); 88 } 89 90 stableOutBuffer = FUZZ_dataProducer_uint32Range(producer, 0, 10) == 5; 91 if (stableOutBuffer) { 92 FUZZ_ZASSERT(ZSTD_DCtx_setParameter(dstream, ZSTD_d_stableOutBuffer, 1)); 93 out.dst = buf; 94 out.size = bufSize; 95 out.pos = 0; 96 } else { 97 out = makeOutBuffer(producer, buf, bufSize); 98 } 99 100 while (size > 0) { 101 ZSTD_inBuffer in = makeInBuffer(&src, &size, producer); 102 do { 103 size_t const rc = ZSTD_decompressStream(dstream, &out, &in); 104 if (ZSTD_isError(rc)) goto error; 105 if (out.pos == out.size) { 106 if (stableOutBuffer) goto error; 107 out = makeOutBuffer(producer, buf, bufSize); 108 } 109 } while (in.pos != in.size); 110 } 111 112 error: 113 #ifndef STATEFUL_FUZZING 114 ZSTD_freeDStream(dstream); dstream = NULL; 115 #endif 116 FUZZ_dataProducer_free(producer); 117 free(buf); 118 return 0; 119 } 120