| # GGUF KV Array Element Type Out-of-Range β Native Loader Abort |
|
|
| ## Finding |
|
|
| A malformed GGUF file with an out-of-range `inner_elem_type` value inside a KV |
| array (`GGUF_TYPE_ARRAY = 9`) causes the native loader (`gguf_init_from_file`) to |
| abort unconditionally via assertion failure (SIGABRT, exit -6 / 134). |
|
|
| The assertion `0 <= type && type < GGUF_TYPE_COUNT` fires before any element is |
| processed, regardless of the declared array count. Valid `GGUF_TYPE` values are |
| 0β12 (`GGUF_TYPE_COUNT = 13`); any value β₯ 13 triggers the abort. |
|
|
| **Crash site**: `gguf_init_from_file+0x7c0` |
| **Tested with**: `llama-cpp-python` (llama.cpp wheel) |
|
|
| ## Distinctness |
|
|
| | Root | Field | Crash offset | |
| |------|-------|-------------| |
| | ROUND_AI377 (prior, submitted) | KV entry outer type | `+0x3d8` | |
| | ROUND_AI381 (prior, submitted) | Tensor info type | `+0xfac` | |
| | **This finding** | **KV array elem type** | **`+0x7c0`** | |
|
|
| ## PoC Files |
|
|
| Six GGUF files in two sets: |
|
|
| | File | elem\_type | count | Role | |
| |------|-----------|-------|------| |
| | `arr_baseline.gguf` | 6 (F32) | 0 | Baseline | |
| | `arr_mutant_0xff.gguf` | 255 | 0 | Mutant (OOB) | |
| | `arr_mutant_13.gguf` | 13 | 0 | Mutant (=GGUF\_TYPE\_COUNT) | |
| | `arr_len1_baseline.gguf` | 6 (F32) | 1 | Baseline | |
| | `arr_len1_mutant_0xff.gguf`| 255 | 1 | Mutant (OOB) | |
| | `arr_len1_mutant_13.gguf` | 13 | 1 | Mutant (=GGUF\_TYPE\_COUNT) | |
|
|
| **Mutation field**: bytes 48β51 (uint32 LE, `inner_elem_type` inside the ARRAY KV value) |
|
|
| ## Observed Behavior |
|
|
| - **C native loader**: SIGABRT for all 4 mutants (12/12 runs). Assertion fires before |
| element iteration, independent of `array_count`. |
| - **Python `gguf` reader (len0)**: Accepts mutants β `range(0)` loop never calls |
| `GGUFValueType(elem_type)`, so the invalid value is not validated. |
| - **Python `gguf` reader (len1)**: Rejects mutants with `ValueError` β |
| `GGUFValueType(255)` raises on first element. |
|
|
| The security-relevant issue is the native loader abort path: an invalid |
| `inner_elem_type` value unconditionally aborts the loading process regardless of |
| array count. |
|
|
| ## Reproduction |
|
|
| ```bash |
| pip install llama-cpp-python gguf |
| python reproduce.py |
| ``` |
|
|
| Expected output summary: `PASS β 12/12 SIGABRT confirmed` |
|
|
| ```bash |
| python inspect_artifacts.py |
| ``` |
|
|
| Verifies SHA256 hashes and prints byte-level layout of mutation field. |
|
|
| ## Evidence Files |
|
|
| | File | Contents | |
| |------|----------| |
| | `runtime_results.json` | Unified run table (12/12 SIGABRT) | |
| | `hash_matrix.json` | SHA256 + layout for all 6 PoC files | |
| | `source_mapping_array_elem_type.json` | GGUF\_TYPE enum + binary confirmation | |
| | `distinctness_matrix.json` | 7-dimension comparison vs prior roots | |
|
|
| ## SHA256 |
|
|
| See `SHA256SUMS.txt`. |
|
|