From 61b625558fd19a186f2baef71ee3270ad839affb Mon Sep 17 00:00:00 2001 From: Noam ismach moshe Date: Fri, 20 Mar 2026 01:10:43 +0200 Subject: [PATCH] Fix potential integer overflow and unbounded allocation in ReadBlock --- table/format.cc | 30 +++++++++++++++++++++++++++--- 1 file changed, 27 insertions(+), 3 deletions(-) diff --git a/table/format.cc b/table/format.cc index ae998c1f30..5dc45d6452 100644 --- a/table/format.cc +++ b/table/format.cc @@ -4,6 +4,8 @@ #include "table/format.h" +#include + #include "leveldb/env.h" #include "leveldb/options.h" #include "port/port.h" @@ -13,6 +15,10 @@ namespace leveldb { +namespace { +// Reader-side safety cap for both compressed and decompressed block payloads. +static constexpr size_t kMaxBlockBytes = 256u * 1024u * 1024u; +} // namespace void BlockHandle::EncodeTo(std::string* dst) const { // Sanity check that all fields have been set assert(offset_ != ~static_cast(0)); @@ -74,15 +80,25 @@ Status ReadBlock(RandomAccessFile* file, const ReadOptions& options, // Read the block contents as well as the type/crc footer. // See table_builder.cc for the code that built this structure. + size_t n = static_cast(handle.size()); - char* buf = new char[n + kBlockTrailerSize]; + + if (n > kMaxBlockBytes) { + return Status::Corruption("bad block size"); + } + if (n > std::numeric_limits::max() - kBlockTrailerSize) { + return Status::Corruption("bad block size overflow"); + } + const size_t block_plus_trailer = n + kBlockTrailerSize; + + char* buf = new char[block_plus_trailer]; Slice contents; - Status s = file->Read(handle.offset(), n + kBlockTrailerSize, &contents, buf); + Status s = file->Read(handle.offset(), block_plus_trailer, &contents, buf); if (!s.ok()) { delete[] buf; return s; } - if (contents.size() != n + kBlockTrailerSize) { + if (contents.size() != block_plus_trailer) { delete[] buf; return Status::Corruption("truncated block read"); } @@ -123,6 +139,10 @@ Status ReadBlock(RandomAccessFile* file, const ReadOptions& options, delete[] buf; return Status::Corruption("corrupted snappy compressed block length"); } + if (ulength > kMaxBlockBytes) { + delete[] buf; + return Status::Corruption("snappy block too large"); + } char* ubuf = new char[ulength]; if (!port::Snappy_Uncompress(data, n, ubuf)) { delete[] buf; @@ -141,6 +161,10 @@ Status ReadBlock(RandomAccessFile* file, const ReadOptions& options, delete[] buf; return Status::Corruption("corrupted zstd compressed block length"); } + if (ulength > kMaxBlockBytes) { + delete[] buf; + return Status::Corruption("zstd block too large"); + } char* ubuf = new char[ulength]; if (!port::Zstd_Uncompress(data, n, ubuf)) { delete[] buf;