clip_image_u8::set_pixel 32-bit index overflow → OOB heap writeggml-org/llama.cpp @ 2d97363 — tools/mtmd/clip-impl.h.
For authorized security research (responsible disclosure via huntr).clip_image_u8::set_pixel/get_pixel (clip-impl.h:485/:477) index the image buffer with 32-bit int:
int idx = (y * nx + x) * 3;. nx = ny = image_size is an mmproj GGUF hparam bounded only to <=65536
(clip.cpp:1179, 1686-1691). set_size allocates with size_t (no overflow, ~2.7 GB for 30000), but the
per-pixel index overflows int for image_size ≳ 26756 → negative idx → huge size_t offset → wild
out-of-bounds heap write, reached via the resize loop (mtmd-image.cpp) during preprocessing of any
image with an MLP/LDP/COGVLM/JANUS_PRO/GLM_EDGE/YASA2/GEMMA3 vision head. Distinct from the MiniCPM-V
bucket_coords stack overflow (different file/root cause).setpixel_repro.cpp — copies the exact clip_image_u8 code + resize loop.CRASH_PROVEN.md / gen_and_run.sh — UBSan run showing the signed-integer overflow at the exact line.c++ -O1 -g -fsanitize=undefined -fno-sanitize-recover=all setpixel_repro.cpp -o setpixel_ubsan
./setpixel_ubsan 30000
# -> setpixel_repro.cpp:29 runtime error: signed integer overflow ... in type 'int' (== clip-impl.h:485)clip.vision.image_size = 30000 in a real MiniCPM-less fixed-size mmproj GGUF and run
llama-mtmd-cli --mmproj evil.gguf --image any.png → OOB heap write in the resize/set_pixel loop.size_t (size_t idx = ((size_t)y*nx + x)*3;) and/or bound image_size²*3 <= INT_MAX.