Bug 15256 - read overflow in lzxpress fuzzer
Summary: read overflow in lzxpress fuzzer
Status: RESOLVED FIXED
Alias: None
Product: Samba 4.1 and newer
Classification: Unclassified
Component: Other (show other bugs)
Version: unspecified
Hardware: All All
: P5 normal (vote)
Target Milestone: ---
Assignee: Samba QA Contact
QA Contact: Samba QA Contact
URL:
Keywords:
Depends on:
Blocks:
 
Reported: 2022-12-02 23:55 UTC by Douglas Bagnall
Modified: 2022-12-28 02:36 UTC (History)
0 users

See Also:


Attachments

Note You need to log in before you can comment on or make changes to this bug.
Description Douglas Bagnall 2022-12-02 23:55:26 UTC
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=53952
https://oss-fuzz.com/testcase-detail/6514143647891456

The stack trace at the second link (which I think never becomes public) is:

 	==10146==ERROR: AddressSanitizer: global-buffer-overflow on address 0x5634c60eab60 at pc 0x5634c5631c0c bp 0x7ffd659fae00 sp 0x7ffd659fadf8
	READ of size 1 at 0x5634c60eab60 thread T0
	SCARINESS: 12 (1-byte-read-global-buffer-overflow)
	    #0 0x5634c5631c0b in lzxpress_decompress samba/lib/compression/lzxpress.c:421:16
	    #1 0x5634c5642461 in LLVMFuzzerTestOneInput samba/lib/fuzzing/fuzz_lzxpress_round_trip.c:42:22
	    #2 0x5634c5642d5b in main
	    #3 0x7f246e7e7082 in __libc_start_main
	    #4 0x5634c556367d in _start
	

I *think* this might just be a bug in the fuzz target, not the compression routines themselves, because the overflow is in lzxpress_decompress() which has not changed (_compress() has had a serious rewrite, as has fuzz_lzxpress_round_trip.c).

Marking as developer only for now. This bug is mainly so we don't forget.
Comment 1 Douglas Bagnall 2022-12-03 00:21:30 UTC
(In reply to Douglas Bagnall from comment #0)
> (_compress() has had a serious rewrite, as has fuzz_lzxpress_round_trip.c).

OK, fuzz_lzxpress_round_trip.c hasn't had a rewrite. That's in an unmerged branch. Or my imagination.

But it is true that lzxpress_decompress() hasn't changed.

My theory is that lzxpress_compress() is returning -1 to indicate error, and this isn't checked (and becomes SIZE_MAX).

The failure will be that the compressed buffer, by the way lzxpress is defined to have 1 flag bit per byte, should expect to be ~1/8 bigger than the decompressed buffer in the worst case. But we have:

        static uint8_t compressed[1024 * 1024] = {0};                                                                          
        static uint8_t decompressed[1024 * 1024] = {0};

        if (len > sizeof(decompressed)) {                                                                                      
                return 0;                                                                                                      
        }     

How didn't this fail before? Maybe it always timed out and failed that way.