Skip to content

Commit ddbfee9

Browse files
corporatesharkmeta-codesync[bot]
authored andcommitted
igl | iglu | Bound ktx2 supercompressed level expansion (fixes fuzzer timeout)
Reviewed By: rudybear Differential Revision: D109911238 fbshipit-source-id: a17bd5a63d07b316228f47fa1862875f598c6268
1 parent 1516d40 commit ddbfee9

1 file changed

Lines changed: 17 additions & 0 deletions

File tree

‎IGLU/texture_loader/ktx2/TextureLoaderFactory.cpp‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,9 @@ bool TextureLoaderFactory::validate(DataReader reader,
130130
// yield a bound large enough to let an over-large uncompressedByteLength through. Treat
131131
// any overflow as absurd dimensions and reject.
132132
constexpr uint64_t kMaxBytesPerTexel = 16u; // RGBA32F; >= any uncompressed format
133+
// Maximum plausible expansion ratio for a supercompressed (ZSTD/ZLIB) level. Real texture
134+
// data never approaches this; a decompression bomb exceeds it by orders of magnitude.
135+
constexpr uint64_t kMaxSupercompressionRatio = 1024u;
133136
uint64_t maxLevelBytes = kMaxBytesPerTexel;
134137
for (const uint32_t dimension :
135138
{range.width, range.height, range.depth, range.numLayers, std::max(range.numFaces, 1u)}) {
@@ -159,6 +162,20 @@ bool TextureLoaderFactory::validate(DataReader reader,
159162
"Uncompressed level data exceeds the texture dimensions.");
160163
return false;
161164
}
165+
// For supercompressed levels, uncompressedByteLength sizes the inflate destination
166+
// (ktxTexture2_LoadImageData allocates inflatedDataCapacity, then ktxTexture2_inflate*Int
167+
// spins filling it). The dimension bound above is attacker-influenced: a header declaring
168+
// absurd dimensions (e.g. depth in the millions) inflates maxLevelBytes enough to admit a
169+
// multi-gigabyte uncompressedByteLength, turning a ~1KB compressed payload into a
170+
// multi-second decompression bomb. Independently cap the expansion ratio against the
171+
// compressed size (levelByteLength is already bounded by the input length above).
172+
if (header->supercompressionScheme != 0u &&
173+
levelUncompressedByteLength > levelByteLength * kMaxSupercompressionRatio) {
174+
igl::Result::setResult(outResult,
175+
igl::Result::Code::InvalidOperation,
176+
"Supercompressed level expansion ratio is implausible.");
177+
return false;
178+
}
162179
}
163180

164181
if (header->vkFormat != 0u) {

0 commit comments

Comments
 (0)