Undefined behavior in `ZSTD_decompress` for certain inputs
squeek502 opened this issue · 0 comments
squeek502 commented
Describe the bug
When compiled with clang and -fsanitize=undefined
, ZSTD_decompress
will hit undefined behavior with certain inputs:
/decompress/zstd_decompress_block.c:1696:45: runtime error: applying non-zero offset 79823856 to null pointer
To Reproduce
- Inputs that trigger the UB: zstd-non-zero-offset-inputs.zip (found when fuzzing a Zig implementation of a zstd decompressor)
- Compile zstd with clang via
make lib CFLAGS="-fsanitize=undefined -fPIC"
- Compile examples with
make LDFLAGS="-fsanitize=undefined"
- Run one of the inputs through
simple_decompression
, e.g../simple_decompression 'id:000032,sig:06,src:000673,time:3423388,execs:797038,op:havoc,rep:2'
Example of the output with DEBUGLEVEL=10
.//decompress/zstd_decompress.c: ZSTD_getFrameHeader_advanced: minInputSize = 5, srcSize = 39
.//decompress/zstd_decompress.c: ZSTD_decompressMultiFrame
.//decompress/zstd_decompress.c: reading magic number FD2FB528 (expecting FD2FB528)
.//decompress/zstd_decompress.c: ZSTD_decompressFrame (srcSize:39)
.//decompress/zstd_decompress.c: ZSTD_getFrameHeader_advanced: minInputSize = 5, srcSize = 9
.//decompress/zstd_decompress_block.c: ZSTD_decompressBlock_internal (size : 20)
.//decompress/zstd_decompress_block.c: ZSTD_decodeLiteralsBlock
.//decompress/zstd_decompress_block.c: ZSTD_decodeLiteralsBlock : cSize=1, nbLiterals=0
.//decompress/zstd_decompress_block.c: ZSTD_decodeSeqHeaders
.//decompress/zstd_decompress_block.c: ZSTD_getLongOffsetsShare: (tableLog=5)
.//decompress/zstd_decompress_block.c: ZSTD_decompressSequencesLong
.//decompress/zstd_decompress_block.c: ZSTD_initFseState : val=5 using 5 bits
.//decompress/zstd_decompress_block.c: ZSTD_initFseState : val=24 using 5 bits
.//decompress/zstd_decompress_block.c: ZSTD_initFseState : val=0 using 0 bits
.//decompress/zstd_decompress_block.c: seq: litL=0, matchL=3, offset=8
/decompress/zstd_decompress_block.c:1696:45: runtime error: applying non-zero offset 94193544721696 to null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /decompress/zstd_decompress_block.c:1696:45 in
.//decompress/zstd_decompress_block.c: seq: litL=2, matchL=3, offset=1
.//decompress/zstd_decompress_block.c: seq: litL=0, matchL=3, offset=4
.//decompress/zstd_decompress_block.c: seq: litL=0, matchL=3, offset=8
.//decompress/zstd_decompress_block.c: seq: litL=0, matchL=3, offset=2
.//decompress/zstd_decompress_block.c: seq: litL=0, matchL=3, offset=4
.//decompress/zstd_decompress_block.c: seq: litL=0, matchL=3, offset=8
.//decompress/zstd_decompress_block.c: seq: litL=0, matchL=3, offset=2
.//decompress/zstd_decompress_block.c: seq: litL=2, matchL=3, offset=8
.//decompress/zstd_decompress_block.c:884: ERROR!: check sequenceLength > (size_t)(oend - op) failed, returning ERROR(dstSize_tooSmall): last match must fit within dstBuffer
simple_decompression.c:40 CHECK(!ZSTD_isError(err)) failed: Destination buffer is too small
Expected behavior
No UB
Desktop:
- OS: Linux
- Compiler clang
Additional context
UB does not happen with the streaming_decompression
example for these inputs.