【BUG】在 Block::Block (位于 block_based/block.cc 文件中) 中,重启偏移量的计算会导致 RocksDB-v6.26.1 中整数溢出。
作者: wkxNiubi创建于 2026年9月14日更新于 2026年9月14日
问题描述 在 Block::Block 中的 kDataBlockBinaryAndHash 路径中,restart_offset_ 计算为 map_offset - num_restarts_ * sizeof(uint32_t)。这里, num_restarts_ 的类型是 uint32_t,根据 data_block_footer.cc,其最大值为 0x7FFFFFFF; map_offset 是一个 uint16_t,由 DataBlockHashIndex::Initialize 从攻击者的字节中解析出来。在赋值给 uint32_t 成员 restart_offset_ 时,64 位乘积会被截断,因此任何 num_restarts_ 都小于或等于 map_offset 模 2^32 都可以绕过包围检查。当 num_restarts_ = 2^30 (footer 0x40000000; 31 位 num_restarts 字段包含第 30 位,这是一个有效值) 时,乘积为 2^32,restart_offset_ 等于 map_offset。"restart_offset_ > map_offset" 条件不成立,且该块被接受。随后,Block 声称其具有一个在内部小缓冲区开始的重启数组,包含 2^30 个四字节项;在 DB 打开、压缩、迭代和由攻击者提供的 SST 数据块的读取过程中,BlockIter::GetRestartPoint 和 BinarySeek/ParseNextKey 会每次执行 Seek/Next/Prev 时解析 data_ + restarts_ + index*4 的引用,最大的越界访问大约为 4GB。上游随后通过将 num_restarts 的上限设置为 2^28 - 1 并拒绝保留 footer 位(DataBlockFooter)来修复此缺陷,并将之前的行为描述为"num_restarts 乘以 4,导致溢出,检查被默默忽略。"
内容来源: facebook/rocksdb