Redis 三线同日发安全版:集群总线传播超过 4GB 的消息会堆溢出
8.10.3、8.8.4、8.6.8 修同一个问题:cluster 模式下通过总线传播大于 4GB 的 PUBLISH/SPUBLISH 消息会堆溢出。影响面窄,但触发条件里有值得记住的东西。
Redis 在 10 月 26 日同时发了 8.10.3、8.8.4、8.6.8,三个版本修同一个问题:
集群模式下,通过集群总线传播大于 4GB 的
PUBLISH/SPUBLISH消息时会发生堆缓冲区溢出。
更新紧急度标的是 SECURITY。这条看起来是个「几乎碰不到」的 bug,但它值得写,因为触发条件的形状很典型。
触发条件拆开看
四个条件必须同时成立:
- cluster 模式 —— 单机或主从复制不经过集群总线,不受影响;
- 用了
PUBLISH或SPUBLISH—— 也就是 pub/sub; - 消息体大于 4GB;
- 通过集群总线传播(消息要跨节点)。
第三条是关键。一个 4GB 的消息本身就不正常:
# 默认协议上限是 512MB,正常业务根本到不了 4GB
redis-cli config get proto-max-bulk-len
# 1) "proto-max-bulk-len"
# 2) "536870912"
proto-max-bulk-len 默认 512 MB。要发出 4 GB 的消息,得先把它调大 —— 也就是说这不是「随手就能触发」的漏洞,而是配置被放宽 + 业务真的发了巨型消息才会碰上。

为什么「4GB」这个数字眼熟
32 位长度字段。很多协议在头部用 32 位整数表示长度,最大 4294967295 字节 —— 恰好 4GB 减 1。当长度计算超过这个边界,就会出现截断或整数回绕,紧接着是分配不足与越界写入。
Redis 集群总线有自己的二进制协议(cluster bus),消息在这里要经过一次重新封装。越界发生在封装这一步:内部表示能装下(Redis 字符串本身用 64 位长度),但总线的长度字段装不下。
这类 bug 的通用教训是:跨协议边界时的长度校验,必须按「最窄的那一层」来做。内部能装 4GB,不代表外部协议能装。
三线同发说明什么
Redis 现在同时维护 8.10、8.8、8.6 三条线。安全修复要在三条线上各打一次,这本身就是成本 —— 也是为什么 Redis 的补丁版发布总是「同一天三个版本」。
对使用者的动作很简单:升到对应线的最新补丁版。三条线的选择取决于你现在用哪个大版本,跨线升级不是安全补丁的范围。

除了升级,还该做什么
这个漏洞的真正提示不是「快升级」,而是你的配置被谁放宽了:
proto-max-bulk-len被调到 4GB 以上,通常是为了「传大对象」—— 那说明有人把 Redis 当消息队列或对象存储用;PUBLISH传大消息,说明 pub/sub 被当成了数据传输通道 —— 它设计上只该传「通知」,不该传「数据」。
我的做法是把这两条写进配置审查清单:
# 上限保持默认或更小;要传大对象请用对象存储
proto-max-bulk-len 512mb
# 单条 pub/sub 消息超过 1MB 就该换设计
client-output-buffer-limit pubsub 8mb 2mb 60
client-output-buffer-limit 那条是防线:即使有人真的发大消息,输出缓冲区上限也会先把他断开,而不是让节点 OOM。
一句话判断
影响面很窄 —— 需要集群 + pub/sub + 放宽过的协议上限。但**「窄」不等于「不用升」**:安全补丁的成本是一次滚动重启,不升的成本是一次无法解释的段错误。而且这次的触发条件里,有一半是配置问题,配置问题从来不会自己变好。


评论
…