Skip to content

Out-of-bounds read in ccv_move when creating an offset view with non-zero x/y #269

@hgarrereyn

Description

@hgarrereyn

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

#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

{
  "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   "
  ]
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions