
云原生【免费下载链接】buildahA tool that facilitates building OCI images.项目地址https://gitcode.com/gh_mirrors/bu/buildah点击查看免费下载本文围绕 buildah 项目go.podman.io/buildah中实际 vendored 的第三方库vendor/github.com/cyphar/filepath-securejoin展开系统讲解其在 OCI 镜像构建工具中承担的安全路径解析职责从旧的SecureJoin语义、其固有 TOCTOU 风险与四条安全保证到基于openat2/fsopen/open_tree等现代内核 API 的全新OpenInRoot/MkdirAll接口并结合 buildah 源码与测试验证其真实调用场景。读完本文你将理解容器工具链中“把用户输入路径安全地限制在 root 目录内”的完整方案演进并掌握新旧两套 API 的适用边界与正确用法。一、背景为什么容器构建工具需要“安全的 filepath.Join”在 buildah 这类 OCI 镜像构建工具中存在大量“以用户输入路径在某个上下文目录context directory内查找/创建文件”的场景。例如解析构建上下文中的.containerignore/.dockerignore文件、从 git/HTTP 下载的构建上下文里定位子目录等。如果这些路径直接交给标准的filepath.Join拼接恶意输入中的..或符号链接就可能把访问引导到 root 目录之外造成路径逃逸。filepath-securejoin最初就是作为SecureJoin的实现而诞生的其设计意图是成为 Go 标准库中一个更安全的filepath.Join将路径查找限制在某个 root 目录之内该提案原计划进入 Go 标准库见go#20126。实现思路源自多个容器运行时中已有的代码。在 buildah 中该库被真实用于这些高风险路径解析点pkg/parse/parse.go 的ContainerIgnoreFile函数中用securejoin.SecureJoin(contextDir, .containerignore)与securejoin.SecureJoin(contextDir, .dockerignore)安全定位 ignore 文件防止构建上下文中的符号链接把解析引出上下文目录pkg/tmpdir/url.go 解析 git / HTTP 构建上下文时用securejoin.SecureJoin(downloadDir, contentSubdir)定位下载目录内的子目录copier/copier_test.go 与 copier/copier_test.go 的测试用例同样借助SecureJoin构造安全的期望路径。二、旧 APISecureJoin/SecureJoinVFS的语义与保证2.1 函数形态与核心行为旧 API 的核心是SecureJoin以及支持注入虚拟文件系统接口的SecureJoinVFS其实现位于vendor/github.com/cyphar/filepath-securejoin/join.gofunc SecureJoin(root, unsafePath string) (string, error)它把unsafePath与root安全地连接起来返回的路径保证落在root之内。SecureJoinVFS则额外接受一个 VFS 接口nil 时回落到标准os.*函数族——这允许在不实际触碰文件系统的情况下模拟路径解析便于测试。2.2 四条安全保证文档明确给出了该库在旧 API 下的四条保证任何使用SecureJoin的代码都应以此为准子路径保证只要未返回错误结果字符串必然是root的子路径且其中不再包含任何符号链接路径组件全部已被展开。chroot 语义展开符号链接时所有符号链接组件必须相对于所提供的 root 解析——这可以视为chroot(2)处理文件路径方式的用户态实现。注意这些符号链接不会被词法展开处理前不会先调用filepath.Clean。不存在的组件不受影响与filepath.EvalSymlinks语义类似SecureJoin不会因为路径中某个组件不存在而失败而是将其原样保留允许悬空符号链接的部分解析。结果必然被 Clean返回路径总是经过filepath.Clean因此不包含任何..组件。2.3 一个“平凡但危险”的对照实现为帮助理解语义README 给出了一个 GNU/Linux 上使用chrootreadlink的对照实现需要 root 权限且要求root内的readlink可信任比库内实现更晦涩package securejoin import ( os/exec path/filepath ) func SecureJoin(root, unsafePath string) (string, error) { unsafePath string(filepath.Separator) unsafePath cmd : exec.Command(chroot, root, readlink, --canonicalize-missing, --no-newline, unsafePath) output, err : cmd.CombinedOutput() if err ! nil { return , err } expanded : string(output) return filepath.Join(root, expanded), nil }这段代码形象地说明了“以 root 为文件系统根展开符号链接”的含义同时也暴露了它的性能与信任成本——这也是库内实现纯用户态、逐组件解析存在的意义。2.4 根本缺陷TOCTOU 竞态README 中最重要的警告是旧 API 在安全模型上“从根本上是危险的”。SecureJoin返回一个字符串路径此后调用者再对该路径执行os.OpenFile/os.MkdirAll等操作。如果攻击者能在SecureJoin返回之后、调用者使用该路径之前修改路径中的某个组件例如把某个中间目录替换成符号链接就会出现典型的 TOCTOUtime-of-check to time-of-use竞态导致路径逃逸。因此SecureJoin及SecureJoinVFS仍被提供仅用于支持历史遗留用户新用户被强烈建议避免使用SecureJoin改用下文的新 API或迁移到 libpathrs。三、新 API基于内核原语的竞态免疫方案新 API 是 libpathrs 部分方法的移植仅支持 Linux其核心思路是放弃“返回字符串路径”改为在打开文件描述符的过程中完成全部校验与解析从机制上消灭 TOCTOU 窗口。3.1 底层内核 API 支撑新 API 的实现会机会性地使用更新的内核接口底层实现见vendor/github.com/cyphar/filepath-securejoin/open.go、vendor/github.com/cyphar/filepath-securejoin/mkdir.go以及pathrs-lite/子包openat2(2)Linux 5.6所有查找操作都使用openat2以限制 magic-links 与 bind-mount 穿越针对部分操作并利用RESOLVE_IN_ROOT在 rootfs 内高效解析符号链接。fsopen(2)/open_tree(2)Linux 5.2为所有用户提供针对恶意/proc挂载的加固——要么检测出伪造的/proc要么避免被其欺骗。普通用户通过openat2获得保护特权用户额外获得fsopen/open_tree的更深层防护。3.2OpenInRoot安全的打开句柄func OpenInRoot(root, unsafePath string) (*os.File, error) func OpenatInRoot(root *os.File, unsafePath string) (*os.File, error) func Reopen(handle *os.File, flags int) (*os.File, error)OpenInRoot是对下面这段易受攻击代码的“更安全版本”path, err : securejoin.SecureJoin(root, unsafePath) file, err : os.OpenFile(path, unix.O_PATH|unix.O_CLOEXEC)新 API 之所以安全是因为它把“解析路径 打开文件”合并为一次不可被中间篡改的内核操作。使用要点返回的*os.File是O_PATH文件描述符能力受限调用者通常需要配合Reopen把它转成更可用的句柄。这个拆分是有意为之既支持 PTY 生成等高级场景也避免用户意外打开坏 inode 造成 DoS。调用者必须小心使用返回的句柄——通常只能直接对句柄操作稍有不慎就会制造新的安全问题。libpathrs 提供了更多辅助函数来安全使用这类句柄但当前没有计划把它们移植回filepath-securejoin。OpenatInRoot与OpenInRoot的区别在于 root 通过*os.File提供从而保证多次OpenatInRoot或MkdirAllHandle调用作用于同一个 rootfs。注意与SecureJoin不同OpenInRoot一旦遇到悬空符号链接或不存在的路径就立即报错。SecureJoin会把不存在的组件当作真实目录、允许悬空符号链接的部分解析这两种行为与 Linux 对不存在路径和悬空符号链接的处理方式相悖因此新 API 不再允许。3.3MkdirAll安全的递归建目录func MkdirAll(root, unsafePath string, mode int) error func MkdirAllHandle(root *os.File, unsafePath string, mode int) (*os.File, error)MkdirAll是对下面这段易受攻击代码的“更安全版本”防护的竞态与OpenInRoot相同path, err : securejoin.SecureJoin(root, unsafePath) err os.MkdirAll(path, mode)MkdirAllHandle与MkdirAll的关系如同OpenatInRoot与OpenInRootroot 以*os.File提供并返回最终创建目录的*os.File。该句柄保证与MkdirAllHandle创建的目录“实际等同”——这是先用MkdirAll再OpenatInRoot无法保证的。同样的 NOTE 适用一旦遇到悬空符号链接或不存在路径即报错不会为悬空符号链接所引用的不存在目录创建目录。四、在 buildah 中的实际调用链buildah 当前对filepath-securejoin的引入集中在路径解析与校验场景全部走旧 APISecureJoin构建上下文 ignore 文件定位pkg/parse/parse.go 在ContainerIgnoreFile中依次对.containerignore、.dockerignore执行securejoin.SecureJoin(contextDir, ...)解析失败即返回错误随后将结果交给imagebuilder.ParseIgnore读取排除规则。该函数在注释中被标记为“已弃用可能转为 internal”说明 buildah 正在谨慎收敛对旧 API 的依赖。远程构建上下文子目录解析pkg/tmpdir/url.go 在 git clone / HTTP 下载 / stdin 等上下文落地到downloadDir后用securejoin.SecureJoin(downloadDir, contentSubdir)解析用户指定的子目录出错时报 “resolving subdirectory …” 错误。测试验证copier/copier_test.go 与 copier/copier_test.go 在 copier 的路径安全测试中用SecureJoin(tmpdir, ...)构造期望路径与解析结果比对间接验证了符号链接、..等输入下的行为符合库的保证。从代码结构看buildah 的引入方式符合“旧 API 用于无文件系统竞争的传统路径校验新 API 面向需要抗竞态的打开/创建操作”的分工对安全性要求更高的打开与建目录场景可依据本库的演进方向逐步迁移到OpenInRoot/MkdirAll。五、许可证与再分发说明本库的许可证标识为SPDX-License-Identifier: BSD-3-Clause AND MPL-2.0双许可证并存部分代码衍生自 Go 标准库采用BSD 3-clause许可见 vendor/github.com/cyphar/filepath-securejoin/LICENSE.BSD其余文件多数衍生自 libpathrs采用MPL-2.0见 vendor/github.com/cyphar/filepath-securejoin/LICENSE.MPL-2.0。使用上文“新 API”的用户多半在使用此许可证下的代码每个源文件头部都有版权声明标明适用许可证请逐文件核对更多细节可参考 vendor/github.com/cyphar/filepath-securejoin/COPYING.md仓库内的完整副本见同目录。六、结论与选型建议追求兼容性、且调用点不存在“解析后复用”竞态窗口如 buildah 中纯路径校验场景可继续使用SecureJoin但必须清楚其 TOCTOU 局限并遵守四条保证的边界需要真正抗竞态的文件打开 / 目录创建应使用新 APIOpenInRoot/OpenatInRoot/Reopen与MkdirAll/MkdirAllHandle并接受“遇到悬空符号链接或缺失路径立即报错”的严格语义长期路线README 建议用户迁移到 libpathrs本库新 API 正是为平滑过渡而移植的过渡层。依赖该库的构建工具在升级内核Linux 5.6 支持openat25.2 支持fsopen/open_tree后将自动获得基于新内核能力的加固路径解析这也是 OCI 构建工具链在路径安全上的主流演进方向。赞分享云原生【免费下载链接】buildahA tool that facilitates building OCI images.项目地址https://gitcode.com/gh_mirrors/bu/buildah点击查看免费下载相关推荐OpenCloud 依赖解析filepath-securejoin 安全路径库的旧版 API 局限与新 API 实战OpenCloud 依赖解析filepath securejoin 安全路径库的旧版 API 局限与新 API 实战 导读 filepath securejo后端微服务存储认证鉴权skopeo 依赖解析filepath-securejoin 安全路径连接库的原理、API 与源码实践skopeo 依赖解析filepath securejoin 安全路径连接库的原理、API 与源码实践 本文以 skopeo 仓库中 vendored 的 g云原生CLI镜像仓库KubeEdge 依赖剖析filepath-securejoin 安全路径拼接库的 API 演进与容器场景实践KubeEdge 依赖剖析filepath securejoin 安全路径拼接库的 API 演进与容器场景实践 filepath securejoin 是一个云原生边缘计算物联网容器编排边缘网关上一篇终极抖音内容管理指南如何轻松批量下载视频、直播回放和完整资源库下一篇瑞萨 CPK-RA2L1 开发板跑通 RT-ThreadRA2L1 Cortex-M23 超低功耗 BSP 编译、烧录与 FSP/ENV 进阶配置实战创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考