Expand GGML submission report
Browse files- README.md +118 -28
- SHA256SUMS.txt +1 -1
README.md
CHANGED
|
@@ -8,43 +8,129 @@ tags:
|
|
| 8 |
library_name: other
|
| 9 |
---
|
| 10 |
|
| 11 |
-
# GGML legacy `n_dims` stack out-of-bounds in loaders and quantizers
|
| 12 |
|
| 13 |
-
|
| 14 |
|
| 15 |
-
|
| 16 |
-
|
| 17 |
-
- Data format: GGML
|
| 18 |
- Suggested title: GGML legacy model-controlled `n_dims` stack out-of-bounds in loaders and quantizers
|
| 19 |
- Severity: High
|
| 20 |
-
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 21 |
|
| 22 |
-
|
| 23 |
|
| 24 |
-
|
| 25 |
-
- Severity assessment: High, denial of service with native memory corruption. No code execution is claimed.
|
| 26 |
-
- Root cause: several legacy parsers read model-controlled `n_dims` and copy dimension entries into fixed local arrays without bounding `n_dims` first.
|
| 27 |
-
- Verified outcome: ASAN `stack-buffer-overflow` traces and release-build segmentation faults/aborts.
|
| 28 |
|
| 29 |
-
|
| 30 |
|
| 31 |
-
|
| 32 |
-
- `artifacts/ggml_gptj_loader_ndims64.bin`: GPT-J legacy loader overflow.
|
| 33 |
-
- `artifacts/ggml_sam_loader_ndims64.bin`: SAM legacy loader overflow.
|
| 34 |
-
- `artifacts/ggml_gpt2_quant_ndims1024.bin`: GPT-2 quantizer common loader overflow.
|
| 35 |
-
- `artifacts/ggml_gptj_quant_ndims1024.bin`: GPT-J quantizer common loader overflow.
|
| 36 |
-
- `logs/*.txt`: ASAN traces from the vulnerable binaries.
|
| 37 |
-
- `modelscan/*`: scanner output captured during verification.
|
| 38 |
-
- `scripts/*`: local generators used to create the PoC files.
|
| 39 |
|
| 40 |
-
|
| 41 |
|
| 42 |
-
|
| 43 |
-
|
| 44 |
-
|
| 45 |
-
|
| 46 |
|
| 47 |
-
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 48 |
|
| 49 |
```text
|
| 50 |
62892adf21342a70b3c6dee5adfa224a435f747a5e6eb7c84e5064f576e99b0c artifacts/ggml_gpt2_loader_ndims3.bin
|
|
@@ -54,6 +140,10 @@ d9a5880f374d68f1c618945e301997b454317e203d23ca35b3d7c11bd69b8ddb artifacts/ggml
|
|
| 54 |
002f3224ac62b36bc9b60da7fa1e5a4ac24f1587552846c10bec8cf3dbf7e928 artifacts/ggml_gptj_quant_ndims1024.bin
|
| 55 |
```
|
| 56 |
|
| 57 |
-
##
|
|
|
|
|
|
|
|
|
|
|
|
|
| 58 |
|
| 59 |
-
|
|
|
|
| 8 |
library_name: other
|
| 9 |
---
|
| 10 |
|
| 11 |
+
# GGML legacy model-controlled `n_dims` stack out-of-bounds in loaders and quantizers
|
| 12 |
|
| 13 |
+
## Submission
|
| 14 |
|
| 15 |
+
- Data format: GGML legacy model files
|
|
|
|
|
|
|
| 16 |
- Suggested title: GGML legacy model-controlled `n_dims` stack out-of-bounds in loaders and quantizers
|
| 17 |
- Severity: High
|
| 18 |
+
- Impact: native memory corruption and reliable denial of service when a victim loads or quantizes a malicious GGML model file
|
| 19 |
+
- Affected target verified: ggml `v0.11.1`, commit `a056a26f508b6160438ddd8aabbc859d2a2e7a97`
|
| 20 |
+
- Not claimed: arbitrary code execution
|
| 21 |
+
|
| 22 |
+
## Executive summary
|
| 23 |
+
|
| 24 |
+
Several GGML legacy model readers trust the model-controlled `n_dims` field before copying tensor dimensions into fixed-size stack arrays. A malicious GGML artifact can set `n_dims` larger than the destination array and cause an out-of-bounds stack write during normal model loading or quantization.
|
| 25 |
+
|
| 26 |
+
This repository includes five minimal malformed GGML files that hit independent loader/tool paths:
|
| 27 |
+
|
| 28 |
+
- GPT-2 loader, fixed local `ne[2]`
|
| 29 |
+
- GPT-J loader, fixed local `ne[2]`
|
| 30 |
+
- SAM loader, fixed local `ne[4]`
|
| 31 |
+
- GPT-2 quantizer helper, fixed local `ne[4]`
|
| 32 |
+
- GPT-J quantizer helper, fixed local `ne[4]`
|
| 33 |
|
| 34 |
+
The issue is artifact-carried: the only attacker-controlled input is the GGML model file passed to the normal loader/quantizer command. ASAN reports stack-buffer-overflow, and release builds crash/abort.
|
| 35 |
|
| 36 |
+
## Why this is security-relevant
|
|
|
|
|
|
|
|
|
|
| 37 |
|
| 38 |
+
GGML artifacts are commonly exchanged as model files and are loaded by native C/C++ tools. The parser reaches the vulnerable path before model execution and before meaningful model validation. A service that accepts, previews, converts, or quantizes untrusted GGML models can be crashed by a tiny file. The ASAN traces show a write beyond a stack buffer, which is stronger than a clean parser error or expected unsupported-format rejection.
|
| 39 |
|
| 40 |
+
## Root cause
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 41 |
|
| 42 |
+
The vulnerable code pattern is:
|
| 43 |
|
| 44 |
+
1. Read `n_dims` from the file.
|
| 45 |
+
2. Allocate a fixed local dimension array such as `int32_t ne[2]` or `int32_t ne[4]`.
|
| 46 |
+
3. Read `n_dims` dimension entries from the file directly into that fixed array.
|
| 47 |
+
4. Validate/use tensor metadata after the out-of-bounds write has already happened.
|
| 48 |
|
| 49 |
+
Verified crash locations:
|
| 50 |
+
|
| 51 |
+
- `examples/gpt-2/main-backend.cpp`, local `ne[2]`
|
| 52 |
+
- `examples/gpt-j/main.cpp`, local `ne[2]`
|
| 53 |
+
- `examples/sam/sam.cpp`, local `ne[4]`
|
| 54 |
+
- `examples/common-ggml.cpp`, local `ne[4]`, reached by GPT-2 and GPT-J quantizers
|
| 55 |
+
|
| 56 |
+
## Repository contents
|
| 57 |
+
|
| 58 |
+
```text
|
| 59 |
+
artifacts/ggml_gpt2_loader_ndims3.bin GPT-2 loader PoC
|
| 60 |
+
artifacts/ggml_gptj_loader_ndims64.bin GPT-J loader PoC
|
| 61 |
+
artifacts/ggml_sam_loader_ndims64.bin SAM loader PoC
|
| 62 |
+
artifacts/ggml_gpt2_quant_ndims1024.bin GPT-2 quantizer PoC
|
| 63 |
+
artifacts/ggml_gptj_quant_ndims1024.bin GPT-J quantizer PoC
|
| 64 |
+
logs/*.txt ASAN traces
|
| 65 |
+
modelscan/* ModelScan outputs from verification
|
| 66 |
+
scripts/* PoC generation scripts
|
| 67 |
+
SHA256SUMS.txt hash manifest
|
| 68 |
+
```
|
| 69 |
+
|
| 70 |
+
## Reproduction
|
| 71 |
+
|
| 72 |
+
Build the affected targets with AddressSanitizer:
|
| 73 |
+
|
| 74 |
+
```bash
|
| 75 |
+
git clone https://github.com/ggml-org/ggml.git
|
| 76 |
+
cd ggml
|
| 77 |
+
git checkout a056a26f508b6160438ddd8aabbc859d2a2e7a97
|
| 78 |
+
cmake -S . -B build-asan -DCMAKE_BUILD_TYPE=Debug \
|
| 79 |
+
-DCMAKE_C_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
|
| 80 |
+
-DCMAKE_CXX_FLAGS="-fsanitize=address -fno-omit-frame-pointer" \
|
| 81 |
+
-DGGML_NATIVE=OFF
|
| 82 |
+
cmake --build build-asan --target gpt-2-backend gpt-j sam gpt-2-quantize gpt-j-quantize -j
|
| 83 |
+
```
|
| 84 |
+
|
| 85 |
+
Download this repository and run the loader cases:
|
| 86 |
+
|
| 87 |
+
```bash
|
| 88 |
+
hf download pragnyanramtha/ggml-legacy-ndims-oob-suite --local-dir ggml-ndims-poc
|
| 89 |
+
|
| 90 |
+
./build-asan/bin/gpt-2-backend -m ggml-ndims-poc/artifacts/ggml_gpt2_loader_ndims3.bin -p test -n 1
|
| 91 |
+
./build-asan/bin/gpt-j -m ggml-ndims-poc/artifacts/ggml_gptj_loader_ndims64.bin -p test -n 1
|
| 92 |
+
./build-asan/bin/sam -m ggml-ndims-poc/artifacts/ggml_sam_loader_ndims64.bin -i /tmp/nonexistent.jpg
|
| 93 |
+
```
|
| 94 |
+
|
| 95 |
+
Run the quantizer cases:
|
| 96 |
+
|
| 97 |
+
```bash
|
| 98 |
+
./build-asan/bin/gpt-2-quantize ggml-ndims-poc/artifacts/ggml_gpt2_quant_ndims1024.bin /tmp/gpt2-out.bin q4_0
|
| 99 |
+
./build-asan/bin/gpt-j-quantize ggml-ndims-poc/artifacts/ggml_gptj_quant_ndims1024.bin /tmp/gptj-out.bin q4_0
|
| 100 |
+
```
|
| 101 |
+
|
| 102 |
+
Expected ASAN result for the quantizer path:
|
| 103 |
+
|
| 104 |
+
```text
|
| 105 |
+
ERROR: AddressSanitizer: stack-buffer-overflow
|
| 106 |
+
WRITE of size 4
|
| 107 |
+
ggml_common_quantize_0(...) examples/common-ggml.cpp:114
|
| 108 |
+
This frame has ... 'ne' (line 112) <== Memory access ... overflows this variable
|
| 109 |
+
```
|
| 110 |
+
|
| 111 |
+
Expected ASAN result for the SAM loader path:
|
| 112 |
+
|
| 113 |
+
```text
|
| 114 |
+
ERROR: AddressSanitizer: stack-buffer-overflow
|
| 115 |
+
sam_model_load(...) examples/sam/sam.cpp:1058
|
| 116 |
+
'ne' (line 1054) <== Memory access ... overflows this variable
|
| 117 |
+
```
|
| 118 |
+
|
| 119 |
+
Expected ASAN result for the GPT loader paths:
|
| 120 |
+
|
| 121 |
+
```text
|
| 122 |
+
ERROR: AddressSanitizer: stack-buffer-overflow
|
| 123 |
+
SUMMARY: AddressSanitizer: stack-buffer-overflow ... in memcpy
|
| 124 |
+
'ne' (...) <== Memory access ... overflows this variable
|
| 125 |
+
```
|
| 126 |
+
|
| 127 |
+
The captured traces are included in `logs/`.
|
| 128 |
+
|
| 129 |
+
## Scanner behavior
|
| 130 |
+
|
| 131 |
+
The artifacts were also scanned with ModelScan during local verification. They are malformed GGML parser tests, not executable payloads, and the scanner did not identify the native parser memory corruption. The scanner logs are included under `modelscan/`.
|
| 132 |
+
|
| 133 |
+
## Hashes
|
| 134 |
|
| 135 |
```text
|
| 136 |
62892adf21342a70b3c6dee5adfa224a435f747a5e6eb7c84e5064f576e99b0c artifacts/ggml_gpt2_loader_ndims3.bin
|
|
|
|
| 140 |
002f3224ac62b36bc9b60da7fa1e5a4ac24f1587552846c10bec8cf3dbf7e928 artifacts/ggml_gptj_quant_ndims1024.bin
|
| 141 |
```
|
| 142 |
|
| 143 |
+
## Suggested fix
|
| 144 |
+
|
| 145 |
+
Reject tensors where `n_dims` exceeds the destination capacity before reading dimension entries. Prefer reading into a dynamically sized container only after bounding `n_dims` to a format-level maximum. Add regression tests for oversized `n_dims` in each legacy loader and shared quantizer helper.
|
| 146 |
+
|
| 147 |
+
## Limitations
|
| 148 |
|
| 149 |
+
This is a denial-of-service/native-memory-corruption report. I am not claiming arbitrary code execution. The PoCs are intentionally tiny malformed model files and should only be loaded in a throwaway test environment.
|
SHA256SUMS.txt
CHANGED
|
@@ -1,4 +1,4 @@
|
|
| 1 |
-
|
| 2 |
62892adf21342a70b3c6dee5adfa224a435f747a5e6eb7c84e5064f576e99b0c ./artifacts/ggml_gpt2_loader_ndims3.bin
|
| 3 |
d9a5880f374d68f1c618945e301997b454317e203d23ca35b3d7c11bd69b8ddb ./artifacts/ggml_gpt2_quant_ndims1024.bin
|
| 4 |
a0f8d2a774f739c6580e51348aa30f455de29c7a774b1f25c3ca27a593fae224 ./artifacts/ggml_gptj_loader_ndims64.bin
|
|
|
|
| 1 |
+
a37d87c867aad3ddb9da6a051d7235707cf96fe32a747686b1341a7cc01cfd62 ./README.md
|
| 2 |
62892adf21342a70b3c6dee5adfa224a435f747a5e6eb7c84e5064f576e99b0c ./artifacts/ggml_gpt2_loader_ndims3.bin
|
| 3 |
d9a5880f374d68f1c618945e301997b454317e203d23ca35b3d7c11bd69b8ddb ./artifacts/ggml_gpt2_quant_ndims1024.bin
|
| 4 |
a0f8d2a774f739c6580e51348aa30f455de29c7a774b1f25c3ca27a593fae224 ./artifacts/ggml_gptj_loader_ndims64.bin
|