Target: Mozilla-Ocho/llamafile
File: llamafile/llamafile.c, lines 155-175 (ZIP central directory parsing)
Severity: MEDIUM (CWE-125 Out-of-Bounds Read)
Reporter: Viridis North LLC |
viridisnorthllc@gmail.com
A crafted .llamafile ZIP container can cause out-of-bounds heap reads during central directory parsing. The EOCD (End of Central Directory) record count field is trusted without validation against the actual central directory size, causing the parsing loop to iterate past valid entries into uninitialized heap memory.
1// llamafile.c:155-175
2cnt = ZIP_CDIR_RECORDS(eocd); // from EOCD — UNTRUSTED
3cdirsize = ZIP_CDIR_SIZE(eocd); // from EOCD
4cdirdata = malloc(cdirsize);
5pread(fd, cdirdata, cdirsize, off);
6
7for (int i = 0; i < cnt; i++) { // iterates 'cnt' times
8 // entry_offset + HDRSIZE check passes for first real entry
9 // but after exhausting real entries, reads garbage from heap
10 if (ZIP_CFILE_MAGIC(cdirdata + entry_offset) != kZipCfileHdrMagic)
11 goto next; // checks magic — but reads from uninitialized memory first
12 // ... memcmp, strndup on potentially OOB data
13}
User opens a crafted .llamafile file. The ZIP container has a manipulated EOCD record count. During model loading, the central directory parser reads out of bounds, potentially leaking heap contents or crashing.
1import struct, zlib
2gguf = struct.pack('<II', 0x46554747, 3) + struct.pack('<QQ', 0, 0)
3name = b'model.gguf'
4# Local file header + Central directory + EOCD with cnt=100
5# See full generator in repo
1# Build with ASan
2make -j$(nproc) CXXFLAGS="-fsanitize=address,undefined -O1 -g" LDFLAGS="-fsanitize=address,undefined"
3
4# Run
5ASAN_OPTIONS=detect_leaks=0 ./llamafile --model llf002_excess_cdir_records.llamafile 2>&1
6# Expected: heap-buffer-overflow or use-of-uninitialized-value
1if (cnt > cdirsize / kZipCfileHdrMinSize) {
2 cnt = cdirsize / kZipCfileHdrMinSize; // cap to maximum possible entries
3}