跳转到主要内容

CVE-2026-42600:ReadMultiple Storage-REST 路径穿越

从前置全量路径校验到彻底删除整条 RPC 接口:为什么一个自 2024 年起已无生产调用方的内部文件读取端点在 73ac524 中被直接移除。

状态: 已发布
首个包含版本: RELEASE.2026-06-18T00-00-00Z
修复提交: 73ac524
GitHub Advisory: GHSA-xh8f-g2qw-gcm7
影响范围: 仅分布式纠删码(distributed erasure)部署;需持有集群 root / 节点间 JWT

节点间 storage-REST 路由 /rmpl(ReadMultiple)的 msgpack 请求体中包含 Bucket、Prefix 与 Files 字段,旧代码未做磁盘根目录包含(containment)检查便直接将它们拼接成主机文件系统路径。

我们的第一版修复保留了该接口并实现了完整的前置路径校验;但在继续审计全仓调用链时发现,这条内部 API 自 2024 年 9 月起就已经没有任何生产调用方。最终方案(73ac524)因此从“原地保留并加固”转为彻底删除路由、处理器、客户端封装、StorageAPI 接口方法以及 msgpack 生成代码——删除约一千行废弃代码看似改动更大,却永久消除了这一高权限攻击面。

威胁模型

/rmpl 路由仅在分布式纠删码模式下注册,单机(single-node)部署不受影响。触发该漏洞需要攻击者持有由集群 root 密钥派生的节点间 JWT、已控制某个集群节点,或能够截获未加密的节点间通信流量。

由于受控的 Bucket、Prefix 与 Files 字段位于 msgpack 请求体内部,而非 URL 路径或查询参数(r.Form)中,上层 HTTP 路径校验中间件完全看不到这些字段。xlStorage.ReadMultiple 直接将它们与磁盘根目录拼接并读取文件,使持有节点间凭据的调用方能够跳出磁盘根目录(drive root),读取节点进程有权访问的任意主机文件。

第一版方案:保留接口并执行路径包含校验

第一版补丁选择在 xlStorage.ReadMultiple 内部原地加固:

  • 拒绝绝对路径、. 与 .. 路径段、反斜杠、Windows 盘符前缀以及 NUL 字节;
  • 校验 drive -> volume -> prefix -> file 的最终路径包含关系;
  • 兼容空 Bucket 与 .minio.sys/multipart 的历史调用约定;
  • 在打开任何文件或开始流式输出之前返回错误。

这套方案足以拦截直接路径穿越,但代码审查很快指出了读取循环与 MaxResults 交互时的一个提前返回漏洞。

MaxResults 暴露了“边读边校验”的缺陷

初版补丁在读取循环中逐项打开 Files 元素前才对该元素做路径校验。如果请求传入 Files = [good, "../../etc/passwd"] 且同时指定 MaxResults = 1,函数在读取第一个合法文件后就会因达到 MaxResults 上限而提前返回,第二个恶意路径永远不会被检查。

虽然该次请求并未实际读取第二个恶意文件,但它破坏了“包含非法路径的整包请求必须在执行任何读取前被拒绝”的安全不变量。为此,我们将所有路径与长度校验前移为流式响应开始前的全量前置(preflight)检查。

最终转折:为什么直接删掉整条 API

在合入前置校验补丁前,我们进一步追问了一个更根本的问题:现在究竟还有谁在调用 ReadMultiple?

全仓调用链与 Git 历史清查证实:

  • 上游早在 2024 年 9 月就已移除最后一个生产调用方,分片读取已全面切换至 ReadParts;
  • 当前 SILO 代码树中没有任何生产路径调用 ReadMultiple;
  • 上游针对 GHSA-xh8f-g2qw-gcm7 的正式处置同样是直接删除 ReadMultiple。
候选方案 短期代码改动 长期维护与攻击面 结论
原地保留并做前置校验 Diff 较小,保留 /rmpl 端点 在 StorageAPI 中永久维护一个无人使用的高权限批量读文件入口 放弃
彻底删除 ReadMultiple 涉及接口与 msgpack 生成代码,删除行数较多 彻底消除 /rmpl 攻击面,同时保持 storageRESTVersion 协议兼容 接受

提交 73ac524 移除了 /rmpl 路由、storage-REST 处理器、客户端包装、StorageAPI / xlStorage 方法、监控指标项以及 msgpack 请求/响应数据类型。

验证与发布

在原地校验阶段,我们编写并执行了覆盖 xlStorage、storage-REST 客户端、msgpack 编解码、路径穿越边界与 MaxResults 前置校验的单元测试。切换为彻底删除方案后,提交 73ac524(随 RELEASE.2026-06-18T00-00-00Z 发布)验证了路由、接口、生成代码与 go test ./cmd 全量通过。

兼容性与后续全局路径审计(SN-2026-002)

  • 外部 S3 API:无任何变化。
  • 集群升级建议:在分布式集群滚动升级期间,建议将所有节点同步升级至相同版本。
  • 其余内部节点接口的全量路径审计:针对其余在 msgpack 请求体或 Grid RPC 帧中传递文件路径的内部节点接口,全面清查与加固已在 SN-2026-002:节点间路径与内存分配边界收敛(随 RELEASE.2026-08-04T00-00-00Z 发布)中完成,覆盖全部剩余的 storage-REST、storage Grid RPC 与 peer-S3 Grid RPC 端点。