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 makes sure that whenever a compression dictionary can be 13*3117ece4Schristos * loaded, the data can be round tripped. 14*3117ece4Schristos */ 15*3117ece4Schristos 16*3117ece4Schristos #include <stddef.h> 17*3117ece4Schristos #include <stdlib.h> 18*3117ece4Schristos #include <stdio.h> 19*3117ece4Schristos #include <string.h> 20*3117ece4Schristos #include "fuzz_helpers.h" 21*3117ece4Schristos #include "zstd_helpers.h" 22*3117ece4Schristos #include "fuzz_data_producer.h" 23*3117ece4Schristos #include "fuzz_third_party_seq_prod.h" 24*3117ece4Schristos 25*3117ece4Schristos /** 26*3117ece4Schristos * Compresses the data and returns the compressed size or an error. 27*3117ece4Schristos */ 28*3117ece4Schristos static size_t compress(void* compressed, size_t compressedCapacity, 29*3117ece4Schristos void const* source, size_t sourceSize, 30*3117ece4Schristos void const* dict, size_t dictSize, 31*3117ece4Schristos ZSTD_dictLoadMethod_e dictLoadMethod, 32*3117ece4Schristos ZSTD_dictContentType_e dictContentType, 33*3117ece4Schristos int const refPrefix) 34*3117ece4Schristos { 35*3117ece4Schristos ZSTD_CCtx* cctx = ZSTD_createCCtx(); 36*3117ece4Schristos if (refPrefix) 37*3117ece4Schristos FUZZ_ZASSERT(ZSTD_CCtx_refPrefix_advanced( 38*3117ece4Schristos cctx, dict, dictSize, dictContentType)); 39*3117ece4Schristos else 40*3117ece4Schristos FUZZ_ZASSERT(ZSTD_CCtx_loadDictionary_advanced( 41*3117ece4Schristos cctx, dict, dictSize, dictLoadMethod, dictContentType)); 42*3117ece4Schristos size_t const compressedSize = ZSTD_compress2( 43*3117ece4Schristos cctx, compressed, compressedCapacity, source, sourceSize); 44*3117ece4Schristos ZSTD_freeCCtx(cctx); 45*3117ece4Schristos return compressedSize; 46*3117ece4Schristos } 47*3117ece4Schristos 48*3117ece4Schristos static size_t decompress(void* result, size_t resultCapacity, 49*3117ece4Schristos void const* compressed, size_t compressedSize, 50*3117ece4Schristos void const* dict, size_t dictSize, 51*3117ece4Schristos ZSTD_dictLoadMethod_e dictLoadMethod, 52*3117ece4Schristos ZSTD_dictContentType_e dictContentType, 53*3117ece4Schristos int const refPrefix) 54*3117ece4Schristos { 55*3117ece4Schristos ZSTD_DCtx* dctx = ZSTD_createDCtx(); 56*3117ece4Schristos if (refPrefix) 57*3117ece4Schristos FUZZ_ZASSERT(ZSTD_DCtx_refPrefix_advanced( 58*3117ece4Schristos dctx, dict, dictSize, dictContentType)); 59*3117ece4Schristos else 60*3117ece4Schristos FUZZ_ZASSERT(ZSTD_DCtx_loadDictionary_advanced( 61*3117ece4Schristos dctx, dict, dictSize, dictLoadMethod, dictContentType)); 62*3117ece4Schristos size_t const resultSize = ZSTD_decompressDCtx( 63*3117ece4Schristos dctx, result, resultCapacity, compressed, compressedSize); 64*3117ece4Schristos FUZZ_ZASSERT(resultSize); 65*3117ece4Schristos ZSTD_freeDCtx(dctx); 66*3117ece4Schristos return resultSize; 67*3117ece4Schristos } 68*3117ece4Schristos 69*3117ece4Schristos int LLVMFuzzerTestOneInput(const uint8_t *src, size_t size) 70*3117ece4Schristos { 71*3117ece4Schristos FUZZ_SEQ_PROD_SETUP(); 72*3117ece4Schristos FUZZ_dataProducer_t *producer = FUZZ_dataProducer_create(src, size); 73*3117ece4Schristos int const refPrefix = FUZZ_dataProducer_uint32Range(producer, 0, 1) != 0; 74*3117ece4Schristos ZSTD_dictLoadMethod_e const dlm = 75*3117ece4Schristos size = FUZZ_dataProducer_uint32Range(producer, 0, 1); 76*3117ece4Schristos ZSTD_dictContentType_e const dct = 77*3117ece4Schristos FUZZ_dataProducer_uint32Range(producer, 0, 2); 78*3117ece4Schristos size = FUZZ_dataProducer_remainingBytes(producer); 79*3117ece4Schristos 80*3117ece4Schristos DEBUGLOG(2, "Dict load method %d", dlm); 81*3117ece4Schristos DEBUGLOG(2, "Dict content type %d", dct); 82*3117ece4Schristos DEBUGLOG(2, "Dict size %u", (unsigned)size); 83*3117ece4Schristos 84*3117ece4Schristos void* const rBuf = FUZZ_malloc(size); 85*3117ece4Schristos size_t const cBufSize = ZSTD_compressBound(size); 86*3117ece4Schristos void* const cBuf = FUZZ_malloc(cBufSize); 87*3117ece4Schristos 88*3117ece4Schristos size_t const cSize = 89*3117ece4Schristos compress(cBuf, cBufSize, src, size, src, size, dlm, dct, refPrefix); 90*3117ece4Schristos /* compression failing is okay */ 91*3117ece4Schristos if (ZSTD_isError(cSize)) { 92*3117ece4Schristos FUZZ_ASSERT_MSG(dct != ZSTD_dct_rawContent, "Raw must always succeed!"); 93*3117ece4Schristos goto out; 94*3117ece4Schristos } 95*3117ece4Schristos size_t const rSize = 96*3117ece4Schristos decompress(rBuf, size, cBuf, cSize, src, size, dlm, dct, refPrefix); 97*3117ece4Schristos FUZZ_ASSERT_MSG(rSize == size, "Incorrect regenerated size"); 98*3117ece4Schristos FUZZ_ASSERT_MSG(!FUZZ_memcmp(src, rBuf, size), "Corruption!"); 99*3117ece4Schristos 100*3117ece4Schristos out: 101*3117ece4Schristos free(cBuf); 102*3117ece4Schristos free(rBuf); 103*3117ece4Schristos FUZZ_dataProducer_free(producer); 104*3117ece4Schristos FUZZ_SEQ_PROD_TEARDOWN(); 105*3117ece4Schristos return 0; 106*3117ece4Schristos } 107