From edc8766ecb011ae0be68db6e4e16c65a5634ac77 Mon Sep 17 00:00:00 2001 From: Luigi Colluto Date: Tue, 14 Jul 2026 22:10:10 +0200 Subject: [PATCH] Bound tensor data offset/size against the mapping in gguf_get_tensor Follow-up to #28. That PR bounds the metadata / tensor-info walk, but the tensor DATA region is still unchecked: gguf_get_tensor computes tensor->offset = ctx->data_off + *offset and tensor->weights_data = ctx->data + tensor->offset from a raw file-supplied 64-bit offset, with no check that the range stays inside the mapping. Any later read of the weights (gguf_tensor_to_float, inspect-tensor, compare) is then an out-of-bounds read. Compute bsize first, then verify (overflow-safe) that *offset and the resulting absolute offset are within ctx->size and that the bsize-byte extent fits, before forming weights_data. Reject with return 0 otherwise. --- gguflib.c | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/gguflib.c b/gguflib.c index b84a6db..86b9c68 100644 --- a/gguflib.c +++ b/gguflib.c @@ -295,7 +295,6 @@ int gguf_get_tensor(gguf_ctx *ctx, gguf_tensor *tensor) { ctx->off += 8; // Skip tensor offset. tensor->offset = ctx->data_off + *offset; - tensor->weights_data = ctx->data + tensor->offset; /* To accurately calculate the bytes used by this tensor on the GGUF * file, we need to take into account that quantization methods store @@ -308,6 +307,22 @@ int gguf_get_tensor(gguf_ctx *ctx, gguf_tensor *tensor) { tf = gguf_get_tensor_type_features(tensor->type); uint64_t weights_padding = gguf_get_alignment_padding(tf->items_per_block,tensor->num_weights); tensor->bsize = ((tensor->num_weights+weights_padding) / tf->items_per_block) * tf->bytes_per_block; + + /* Bound the tensor data region against the mapped file BEFORE forming the + * data pointer. The offset comes straight from the file, so a crafted + * value can place weights_data (or its bsize-byte extent) outside the + * mapping; any later read of the weights (dequantization, inspect-tensor, + * compare) would then be an out-of-bounds read. Checks are overflow-safe: + * *offset and the resulting absolute offset must both be within ctx->size, + * and the extent is verified with a subtraction that cannot underflow. */ + if (*offset > ctx->size || + tensor->offset > ctx->size || + tensor->bsize > ctx->size - tensor->offset) + { + return 0; + } + + tensor->weights_data = ctx->data + tensor->offset; return 1; }