Validate IndexBinaryHash b <= code_size*8 during deserialization (#5011)

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

Add a deserialization-time check in `read_index_binary` that rejects
`IndexBinaryHash` data where `b` exceeds `code_size * 8`.  Without
this validation, a malformed index can cause `BitstringReader::read()`
to access past the allocated code buffer during search, resulting in a
heap-buffer-overflow.

Reviewed By: mnorris11

Differential Revision: D98811392

fbshipit-source-id: 6847bce77be6edb66d87bd28a770c2af615868d3
This commit is contained in:
Justin Gibbs
2026-04-01 15:09:00 -07:00
committed by meta-codesync[bot]
parent 87bc9b0872
commit 668da4a386
2 changed files with 20 additions and 0 deletions
+5
View File
@@ -2624,6 +2624,11 @@ std::unique_ptr<IndexBinary> read_index_binary_up(IOReader* f, int io_flags) {
idxh->b > 0,
"invalid IndexBinaryHash b=%d (must be > 0)",
idxh->b);
FAISS_THROW_IF_NOT_FMT(
static_cast<size_t>(idxh->b) <= idxh->code_size * 8,
"IndexBinaryHash b=%d exceeds code_size=%d bits",
idxh->b,
idxh->code_size);
READ1(idxh->nflip);
read_binary_hash_invlists(idxh->invlists, idxh->b, idxh->code_size, f);
idx = std::move(idxh);
+15
View File
@@ -704,6 +704,21 @@ TEST(ReadIndexDeserialize, BinaryHashIlNbitZeroWithEntries) {
expect_binary_read_throws_with(buf, "il_nbit=");
}
// -----------------------------------------------------------------------
// Test: IndexBinaryHash with b exceeding code_size*8 triggers validation.
// Without this check, BitstringReader::read() would access past the
// allocated code buffer, causing a heap-buffer-overflow.
// -----------------------------------------------------------------------
TEST(ReadIndexDeserialize, BinaryHashBExceedsCodeSize) {
std::vector<uint8_t> buf;
push_fourcc(buf, "IBHh");
push_binary_index_header(buf, /*d=*/16, /*ntotal=*/0);
// d=16 → code_size=2 → 16 bits available
push_val<int>(buf, 17); // b = 17 (exceeds 16 bits)
expect_binary_read_throws_with(buf, "IndexBinaryHash b=");
}
// -----------------------------------------------------------------------
// Test: read_binary_multi_hash_map with crafted ilsz values that sum to
// more than ntotal. Without the check, the inner loop would read past