Skip to content

Divide-by-zero (SIGFPE) in gguflib from untrusted general.alignment value #27

Description

@professor-moody

Summary

A crafted GGUF file that sets the general.alignment metadata key to 0 triggers a divide-by-zero
(SIGFPE) in gguf_get_alignment_padding(). The alignment value is read directly from the file
without validation and used as a modulus divisor. A 90-byte file is sufficient to crash any
application that loads it via gguflib.

Affected component

  • Repository: antirez/gguf-tools
  • File: gguflib.cgguf_get_alignment_padding() (divide site per the advisory at gguflib.c:218;
    called from gguf_set_data_offset() and the bsize calculation in gguf_get_tensor()).

gdb-confirm the exact file:line before filing (the bare SIGFPE at revalidation proves the bug is
live, not the exact frame).

Reproduction

PoC: poc-041-div-by-zero.gguf (90 bytes) — a GGUF v3 file with general.alignment = 0 and one
minimal tensor.

$ gguf-tools show poc-041-div-by-zero.gguf
# -> SIGFPE (exit 136)

Root cause

The alignment value is stored from the file without validation:

if (key->type == GGUF_VALUE_TYPE_UINT32 && /* key == "general.alignment" */ ...) {
    ctx->alignment = key->val->uint32;   // attacker-controlled, no validation
}

and later used as a modulus operand:

uint64_t gguf_get_alignment_padding(uint64_t alignment, uint64_t offset) {
    return (alignment - (offset % alignment)) % alignment;   // % 0 -> SIGFPE when alignment == 0
}

Suggested fix

Guard the divisor, and/or reject general.alignment == 0 at parse time:

uint64_t gguf_get_alignment_padding(uint64_t alignment, uint64_t offset) {
    if (alignment == 0) return 0;
    return (alignment - (offset % alignment)) % alignment;
}
ctx->alignment = key->val->uint32;
if (ctx->alignment == 0) {
    /* invalid alignment — reject file */
    gguf_close(ctx);
    return NULL;
}

Revalidation

Revalidated live on 2026-06-14 against current gguf-tools fdfafbe via gguf-tools show:
poc-041-div-by-zero.gguf produces SIGFPE (exit 136). Class: CWE-369 (divide by zero).

Proof-of-concept (base64; base64 -d > poc.gguf)

poc-041-div-by-zero.gguf (90 bytes):

R0dVRgMAAAABAAAAAAAAAAEAAAAAAAAAEQAAAAAAAABnZW5lcmFsLmFsaWdubWVudAQAAAAAAAAAAQAAAAAAAAB4AQAAAAEAAAAAAAAAAAAAAAAAAAAAAAAA

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions