#1348·leveldb

Block entry bounds check wraps around: 2 GiB out-of-bounds read in Block::Iter::ParseNextKey

Author: h-t-mCreated Aug 19, 2026Updated Aug 22, 2026

DecodeEntry (table/block.cc:71 at HEAD 7ee830d) validates a block entry with:

cpp
if (static_cast<uint32_t>(limit - p) < (*non_shared + *value_length)) {
  return nullptr;
}

The sum *non_shared + *value_length is computed in uint32_t and wraps around. A crafted entry with non_shared = 0x80000000 and value_length = 0x80000001 sums to 1, passes the check, and Block::Iter::ParseNextKey then executes key_.append(p, 0x80000000) (table/block.cc:269) — reading 2 GiB starting from inside the (small) block buffer.

Reproduction (105-byte crafted SSTable, no fuzzing required):

  • data block contents: entry [shared=0][non_shared=varint(0x80000000)][value_length=varint(0x80000001)] + 1 filler byte + restart array (restart point 0, num_restarts 1); trailer type kNoCompression
  • index block with a single entry pointing at that data block; standard footer with magic
  • Table::Open succeeds; NewIterator() + SeekToFirst() triggers the read

Observed:

  • Release build (leveldb built by its own CMake): the process dies with SIGBUS/SIGSEGV inside the 2 GiB read (exit 135).
  • ASan build with NDEBUG: AddressSanitizer: READ of size 2147483648 in leveldb::Block::Iter::ParseNextKey() via SeekToFirst.

This is reachable from any iteration/seek over a crafted on-disk table (block checksums protect against accidental corruption, not against a deliberately constructed file), e.g. when opening a restored/synced/imported database. I reported this through Google's vulnerability process first; it was reviewed as a valid finding and I was directed to open it here.

Suggested fix — widen the sum before comparing:

cpp
if (static_cast<uint64_t>(limit - p) <
    static_cast<uint64_t>(*non_shared) + *value_length) {
  return nullptr;
}

or bound-check each operand against limit - p individually.

A self-contained reproduction program (crafts the table and drives Table::Open/SeekToFirst) is available; happy to attach it or send it as a PR adding a regression test.