reject out-of-range numFrames in seekable seek table loader

This commit is contained in:
Saleem Malik 2026-07-29 18:09:24 +05:30
parent 5c7b7bad26
commit 19d806eb0f
2 changed files with 30 additions and 0 deletions

View file

@ -6,6 +6,7 @@
#include <string.h>
#include "../zstd_seekable.h"
#include "zstd_errors.h"
/* ZSTD_seekable_customFile implementation that reads/seeks a buffer while keeping track of total bytes read */
@ -365,6 +366,28 @@ int main(int argc, const char** argv)
}
printf("Success!\n");
printf("Test %u - reject seek table with numFrames beyond format max: ", testNb++);
{ /* A corrupt footer claiming numFrames > ZSTD_SEEKABLE_MAXFRAMES must be
* rejected up front: such a value overflows the seek table size math. */
const uint8_t compressed_data[17] = {
0x5e, 0x2a, 0x4d, 0x18, /* skippable frame magic (| 0xE) */
0x09, 0x00, 0x00, 0x00, /* skippable frame size = 9 */
0x01, 0x00, 0x00, 0x08, /* footer: numFrames = 0x08000001 */
0x00, /* footer: seek table descriptor */
0xb1, 0xea, 0x92, 0x8f, /* seekable magic number */
};
ZSTD_seekable* const stream = ZSTD_seekable_create();
assert(stream != NULL);
{ size_t const status = ZSTD_seekable_initBuff(stream, compressed_data, sizeof(compressed_data));
if (ZSTD_getErrorCode(status) != ZSTD_error_corruption_detected) {
ZSTD_seekable_free(stream);
goto _test_error;
} }
ZSTD_seekable_free(stream);
}
printf("Success!\n");
/* TODO: Add more tests */
printf("Finished tests\n");
return 0;

View file

@ -397,6 +397,13 @@ static size_t ZSTD_seekable_loadSeekTable(ZSTD_seekable* zs)
U32 const frameSize = tableSize + ZSTD_seekTableFooterSize + ZSTD_SKIPPABLEHEADERSIZE;
U32 remaining = frameSize - ZSTD_seekTableFooterSize; /* don't need to re-read footer */
/* numFrames is bounded by the format (the compressor never writes more
* than ZSTD_SEEKABLE_MAXFRAMES). A larger value can only come from a
* corrupt footer and overflows the tableSize/frameSize math above, so
* reject it before those values are used to seek or size the table. */
if (numFrames > ZSTD_SEEKABLE_MAXFRAMES) return ERROR(corruption_detected);
{ U32 const toRead = MIN(remaining, SEEKABLE_BUFF_SIZE);
CHECK_IO(src.seek(src.opaque, -(S64)frameSize, SEEK_END));
CHECK_IO(src.read(src.opaque, zs->inBuff, toRead));