You need to agree to share your contact information to access this model

This repository is publicly accessible, but you have to accept the conditions to access its files and content.

Log in or Sign Up to review the conditions and access this model content.

Mozilla-Ocho/llamafile β€” signed/unsigned mismatch in get_zip_cfile_compressed_size() -> mmap() size underflow -> OOB read / SIGBUS

Status: gated, manual-approval PoC repository. For authorized security research / bug-bounty triage only (huntr.com MFF).

Target

  • Project: Mozilla-Ocho/llamafile
  • Verified against commit: 84e3e1ae0f7f17d613f80539e10fc47ae9b1a6a7 (2026-07-02)
  • Files: llamafile/llamafile.c (llamafile_open_zip(), the sink), llamafile/zip.c (root cause, get_zip_cfile_compressed_size())
  • Class: CWE-195/CWE-191 (signed/unsigned conversion error, integer underflow) -> undersized mmap() -> CWE-125 heap/mapping out-of-bounds read (SIGBUS)

This is a different bug from this campaign's already-confirmed zip64-extra-field-parser OOB read in the same file (a missing bounds check before a pointer dereference while walking zip64 extra records). This finding is a distinct root cause: a signed sentinel value silently becoming SIZE_MAX and then wrapping an unsigned mmap() size calculation.

Root cause

get_zip_cfile_compressed_size() (real zip.c, unmodified) returns int64_t and uses -1 as an explicit "couldn't find it" sentinel when a ZIP64 escape marker (0xFFFFFFFF) is present in the 32-bit compressed-size field but no valid ZIP64 extra field backs it up. The real llamafile_open_zip() (llamafile.c) assigns this signed return value directly into file->size, a size_t (unsigned) struct field:

// llamafile.c:178 (struct llamafile { ... size_t size; ... size_t mapsize; ... };)
file->size = get_zip_cfile_compressed_size(cdirdata + entry_offset);

-1 silently becomes SIZE_MAX. That poisoned value then flows into an unsigned addition a few lines later:

// llamafile.c:227
file->mapsize = skew + file->size;   // skew (small) + SIZE_MAX wraps back down to a tiny number
file->mapping = mmap(0, file->mapsize, PROT_READ, MAP_SHARED, fd, mapoff);

mmap() maps only the tiny wrapped size, but every later read against the file (e.g. llamafile_read(), llamafile_size()) trusts the original poisoned file->size (still SIZE_MAX) as the "how much data is really here" bound β€” so any read past the first few bytes walks off the real mapping into unmapped memory.

Methodology

get_zip_cfile_compressed_size()/get_zip_cfile_offset() are compiled in from the REAL, unmodified zip.c/zip.h (fetched at the pinned commit; reused from this campaign's earlier llamafile build work). The mmap/read sequence from llamafile_open_zip() is reproduced with the exact real variable roles and the exact real lines (cross-checked byte-for-byte against the real fetched llamafile.c, included in this repo for verification), since llamafile.c itself depends on Cosmopolitan-specific machinery (gc(), GetProgramExecutableName(), etc.) not available on stock Linux β€” none of those substitutions touch the vulnerable arithmetic itself, which lives entirely in the real, verbatim zip.c functions plus the file->mapsize = skew + file->size line.

Proof of concept (run_output.txt)

[VULN] get_zip_cfile_offset()           = 0 (valid, small)
[VULN] get_zip_cfile_compressed_size()   = -1  <-- returned -1 (sentinel, no ZIP64 backing)
[VULN] file->size (size_t, after assignment) = 18446744073709551615  (0xffffffffffffffff) <-- silently became SIZE_MAX!
...
[VULN] file->mapsize = skew + file->size = 36 + 18446744073709551615 = 35 (0x23)
[VULN] ^^^ wrapped around to a TINY value instead of an error/huge value!

[mmap]  mmap(size=35) SUCCEEDED at 0x7f1325180000 -- real mapped extent is only ~35 bytes

[crash-test] forking a child to attempt a 64 MiB read via the exact
[crash-test] llamafile_read() logic (memcpy bounded by the poisoned
[crash-test] file->size, not the real ~35-byte mapping)...

[CONFIRMED] child process was KILLED by signal 7 (Bus error) --
[CONFIRMED] this is the real, dynamically-triggered out-of-bounds read crash.

Every claimed line was cross-checked against the real llamafile.c fetched at the pinned commit β€” confirmed byte-for-byte matches at:

  • llamafile.c:178: file->size = get_zip_cfile_compressed_size(cdirdata + entry_offset);
  • llamafile.c:227: file->mapsize = skew + file->size;
  • llamafile.c:59-68: struct llamafile { ... size_t size; ... size_t mapsize; ... };

Reachability

Every .llamafile / foo.zip@weights.gguf load goes through llamafile_open_zip(). An attacker supplying a crafted ZIP/llamafile container with a central-directory entry whose compressed-size field is the ZIP64 escape marker (0xFFFFFFFF) and no backing ZIP64 extra record triggers this on ordinary model load.

Files

  • poc_harness.c β€” the verification harness (craft + repro, see file header for full detail)
  • zip.c / zip.h β€” real, unmodified files from Mozilla-Ocho/llamafile at the pinned commit
  • llamafile.c β€” real, unmodified llamafile.c fetched at the pinned commit, included so the claimed vulnerable lines can be independently verified against it
  • run_output.txt β€” captured run output showing the wraparound and the SIGBUS crash
  • malicious.llamafile β€” the crafted 130-byte trigger file

Build & run

gcc -O0 -g -Wall -include stdint.h -o poc poc_harness.c zip.c
./poc

Independent re-verification (2026-07-11)

Rebuilt from these exact source files with a fresh gcc -O0 -g -Wall -include stdint.h invocation and re-ran the resulting binary independently (not reusing any cached build or prior run's captured output). Fresh output matched the documented behavior exactly: get_zip_cfile_compressed_size() returned -1, file->size became SIZE_MAX (18446744073709551615), file->mapsize wrapped to 35, mmap(size=35) succeeded, and the forked child performing a bounded-by-file->size read was killed by signal 7 (Bus error). Also re-confirmed the two cited line numbers (llamafile.c:178, llamafile.c:227) via direct grep against the unmodified llamafile.c included in this bundle. Dedup search re-run same night: no CVE/GHSA/GitHub issue found for this function or bug class in either Mozilla-Ocho/llamafile or its successor mozilla-ai/llamafile.

Downloads last month
-
Inference Providers NEW
This model isn't deployed by any Inference Provider. πŸ™‹ Ask for provider support