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