CVE-2026-39414:S3 Select 超大记录与 SIMD 快路径绕过
状态: 已发布,6 月完成第二轮闭环
初始修复版本: RELEASE.2026-04-17T00-00-00Z
完整修复版本: RELEASE.2026-06-18T00-00-00Z
修复提交: 3252d5b、5dc705936(fd69c89)
GitHub Issue: pgsty/silo#25
4 月份的第一轮修复(3252d5b)复用既有的 1 MiB maxCharsPerRecord 常量,同时限制 S3 Select 中的 CSV 与标准 JSON Lines 单条记录长度,防止在遇到记录分隔符前无界缓冲内存,并向客户端返回明确的 OverMaxRecordSize 错误码。
6 月份的调用链复核却发现了一个与硬件特性绑定的绕过缺口:在支持 AVX2/AVX-512(即 simdjson.SupportedCPU() 返回 true)的 CPU 上,JSON Lines 会进入另一条 simdjson 快路径,完全绕过第一轮修复的 json.PReader。最终方案(5dc705936 / fd69c89)让 JSON Lines 在所有 CPU 上统一走有界读取器,并同步修正了流式错误码映射、解析器错误包装以及终止错误事件前的已完成记录刷出逻辑。
威胁模型
具备 s3:GetObject 权限的调用方可以通过 S3 Select(SelectObjectContent)查询包含超长无换行单条记录的对象。如果读取器在遇到记录分隔符前持续向内存追加缓冲而没有上限,单次查询即可耗尽节点内存与 CPU。
更隐蔽的风险在于硬件特性分流:同一份输入对象在不同指令集特性的机器上会进入完全不同的解析实现。在不支持 SIMD 的测试环境中跑通的边界检查,并不自动保护支持 AVX2/AVX-512 的生产服务器。
第一轮:复用既有的 1 MiB 单记录不变量
第一版补丁(3252d5b)没有引入新的配置项,而是直接沿用代码库已有的 maxCharsPerRecord = 1 MiB(1048576 字节)规则:
- CSV 切分器与标准行分隔 JSON 读取器在继续缓冲或解析前拒绝超过 1 MiB 的单条记录;
- 保留最早发生的切分器错误,避免被后续不完整解码产生的次生错误覆盖;
- 将错误准确透传为
OverMaxRecordSize,而不再折叠成笼统的InternalError,使客户端与监控告警能够区分“触发安全长度上限”与“服务端内部故障”。
第二轮:与 CPU 指令集相关的 SIMD 绕过
6 月份顺着 S3 Select 的 JSON 分发链路继续下钻时,我们发现了下面这条分支:
当 simdjson.SupportedCPU() 为真时,JSON Lines 直接进入 simdj.NewReader,完全绕过了有界的 json.PReader。而在 simdjson.ParseNDStream 内部,第三方解析器会跨数据块持续读取,直到找到换行符为止。如果在底层 io.Reader 外面再套一层字节计数包装器,根本无法同时满足“不截断同一数据块内已完成的合法记录”与“严格限制下一条记录不超过 1 MiB”两个条件。
因此,提交 5dc705936 与 fd69c89 没有采用脆弱的外层包装器,而是停用了 JSON Lines 的 SIMD 分支,让所有 CPU 统一走有界的 json.PReader。未来若要重新启用 SIMD 加速,SIMD 解析器自身必须原生执行相同的单记录长度边界,并通过同一套与 CPU 特性无关的回归测试。
同一轮修正的流式协议语义
6 月份的复核同时修复了 S3 Select 流式管道中的四处相邻问题:
- 基于接口识别错误类型:改用
errors.As透传所有实现SelectError接口的错误,而非仅匹配单一具体结构体类型。 - 包装 JSON 语法错误:在 JSON worker 中将语法解析失败统一包装为
JSONParsingError。 - 终止错误前刷出已完成记录:在写出终止错误事件(terminal error event)之前,先将输出队列中已完成解析但尚不足一个 batch 大小的结果刷出给客户端。
- 按输入顺序保留错误优先级:当输入流中前一行先发生语法错误、后一行又出现超长记录时,保留最早发生的解析错误而不被后续超长记录覆盖。
刻意排除在本 CVE 之外的问题
为避免在安全补丁中混入未经充分兼容性求证的行为变更,以下三项议题被明确留在本次修复范围之外:
- CSV
AllowQuotedRecordDelimiter与外层物理换行切分器之间的历史语义偏差; CRLF中的\r是否计入 1 MiB 记录长度;- 在
simdjson内部尚未具备原生记录长度裁剪机制前恢复 SIMD NDJSON 快路径。
验证与发布
internal/s3select 的回归测试覆盖了超长 CSV 与 JSON Lines 记录、OverMaxRecordSize 与 JSONParsingError 错误码保留、错误前队列刷出以及不依赖本机 SIMD 能力的行为一致性验证:
初始修复随 RELEASE.2026-04-17T00-00-00Z(3252d5b)发布,消除 SIMD 绕过的完整修复随 RELEASE.2026-06-18T00-00-00Z(5dc705936 / fd69c89)发布。
最终取舍
- 吞吐量与一致边界的取舍:停用 SIMD NDJSON 快路径会降低支持 AVX2/AVX-512 主机上的 JSON Lines 解析吞吐量,但换取了所有 CPU 架构上严格一致的 1 MiB 单记录内存上限。
- 1 MiB 单记录硬上限:包含超过 1 MiB 单行或单记录的输入在升级后会被
OverMaxRecordSize拒绝,客户端需在查询前切分超长记录。 - 带引号的多行 CSV:带引号多行 CSV 的分隔符语义作为独立兼容性问题另行跟踪。