lizard
lizard copied to clipboard
LizardF_compressFrameBound underestimates for tiny inputs causing heap OOB in LizardF_compressFrame
I understand this library may no longer be maintained, but in case there are still users who may be affected by this:
There is a small bug in LizardF_compressFrameBound causing it to underestimate bound sizes for small inputs, leading to OOB writes:
testcase.cc
#include <cstdio>
#include <cstdlib>
#include <cstdint>
extern "C" {
#include "/fuzz/install/include/lizard_frame.h"
}
int main() {
// 1-byte input
const unsigned char src[1] = {0};
// Preferences: only set contentSize; all other fields default/zero
LizardF_preferences_t prefs{}; // zero-initialize
prefs.frameInfo.contentSize = 1; // known content size
// Library promises this bound guarantees success
size_t bound = LizardF_compressFrameBound(1, &prefs);
if (bound == 0) return 0;
char *dst = (char*)malloc(bound);
// Crashes with ASan heap-buffer-overflow: library writes past 'dst'
size_t written = LizardF_compressFrame(dst, bound, src, 1, &prefs);
fprintf(stderr, "bound=%zu written=%zu\n", bound, written);
(void)written;
return 0;
}
casr report
{
"Date": "2025-09-21T04:11:03.101632+00:00",
"Uname": "Linux 2fe9075ff52e 5.15.0-140-generic #150-Ubuntu SMP Sat Apr 12 06:00:09 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux",
"OS": "Ubuntu",
"OSRelease": "22.04",
"Architecture": "amd64",
"ExecutablePath": "/tmp/tmpv73y9kwj/reproducer",
"ProcEnviron": [
"LIBAFL_EDGES_MAP_SIZE=800000",
"PWD=/fuzz/workspace",
"CXX=gf_libafl_cxx",
"GRAPHFUZZ_USE_ASAN=1",
"HOME=/root",
"ASAN_OPTIONS=hard_rss_limit_mb=1024:detect_leaks=0",
"TERM=xterm-256color",
"SHLVL=1",
"LD_LIBRARY_PATH=/fuzz/install/lib",
"PATH=/root/.cargo/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin",
"CC=gf_libafl_cc",
"DEBIAN_FRONTEND=noninteractive",
"OLDPWD=/fuzz/src/lib",
"_=/usr/local/bin/agfi"
],
"ProcCmdline": "/tmp/tmpv73y9kwj/reproducer",
"Stdin": "",
"ProcStatus": [],
"ProcMaps": [],
"ProcFiles": [],
"NetworkConnections": [],
"CrashSeverity": {
"Type": "EXPLOITABLE",
"ShortDescription": "heap-buffer-overflow(write)",
"Description": "Heap buffer overflow",
"Explanation": "The target writes data past the end, or before the beginning, of the intended heap buffer."
},
"Stacktrace": [
" #0 0x55555561a7e3 in __asan_memcpy (/tmp/tmpv73y9kwj/reproducer+0xc67e3) (BuildId: bc1331dfdfe6ec06a38aa5826490659a614cfc10)",
" #1 0x7ffff7ea0d18 in Lizard_writeBlock /fuzz/src/lib/lizard_compress.c:243:5",
" #2 0x7ffff7f3952d in Lizard_compress_generic /fuzz/src/lib/lizard_compress.c:535:13",
" #3 0x7ffff7f3952d in Lizard_compress_extState /fuzz/src/lib/lizard_compress.c:592:12",
" #4 0x7ffff7f66aa4 in LizardF_compressBlock /fuzz/src/lib/lizard_frame.c:461:18",
" #5 0x7ffff7f66aa4 in LizardF_compressUpdate /fuzz/src/lib/lizard_frame.c:554:19",
" #6 0x7ffff7f6498c in LizardF_compressFrame /fuzz/src/lib/lizard_frame.c:297:17",
" #7 0x55555565b62b in main /tmp/tmpv73y9kwj/reproducer.cpp:21:22",
" #8 0x7ffff794bd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
" #9 0x7ffff794be3f in __libc_start_main csu/../csu/libc-start.c:392:3",
" #10 0x555555580304 in _start (/tmp/tmpv73y9kwj/reproducer+0x2c304) (BuildId: bc1331dfdfe6ec06a38aa5826490659a614cfc10)"
],
"Registers": {},
"Disassembly": [],
"Package": "",
"PackageVersion": "",
"PackageArchitecture": "",
"PackageDescription": "",
"AsanReport": [
"==156==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x503000000058 at pc 0x55555561a7e4 bp 0x7ffffffd1b80 sp 0x7ffffffd1340",
"WRITE of size 1 at 0x503000000058 thread T0",
" #0 0x55555561a7e3 in __asan_memcpy (/tmp/tmpv73y9kwj/reproducer+0xc67e3) (BuildId: bc1331dfdfe6ec06a38aa5826490659a614cfc10)",
" #1 0x7ffff7ea0d18 in Lizard_writeBlock /fuzz/src/lib/lizard_compress.c:243:5",
" #2 0x7ffff7f3952d in Lizard_compress_generic /fuzz/src/lib/lizard_compress.c:535:13",
" #3 0x7ffff7f3952d in Lizard_compress_extState /fuzz/src/lib/lizard_compress.c:592:12",
" #4 0x7ffff7f66aa4 in LizardF_compressBlock /fuzz/src/lib/lizard_frame.c:461:18",
" #5 0x7ffff7f66aa4 in LizardF_compressUpdate /fuzz/src/lib/lizard_frame.c:554:19",
" #6 0x7ffff7f6498c in LizardF_compressFrame /fuzz/src/lib/lizard_frame.c:297:17",
" #7 0x55555565b62b in main /tmp/tmpv73y9kwj/reproducer.cpp:21:22",
" #8 0x7ffff794bd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
" #9 0x7ffff794be3f in __libc_start_main csu/../csu/libc-start.c:392:3",
" #10 0x555555580304 in _start (/tmp/tmpv73y9kwj/reproducer+0x2c304) (BuildId: bc1331dfdfe6ec06a38aa5826490659a614cfc10)",
"",
"0x503000000058 is located 0 bytes after 24-byte region [0x503000000040,0x503000000058)",
"allocated by thread T0 here:",
" #0 0x55555561c6ae in malloc (/tmp/tmpv73y9kwj/reproducer+0xc86ae) (BuildId: bc1331dfdfe6ec06a38aa5826490659a614cfc10)",
" #1 0x55555565b614 in main /tmp/tmpv73y9kwj/reproducer.cpp:19:24",
" #2 0x7ffff794bd8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
"",
"SUMMARY: AddressSanitizer: heap-buffer-overflow (/tmp/tmpv73y9kwj/reproducer+0xc67e3) (BuildId: bc1331dfdfe6ec06a38aa5826490659a614cfc10) in __asan_memcpy",
"Shadow bytes around the buggy address:",
" 0x502ffffffd80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x502ffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x502ffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x502fffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x502fffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
"=>0x503000000000: fa fa 00 00 00 fa fa fa 00 00 00[fa]fa fa fa fa",
" 0x503000000080: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
" 0x503000000100: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
" 0x503000000180: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
" 0x503000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
" 0x503000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
"Shadow byte legend (one shadow byte represents 8 application bytes):",
" Addressable: 00",
" Partially addressable: 01 02 03 04 05 06 07",
" Heap left redzone: fa",
" Freed heap region: fd",
" Stack left redzone: f1",
" Stack mid redzone: f2",
" Stack right redzone: f3",
" Stack after return: f5",
" Stack use after scope: f8",
" Global redzone: f9",
" Global init order: f6",
" Poisoned by user: f7",
" Container overflow: fc",
" Array cookie: ac",
" Intra object redzone: bb",
" ASan internal: fe",
" Left alloca redzone: ca",
" Right alloca redzone: cb",
"==156==ABORTING"
],
"MsanReport": [],
"UbsanReport": [],
"LuaReport": [],
"PythonReport": [],
"GoReport": [],
"JavaReport": [],
"RustReport": [],
"JsReport": [],
"CSharpReport": [],
"CrashLine": "/fuzz/src/lib/lizard_compress.c:243:5",
"Source": [
" 239 *start = LIZARD_FLAG_UNCOMPRESSED;",
" 240 *op = start + 1;",
" 241 MEM_writeLE24(*op, inputSize);",
" 242 *op += 3;",
"--->243 memcpy(*op, ip, inputSize);",
" 244 *op += inputSize;",
" 245 return 0;",
" 246 ",
" 247 _output_error:",
" 248 LIZARD_LOG_COMPRESS(\"Lizard_writeBlock ERROR size=%d/%d flagsLen=%d literalsLen=%d lenLen=%d offset16Len=%d offset24Len=%d\\n\", (int)(*op-start), (int)(oend-start), flagsLen, literalsLen, lenLen, offset16Len, offset24Len);"
]
}
Thanks for reporting it. I confirm the issue:
size=0 bound=23 written=11
size=1 bound=24 written=29 -> THE ISSUE
size=2 bound=25 written=25
size=3 bound=26 written=26
size=4 bound=27 written=27
size=5 bound=28 written=28
size=6 bound=29 written=29
size=7 bound=30 written=30
size=8 bound=31 written=31
size=9 bound=32 written=32
size=10 bound=33 written=33
size=11 bound=34 written=34
size=12 bound=35 written=35
The issue is fixed at https://github.com/inikep/lizard/commit/d3becc7e80 in the main branch.