facebook / facebook/zstd

Undefined behavior in `ZSTD_decompress` for certain `dest` values when `dstCapacity` is zero

Open
#3,507 1 comment 2 reactions 1 assignee Claimed by @daniellerozenblit View on GitHub
Dominant language
C
Stars
27.9k
Forks
2.6k
Avg merge
1d 3h
Merged PRs (30d)
8

Description

**Describe the bug**
When `dstCapacity` is zero, in theory the `dest` pointer should be irrelevant--any pointer value should be allowed (or, alternatively, the docs should specify what is and isn't allowed). However, if `ZSTD_decompress` is called with `dstCapacity=0` and `dest` having a value of e.g. `0xffffffffffffffff`, it will hit UB and may trip an assertion. I'm unsure exactly what range of pointer values will trigger this, but the maximum pointer value definitely does.

**To Reproduce**
1. Inputs that can trigger the UB: [zstd-zero-dest-capacity.zip](https://github.com/facebook/zstd/files/10750794/zstd-zero-dest-capacity.zip) (found when fuzzing a Zig implementation of a zstd decompressor). I'm not sure the input matters too much, the uncompressed size just needs to be zero; some inputs are the same as those in #3506
2. Compile zstd with clang via `make lib CFLAGS="-fsanitize=undefined -fPIC"`
3. Modify `examples/simple_decompression.c` with the following patch:

```diff
- void* const rBuff = malloc_orDie((size_t)rSize);
+ CHECK(rSize == 0, "Uncompressed size must be zero");
+ void* const rBuff = (void*)(-1); // 0xffffffffffffffff
```

4. Compile examples with `make LDFLAGS="-fsanitize=undefined"`
5. Run one of the inputs through `simple_decompression`, e.g. `./simple_decompression 'id:000000,sig:04,src:000193,time:1035023,execs:294994,op:havoc,rep:4'`

Example of the output with `DEBUGLEVEL=10`:

```
$ ./simple_decompression 'id:000000,sig:04,src:000193,time:1035023,execs:294994,op:havoc,rep:4'
.//decompress/zstd_decompress.c: ZSTD_getFrameHeader_advanced: minInputSize = 5, srcSize = 32
.//decompress/zstd_decompress.c: ZSTD_decompressMultiFrame
.//decompress/zstd_decompress.c: reading magic number FD2FB528 (expecting FD2FB528)
.//decompress/zstd_decompress.c: ZSTD_decompressFrame (srcSize:32)
.//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=0 using 6 bits
.//decompress/zstd_decompress_block.c: ZSTD_initFseState : val=0 using 5 bits
.//decompress/zstd_decompress_block.c: ZSTD_initFseState : val=0 using 6 bits
.//decompress/zstd_decompress_block.c: seq: litL=0, matchL=3, offset=4
/decompress/zstd_decompress_block.c:1696:45: runtime error: applying non-zero offset 18446744073709551615 to null pointer
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /decompress/zstd_decompress_block.c:1696:45 in
/decompress/zstd_decompress_block.c:1698:29: runtime error: pointer index expression with base 0xfffffffffffffffb overflowed to 0x00000000003b
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /decompress/zstd_decompress_block.c:1698:29 in
.//decompress/zstd_decompress_block.c: seq: litL=0, 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=41, offset=1
.//decompress/zstd_decompress_block.c: seq: litL=0, matchL=3, offset=4
.//decompress/zstd_decompress_block.c: seq: litL=10, matchL=3, offset=571
/decompress/zstd_decompress_block.c:1696:59: runtime error: pointer index expression with base 0x00000000003e overflowed to 0xfffffffffffffe03
SUMMARY: UndefinedBehaviorSanitizer: undefined-behavior /decompress/zstd_decompress_block.c:1696:59 in
.//decompress/zstd_decompress_block.c: seq: litL=2, matchL=3, offset=37
.//decompress/zstd_decompress_block.c:1755: ERROR!: check seqNb

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.