Skip to content

Security: constrain local volume removal - #657

Open
GOLDKUN wants to merge 2 commits into
chaitin:mainfrom
GOLDKUN:fix/managed-volume-path-boundary
Open

Security: constrain local volume removal#657
GOLDKUN wants to merge 2 commits into
chaitin:mainfrom
GOLDKUN:fix/managed-volume-path-boundary

Conversation

@GOLDKUN

@GOLDKUN GOLDKUN commented Sep 2, 2026

Copy link
Copy Markdown

问题

Local volume removal accepted the persisted record.Path and passed it to os.RemoveAll. A path outside the daemon-managed volume tree could therefore be deleted when a volume was removed. Symlink and path normalization checks were also incomplete.

影响

如果恶意或被篡改的 volume metadata 包含宿主机敏感目录,调用 volume remove/prune 可能删除项目根目录之外的数据。涉及 CWE-22、CWE-61。

修复内容

  • Local driver 删除前将 volume path 和 managed root 规范化为绝对 realpath。
  • 强制删除目标必须位于 DATA_ROOT/volumes/local 内,拒绝 root 本身和所有越界路径。
  • managed volume 仍只删除其自身 volume 目录,不改变正常生命周期。
  • 增加回归测试,验证 managed root 外的 marker 文件不会被删除。

验证

  • go test ./pkg/volumes -run 'TestLocalDriverRemoveRejectsPathOutsideManagedRoot|TestManagerRemoveForce' -count=1
  • git diff --check

说明:完整 pkg/volumes 测试当前在 macOS 上仍有基线中的 /var/private/var 路径断言失败,本 PR 未改变该路径规范化行为。

@monkeyscan

monkeyscan Bot commented Sep 2, 2026

Copy link
Copy Markdown

PR Title: Security: constrain local volume removal

Commit: 450c285

本次变更为 LocalDriver.Remove 增加路径越界防护:将 record.Path 与受管根 DataRoot/volumes/local 都经 filepath.Abs 规范化后,用 EvalSymlinks 解析真实路径,再通过新增的 pathWithinRoot 校验待删路径必须位于受管根内,防止删除受管目录之外的任意路径;同时把“是否删除 volume 数据父目录”的判断从字符串比较改为符号链接解析后的等值比较。测试新增了外部路径拒绝用例,并调整两个既有用例使 record.Path 落在受管根内。

安全方向正确,但实现引入两个问题:(1) EvalSymlinks 要求路径必须存在,破坏了原 os.RemoveAll 对不存在路径幂等成功的语义,当 volume 数据目录已被删除或 DataRoot/volumes/local 尚未创建时,driver.Remove 返回错误,导致 Manager.Remove 跳过 store.DeleteVolume,留下无法清理的僵尸记录;(2) 符号链接解析后的等值比较会把删除范围从 volume 目录提升到整个受管根 volumes/local,存在删除范围放大为清空全部 volume 的风险。

Comment thread pkg/volumes/driver.go
Comment thread pkg/volumes/driver.go Outdated
@GOLDKUN

GOLDKUN commented Sep 2, 2026

Copy link
Copy Markdown
Author

已按最新评论修订卷删除逻辑:

  • 对已经不存在的 volume data path 保持 os.RemoveAll 的幂等语义,直接成功返回,避免 Manager 无法删除数据库中的僵尸记录。
  • managed root 不存在时不再盲目依赖 EvalSymlinks;对存在目标使用允许缺失祖先的 canonicalization 进行安全边界判断。
  • 删除 volume 父目录的提升条件改为仅接受“record.Path 与该 volume 的规范 managed data path 完全相同”,不再根据解析后的符号链接路径等值提升删除范围。
  • 即使 data 路径是指向 volume 父目录的自指符号链接,也只删除单个 volume 目录,不会删除整个 volumes/local 根目录。
  • 新增缺失路径幂等测试和自指符号链接回归测试。

本地新增及相关测试通过:go test ./pkg/volumes -run 'TestLocalDriverRemove|TestManagerRemoveForce' -count=1

@monkeyscan

monkeyscan Bot commented Sep 2, 2026

Copy link
Copy Markdown

PR Title: Security: constrain local volume removal

Commit: 388dc05

本次改动针对 pkg/volumes/driver.go 中 LocalDriver.Remove 的两个已确认历史问题做安全加固,并新增两个回归测试。

改动要点:

  1. EvalSymlinks(absPath) 失败且为 os.ErrNotExist 时直接返回 nil,恢复删除幂等性(历史问题②:数据目录已被清理时 driver.Remove 报错导致 store 记录变僵尸)。
  2. 将 EvalSymlinks(managedRoot) 替换为新增的 canonicalizePathAllowMissing(),允许受管根目录尚未创建时仍能完成路径判定(也服务于幂等删除)。
  3. 将“升级删除范围为 volume 父目录”的判定从 EvalSymlinks 后的真实路径等值比较(resolvedPath == resolvedManagedPath)改为对 absPath/absManagedPath 做纯字符串比较,再对 volume 父目录 canonicalize 后做 pathWithinRoot 校验。这修复了历史问题①:当 data 子路径是 -> . 之类的符号链接时,旧逻辑会把删除范围放大到整个受管根目录;新逻辑把删除边界收敛到该 volume 自身的容器目录 。

评估结论:

  • 对历史问题①的修复在威胁模型内是完整的:removePath 只能是 resolvedPath 或 resolvedVolumePath,二者都被 pathWithinRoot 校验为严格位于受管根目录内部(排除 "."、".."),因此无法再删除受管根目录或其上级;os.RemoveAll 不跟随符号链接,即使 volume 容器内含指向外部的符号链接,也只会删除链接本身,不会扩大删除范围。
  • 对历史问题②的修复覆盖了“默认受管 volume 数据目录缺失”及“受管根目录未创建”的幂等删除场景;Manager.Remove 在 driver.Remove 返回 nil 后会正常清理 store 记录。
  • 我额外推演了 data->..、data->兄弟 volume、中间目录为悬空符号链接、受管根目录为悬空符号链接、外部自定义路径、TOCTOU(RemoveAll 不跟随链接)等边界,均未发现本改动新引入的高置信度漏洞或数据丢失回归;涉及外部自定义路径 volume 的删除被 pathWithinRoot 拒绝属于既有安全设计(避免删除受管根以外的宿主目录),并非本改动引入。
  • 新增的两个测试分别覆盖幂等删除与符号链接不放大删除范围,方向正确;未发现需要报告的遗漏。

总体判断:改动目标明确、实现与威胁模型匹配,未发现本改动引入的新增可操作问题,因此不提交新 finding。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant