mirror of
https://github.com/lighttransport/tinyusdz.git
synced 2026-01-18 01:11:17 +01:00
Harden LZ4_Decompress.
Add fuzzer for LZ4_Decompress.
This commit is contained in:
@@ -137,6 +137,20 @@ size_t LZ4Compression::DecompressFromBuffer(char const *compressed,
|
||||
|
||||
// Check first byte for # chunks.
|
||||
int nChunks = *compressed++;
|
||||
if (nChunks > 127) {
|
||||
if (err) {
|
||||
(*err) =
|
||||
"Too many chunks in LZ4 compressed data.\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
//std::cout << "compressedSize = " << compressedSize << "\n";
|
||||
//std::cout << "maxOutputSize = " << maxOutputSize << "\n";
|
||||
//std::cout << "nChunks = " << nChunks << "\n";
|
||||
|
||||
size_t consumedCompressedSize = 1;
|
||||
|
||||
if (nChunks == 0) {
|
||||
// Just one.
|
||||
int nDecompressed = LZ4_decompress_safe(compressed, output,
|
||||
@@ -154,14 +168,37 @@ size_t LZ4Compression::DecompressFromBuffer(char const *compressed,
|
||||
} else {
|
||||
// Do each chunk.
|
||||
size_t totalDecompressed = 0;
|
||||
for (int i = 0; i != nChunks; ++i) {
|
||||
for (int i = 0; i < nChunks; ++i) {
|
||||
int32_t chunkSize = 0;
|
||||
memcpy(&chunkSize, compressed, sizeof(chunkSize));
|
||||
if (chunkSize > LZ4_MAX_INPUT_SIZE) {
|
||||
if (err) {
|
||||
(*err) += "ChunkSize exceeds LZ4_MAX_INPUT_SIZE.\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
if (chunkSize <= 0) {
|
||||
if (err) {
|
||||
(*err) += "Invalid ChunkSize.\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//std::cout << "chunkSize = " << chunkSize << "\n";
|
||||
consumedCompressedSize += sizeof(chunkSize);
|
||||
//std::cout << "consumedCompressedSize = " << consumedCompressedSize << "\n";
|
||||
//std::cout << "compressedSize = " << compressedSize << "\n";
|
||||
if (consumedCompressedSize > compressedSize) {
|
||||
if (err) {
|
||||
(*err) += "Total chunk size exceeds input compressedSize.\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
compressed += sizeof(chunkSize);
|
||||
int nDecompressed = LZ4_decompress_safe(
|
||||
compressed, output, chunkSize,
|
||||
int(std::min<size_t>(LZ4_MAX_INPUT_SIZE, maxOutputSize)));
|
||||
if (nDecompressed < 0) {
|
||||
if (nDecompressed <= 0) {
|
||||
if (err) {
|
||||
(*err) =
|
||||
"Failed to decompress data, possibly corrupt? "
|
||||
@@ -170,6 +207,14 @@ size_t LZ4Compression::DecompressFromBuffer(char const *compressed,
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
//std::cout << "nDecompressed = " << nDecompressed << "\n";
|
||||
if (nDecompressed > maxOutputSize) {
|
||||
if (err) {
|
||||
(*err) =
|
||||
"Failed to decompress data, possibly corrupt?\n";
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
compressed += chunkSize;
|
||||
output += nDecompressed;
|
||||
maxOutputSize -= size_t(nDecompressed);
|
||||
|
||||
51
tests/fuzzer/lz4_decompress_fuzzmain.cc
Normal file
51
tests/fuzzer/lz4_decompress_fuzzmain.cc
Normal file
@@ -0,0 +1,51 @@
|
||||
#include <cstdint>
|
||||
#include <cstring>
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
#include "lz4-compression.hh"
|
||||
|
||||
static int lz4_decompress_main(const uint8_t *data, size_t size)
|
||||
{
|
||||
if (size < (16+1)) return -1;
|
||||
|
||||
// first 8 byte: uncompress size
|
||||
// second 8 byte: compress size
|
||||
// 1 byte: # chunks
|
||||
// remaining : compressed data
|
||||
uint64_t uncompressedSize; // nInts
|
||||
uint64_t compressedSize;
|
||||
|
||||
memcpy(&uncompressedSize, data, 8);
|
||||
memcpy(&compressedSize, data+8, 8);
|
||||
|
||||
// FIXME: Currently up to 4GB
|
||||
if ((uncompressedSize < 4) || (uncompressedSize > 1024*1024*4)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if ((compressedSize < 4) || (compressedSize > 1024*1024*4)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (compressedSize > (size - (16+1))) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
std::vector<char> dst;
|
||||
dst.resize(uncompressedSize);
|
||||
|
||||
std::string err;
|
||||
size_t n = tinyusdz::LZ4Compression::DecompressFromBuffer(reinterpret_cast<const char *>(data + 8), dst.data(), compressedSize, uncompressedSize, &err);
|
||||
(void)n;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
extern "C"
|
||||
int LLVMFuzzerTestOneInput(std::uint8_t const* data, std::size_t size)
|
||||
{
|
||||
int ret = lz4_decompress_main(data, size);
|
||||
return ret;
|
||||
}
|
||||
@@ -69,6 +69,15 @@ executable('fuzz_intcoding',
|
||||
cpp_args : '-fsanitize=address,fuzzer',
|
||||
link_args : '-fsanitize=address,fuzzer' )
|
||||
|
||||
executable('fuzz_lz4_decompress',
|
||||
'../../src/lz4/lz4.c',
|
||||
'lz4_decompress_fuzzmain.cc',
|
||||
'../../src/lz4-compression.cc',
|
||||
install: true,
|
||||
include_directories : incdirs,
|
||||
cpp_args : '-fsanitize=address,fuzzer',
|
||||
link_args : '-fsanitize=address,fuzzer' )
|
||||
|
||||
|
||||
executable('fuzz_usdaparser',
|
||||
'usdaparser_fuzzmain.cc',
|
||||
|
||||
Reference in New Issue
Block a user