Skip to content

Signed shape-product wrap in safetensors reader (NULL deref / DoS, ASAN-confirmed) #1876

Description

@x14ngch3n

Summary

read_safetensors_file (src/model_io/safetensors_io.cpp) accepts a crafted .safetensors file whose tensor shape overflows the element-count product to 0, leading to a NULL pointer dereference (denial of service) when the tensor is later accessed.

Root cause

Each tensor dimension is parsed with shape[i].get<int64_t>() and stored into ne[] with no range or overflow check. TensorStorage::nelements() (src/model_io/tensor_storage.h) multiplies the dims as a signed int64 product, and the reader uses nbytes() (derived from that product) for its only size check:

tensor_size_ok = (tensor_storage.nbytes() == tensor_data_size);   // safetensors_io.cpp:346
// tensor_data_size = end - begin, bounded against the file at :255

shape = [4294967296, 4294967296]int64 product 2^32 · 2^32 = 2^64 ≡ 0nbytes() == 0. Paired with an empty in-bounds data range (data_offsets [x, x]), 0 == 0 passes the check and the tensor is accepted with huge ne[] but nbytes() == 0. Negative dimensions are also accepted at parse time and reach the int64 product.

Impact

ggml_new_tensor computes its allocation from the same ne[] and also wraps to 0, returning a tensor with data == NULL. The first consumer access dereferences NULL → crash. A malicious model file causes a denial of service.

Reproduction

import struct, json
m = {"t":{"dtype":"I8","shape":[4294967296,4294967296],"data_offsets":[0,0]}}
j = json.dumps(m, separators=(",",":")).encode()
open("poc.safetensors","wb").write(struct.pack("<Q", len(j)) + j)
# load -> read_safetensors_file ACCEPTS; ggml_new_tensor -> data=NULL -> SEGV on access

Suggested fix

Validate each parsed dimension (reject <= 0) and compute the element-count product with __builtin_mul_overflow, rejecting the tensor up front on a non-positive dim or overflow. PR: #1875.

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