LWN:pidfdfs 带来的另一个意外!
共 2716字,需浏览 6分钟
·
2024-06-13 13:39
关注了就能看到更多这么棒的文章哦~
One more pidfdfs surprise
By Jonathan Corbet
May 31, 2024
Gemini-1.5-flash translation
https://lwn.net/Articles/976125/
“pidfdfs” 虚拟文件系统 (virtual filesystem) 在 6.9 内核版本中被添加,其目的是为了向用户空间 (user space) 提供关于运行进程 (running processes) 更完善的信息。它取代了之前的一个实现,表面上是完全兼容的,同时还增加了一些新的功能。这个过渡原本意图对现有的应用程序 (applications) 完全透明,但早在今年三月就 遇到了问题,当时 SELinux 的一个误解导致了安装了 pidfdfs 的系统无法正常启动 (boot)。这个问题很快就被解决了,但事实证明,还有一个惊喜在等着我们,它表明 ABI 兼容性有时是多么难以实现。
pidfd 是一个标识运行进程的文件描述符 (file descriptor)。在内核 (kernel) 中,它必须包含所有与文件描述符相关的正常数据结构,这样内核子系统才能知道如何处理它。从 2007 年的 2.6.22 版本开始,内核就有一个小型的辅助机制,为那些没有实际文件支持的虚拟文件系统上的文件描述符提供匿名 inode (anonymous inodes)。当 pidfd 抽象 被添加到 5.1 内核时,它自然地使用了匿名 inode,并且一切如预期地工作。
然而,最终,这种实现的局限性开始显现。为了解决这个问题,Christian Brauner 重构了实现,不再使用匿名 inode,而是创建了独立的 pidfdfs 文件系统。新文件系统支持在 pidfd 上使用 statx()
;这反过来又让用户空间能够获得真正的 inode 编号,可以用它们来比较两个 pidfd 是否相等。新的功能(比如当引用某个进程的最后一个 pidfd 被关闭时杀死该进程)成为可能。新实现也让安全模块 (security modules) 参与了 pidfd 操作;这是第一组问题的根源,但从长远来看,它将帮助管理员更好地控制他们的系统。
当安全模块问题解决后,似乎 pidfdfs 的问题已经解决了。但随后,Jiri Slaby 报告说,安装了 pidfdfs 的内核破坏了 util-linux 测试套件和 lsof
实用程序。Brauner 回答说 util-linux 的问题已经在上游被修复了,但 lsof
却是一个意外。事实证明,有两个问题需要解决,其中一个比另一个更容易预先想到。
在 6.9 之前的系统中,"ls -l
" 或 lstat()
会将 pidfd 显示为指向字符串 "anon_inode:[pidfd]
" 的符号链接 (symbolic link)。从 6.9 开始,结果变成了 "pidfd:[=/=inode=/=]
", 显示了分配给 pidfd 的 inode 编号。由于 lsof
在寻找 6.9 之前的字符串版本,因此它无法识别或正确处理 pidfd。
但事实证明,还有更多问题。当匿名 inode 代码被添加时,作者从未费心 (或者只是忘记了) 在创建每个 inode 时设置其中的文件类型字段。因此,像 stat()
这样的系统调用会报告文件类型为零,而这实际上并非定义好的文件类型。这会导致像 stat
这样的命令行工具将结果描述为“奇怪的文件”(weird file),这客观上是正确的。这个小问题从未对真正使用匿名 inode 支持的文件的工具造成过麻烦,因此它从未被修复。
但它还是被注意到了。某个正在开发 lsof
的人巧妙地意识到,文件类型为零是一种识别匿名 inode 文件的方便方法。因此, lsof
获得了一个针对此条件的测试,利用了从未被预期,更不用说记录的 ABI 特性。一旦对 pidfd 的 stat()
调用开始返回正确的文件类型, lsof
便不再识别该文件,并变得不知所措。当这一切查清楚时,Linus Torvalds 并不高兴:
真是糟糕。太可怕了,我们显然从未注意到 anon_inode 有多糟糕,因为没有人真正关心。但随后
lsof
似乎做了 相反 的事情,只是 (出于难以理解的原因) 说“这不可能是一个正常的普通文件”。
也就是说,他也承认,“我们可能不得不睡在我们自己做的床上(意思是自食其果)”;破坏 lsof
是一个需要修复的用户空间 (user-space) 回归问题。
Brauner 编写了一个补丁,该补丁在 6.10-rc1 版本发布之前被 合并;它尚未进入 6.9 稳定更新。该补丁恢复了 pidfd 的旧输出格式,并使文件类型字段被显式地屏蔽为零,恢复了之前行为。有了这个修复, lsof
再次工作,人们大多很满意。
当他 发送补丁 时,Brauner 说他“希望在不久的将来尝试摆脱目前这种疯狂的行为”。他希望 lsof
能被修复,以便能够处理新的输出格式,并且能够删除这个兼容性 hack。Torvalds 似乎愿意尝试,但他指出,一些用户 (及其发行版) 更新用户空间工具的速度可能非常慢,因此可能要很长时间才能不再需要这个更改。
总而言之:Hyrum's law 再次证明了它的适用性。在类型字段中留零从未被设计为匿名 inode 的 ABI 部分;它只是一个错误,一个工作没有完全完成的产物。但由于这种行为是可见的,代码开始依赖它,而这个错误无法再被修复。这一事件再次暗示,内核接口在发布到内核版本之前可能需要比通常更高的审查级别。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~