Validate SVS-Vamana stored_vectors size on deserialization (ISV2) (#5434)

Summary:
Pull Request resolved: https://github.com/facebookresearch/faiss/pull/5434

The `ISV2` (IndexSVSVamana) deserialization branch reads `ntotal`, `d`
(header), and the raw `stored_vectors` payload as independent fields and
never re-establishes the invariant `stored_vectors.size() == ntotal * d`
that the programmatic `add()` path maintains.
`IndexSVSVamana::reconstruct` guards only `key < ntotal` and
`stored_vectors` non-empty, then `memcpy`s `sizeof(float) * d` bytes from
`stored_vectors.data() + key * d`. A crafted index declaring e.g.
`ntotal=1, d=256` with a 1-element payload reads ~1 KiB past the heap
allocation (heap-buffer-overflow read).

Adds the `stored_vectors.size() == ntotal * d` check at deserialization,
matching the sibling flat-codes readers, converting the OOB read into a
clean FaissException. The SVS family is compile-gated (FAISS_ENABLE_SVS,
x86_64). Found by agentic fuzzing.

Reviewed By: trang-nm-nguyen

Differential Revision: D112368334

fbshipit-source-id: ba4ba275dd0444216139921c8d15628ccbb29fc0
This commit is contained in:
Michael Norris
2026-07-17 10:16:31 -07:00
committed by meta-codesync[bot]
parent dfd2a25aed
commit d43336302e
+7
View File
@@ -2851,6 +2851,13 @@ std::unique_ptr<Index> read_index_up(IOReader* f, int io_flags) {
}
if (h == fourcc("ISV2")) {
READVECTOR(svs->stored_vectors);
FAISS_THROW_IF_NOT_MSG(
svs->stored_vectors.size() ==
mul_no_overflow(
(size_t)svs->ntotal,
(size_t)svs->d,
"IndexSVSVamana stored_vectors"),
"ISV2: stored_vectors size inconsistent with ntotal * d");
} else {
svs->stored_vectors_valid = false;
}