Cross-check tensor data size against shape in FP8/FP4 dequant (OOB read)#543
Open
gigioneggiando wants to merge 1 commit into
Open
Cross-check tensor data size against shape in FP8/FP4 dequant (OOB read)#543gigioneggiando wants to merge 1 commit into
gigioneggiando wants to merge 1 commit into
Conversation
A safetensors tensor's shape and its data_offsets byte range are independent header fields. db_read() sizes the buffer (st_value.nbytes) from data_offsets, while dequant_fp8_weight() / dequant_fp4_weight() index w->data and scale->data by shape. They were never cross-validated, so a weight that declares a large shape but a tiny data_offsets range (e.g. shape [128,128] = 16384 elements with only 128 bytes of data) makes the loops read past the end of the heap buffer -- a heap-buffer-overflow read, leaking adjacent heap bytes into the produced GGUF. Before the loops, require nbytes to cover the shape-driven access: one byte per element for the F8_E4M3 / I8 weights and F8_E8M0 scales.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
A safetensors tensor's
shapeand itsdata_offsetsbyte range are independent header fields.db_read()sizes the on-disk buffer (st_value.nbytes) fromdata_offsets, whiledequant_fp8_weight()/dequant_fp4_weight()indexw->dataandscale->databyshape. The two are never cross-validated.So a weight that declares a large
shapebut a tinydata_offsetsrange — e.g.shape=[128,128](16384 elements) with only 128 bytes of data — makes the dequant loops read far past the end of the heap buffer: a heap-buffer-overflow read, which leaks adjacent heap bytes into the produced GGUF.Fix
Before the dequant loops, require
nbytesto cover the shape-driven indexing (one byte per element for theF8_E4M3/I8weights andF8_E8M0scales). Mismatched tensors are rejected with a clear error instead of reading OOB.Verification
Drove a real crafted safetensors shard + index through
db_open → db_read → dequant_fp8_weightunder ASan:AddressSanitizer: heap-buffer-overflow READatdequant_fp8_weightoff the 128-byte buffer.error: FP8 tensor data smaller than its declared shape, no sanitizer error.Found during a coordinated security review of ds4; a standalone offline PoC is available on request.