Out-of-bounds read in ccv_move when creating an offset view with non-zero x/y
Hi, it seems like there is a trivial buffer overflow (read) in `ccv_move`.
As far as I can tell, this overflow happens in most uses with nonzero `x` and `y` values for the offsets.
It looks like `ccv_move` is not used anywhere else, so perhaps this API is just incomplete.
(found via automated fuzzing)
See the following testcase:
**testcase.cpp**
```cpp
#include <cstdlib>
extern "C" {
#include "/fuzz/install/include/ccv.h"
}
int main() {
// 2x2, 3 channels (8U C3)
ccv_dense_matrix_t* a = ccv_dense_matrix_new(2, 2, CCV_8U | CCV_C3, 0, 0);
if (!a) return 0;
ccv_matrix_t* b = 0;
// Non-zero x offset triggers OOB read inside ccv_move
ccv_move((ccv_matrix_t*)a, &b, 0, /*y=*/0, /*x=*/1);
// Clean up (not reached if it crashes under ASan)
if (b) ccv_matrix_free(b);
ccv_matrix_free((ccv_matrix_t*)a);
return 0;
}
```
**crash report**
```json
{
"Date": "2025-09-29T02:13:53.522821+00:00",
"Uname": "Linux e98b1e44d7b2 5.15.0-156-generic #166-Ubuntu SMP Sat Aug 9 00:02:46 UTC 2025 x86_64 x86_64 x86_64 GNU/Linux",
"OS": "Ubuntu",
"OSRelease": "22.04",
"Architecture": "amd64",
"ExecutablePath": "/tmp/tmpnviyeqc0/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/tmpnviyeqc0/reproducer",
"Stdin": "",
"ProcStatus": [],
"ProcMaps": [],
"ProcFiles": [],
"NetworkConnections": [],
"CrashSeverity": {
"Type": "NOT_EXPLOITABLE",
"ShortDescription": "heap-buffer-overflow(read)",
"Description": "Heap buffer overflow",
"Explanation": "The target reads data past the end, or before the beginning, of the intended heap buffer."
},
"Stacktrace": [
" #0 0x555555695ad5 in ccv_move /fuzz/src/lib/ccv_util.c:1356:3",
" #1 0x55555565c4e8 in main /tmp/tmpnviyeqc0/reproducer.cpp:11:3",
" #2 0x7ffff5619d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
" #3 0x7ffff5619e3f in __libc_start_main csu/../csu/libc-start.c:392:3",
" #4 0x5555555812f4 in _start (/tmp/tmpnviyeqc0/reproducer+0x2d2f4) (BuildId: dc06ba8ce9aca5b9eaea2d972e7769f1a52f3776)"
],
"Registers": {},
"Disassembly": [],
"Package": "",
"PackageVersion": "",
"PackageArchitecture": "",
"PackageDescription": "",
"AsanReport": [
"==219==ERROR: AddressSanitizer: heap-buffer-overflow on address 0x50d0000000d0 at pc 0x555555695ad6 bp 0x7fffffffe970 sp 0x7fffffffe968",
"READ of size 1 at 0x50d0000000d0 thread T0",
" #0 0x555555695ad5 in ccv_move /fuzz/src/lib/ccv_util.c:1356:3",
" #1 0x55555565c4e8 in main /tmp/tmpnviyeqc0/reproducer.cpp:11:3",
" #2 0x7ffff5619d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
" #3 0x7ffff5619e3f in __libc_start_main csu/../csu/libc-start.c:392:3",
" #4 0x5555555812f4 in _start (/tmp/tmpnviyeqc0/reproducer+0x2d2f4) (BuildId: dc06ba8ce9aca5b9eaea2d972e7769f1a52f3776)",
"",
"0x50d0000000d0 is located 0 bytes after 144-byte region [0x50d000000040,0x50d0000000d0)",
"allocated by thread T0 here:",
" #0 0x55555561d69e in malloc (/tmp/tmpnviyeqc0/reproducer+0xc969e) (BuildId: dc06ba8ce9aca5b9eaea2d972e7769f1a52f3776)",
" #1 0x55555565c925 in ccv_dense_matrix_new /fuzz/src/lib/ccv_memory.c:38:45",
" #2 0x55555565c499 in main /tmp/tmpnviyeqc0/reproducer.cpp:7:27",
" #3 0x7ffff5619d8f in __libc_start_call_main csu/../sysdeps/nptl/libc_start_call_main.h:58:16",
"",
"SUMMARY: AddressSanitizer: heap-buffer-overflow /fuzz/src/lib/ccv_util.c:1356:3 in ccv_move",
"Shadow bytes around the buggy address:",
" 0x50cffffffe00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x50cffffffe80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x50cfffffff00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x50cfffffff80: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x50d000000000: fa fa fa fa fa fa fa fa 00 00 00 00 00 00 00 00",
"=>0x50d000000080: 00 00 00 00 00 00 00 00 00 00[fa]fa fa fa fa fa",
" 0x50d000000100: fa fa 00 00 00 00 00 00 00 00 00 00 00 00 00 00",
" 0x50d000000180: 00 00 00 00 fa fa fa fa fa fa fa fa fa fa fa fa",
" 0x50d000000200: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
" 0x50d000000280: fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa fa",
" 0x50d000000300: 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",
"==219==ABORTING"
],
"MsanReport": [],
"UbsanReport": [],
"LuaReport": [],
"PythonReport": [],
"GoReport": [],
"JavaReport": [],
"RustReport": [],
"JsReport": [],
"CSharpReport": [],
"CrashLine": "/fuzz/src/lib/ccv_util.c:1356:3",
"Source": [
" 1352 \t\t\t} \\",
" 1353 \t\t\ta_ptr += da->step; \\",
" 1354 \t\t\tb_ptr += db->step; \\",
" 1355 \t\t}",
"--->1356 \t\tccv_matrix_setter(db->type, ccv_matrix_getter, da->type, for_block);",
" 1357 #undef for_block",
" 1358 \t} else if (type & CCV_MATRIX_SPARSE) {",
" 1359 \t}",
" 1360 }",
" 1361 "
]
}
```
0 条评论