LWN:针对特殊文件的扩展属性!
共 3827字,需浏览 8分钟
·
2021-09-30 19:32
关注了就能看到更多这么棒的文章哦~
Extended attributes for special files
By Jonathan Corbet
September 9, 2021
DeepL assisted translation
https://lwn.net/Articles/868505/
Linux 的扩展属性(extended-attribute)机制是用来给文件系统中的文件增加 metadata(元数据)的。这个功能往往很少被使用,尤其是如果没有 SELinux 这类安全模块(security module)的情况下。不过,人们对这些属性的工作机制很感兴趣,这一点可以从 Vivek Goyal 发布的一个 patch 的最新修订版引出的讨论看得出来,该 patch 试图对扩展属性和特殊文件相关的规则做一个看起来很小的变动。
具体来说,扩展属性(通常被称为 "xattrs")都是可以跟文件绑定的一些键值对(name-value pair)。扩展属性的 name 被分为两部分,一部分是指明命名空间(namespace),另一部分是在这个命名空间中的标识符。命名空间目前可以是 security、system、user、或 trusted 中的一个。每个命名空间都有自己特有的一些规则。system 和 trsuted 这两个很少在一般情况下使用。相应地,security 命名空间则在许多 Linux 安全模块中有使用到。security 属性的例子可以简单通过在一个设置好了 SELinux 的系统上运行 getfattr 命令来查看到:
cd /; getfattr -d -m - .
# file: .
security.selinux="system_u:object_r:root_t:s0"
这就是 SELinux 标签(label),用于确定这个目录应该使用哪些访问策略(access policies)。一个进程必须有 CAP_SYS_ADMIN 的 capability 才能修改 security 命名空间的属性。更进一步地来说,系统中正在运行的安全模块可能还不一定同意此进程提出的改动。
user 命名空间完全没有特权。用户可以为他们有权写入的文件随意分配任何他们喜欢的属性。但有一个例外:不可以将 user 扩展属性附加到符号链接或设备文件这种特殊文件上。man 手册中将这个限制的原因解释了一下,是为了控制资源消耗。如果任何可以写入/dev/null 的进程都可以给它设置一个附加扩展属性,那么磁盘很快就会被这些无限多的属性数据填满。有相应权限的进程仍然有可能给这些文件附加 security 扩展属性。
Goyal 的 patch 稍微放宽了一下这个限制。改动后,符号链接或设备特殊文件的 owner 进程就有权给该文件设置 user 扩展属性了。这使得用户可以改变他们所控制的文件,同时又避免了/dev/null 问题。在许多人看来,这似乎是一个合理的改变,但 Andreas Gruenbacher 表示了反对:
user.* xattrs 设计时希望在进行设置的权限方面,它就类比于文件内容。根据这个原则,符号链接和特殊文件不能有 user.* xattrs。这已经是多年来的行为模式了,应用程序可能正按照这些语义来实现,所以我们不能简单地改变这里的行为。
确实需要避免用这种微妙之处的改动来破坏用户空间程序。Goyal 建议可以将新的行为作为可选项来加入,就能避免产生这种意外。但更大的症结在于这个功能预期是如何使用。内核开发者通常会问为什么需要一个新的行为,这些信息在评估所实现的解决方案是否确实是解决问题的最佳方式时是非常必要的。在这个话题中,并非所有的人都对答案感到满意。
Goyal 正在研究虚拟化,特别是研究 guest 想与 host 共享同一个文件系统的用例。内核的 virtiofs 文件系统就是为这种应用场景而设计的,它是一种基于 Virtio 的 FUSE 文件系统,所以它的效果相当不错。在 host 端,virtiofsd 守护进程会真正进行客户端提出的文件系统访问申请。
Virtiofsd 希望能放弃尽可能多的 capability,只保留那些必须要用的 capability,确保能够操作任何用户和组 ID 所拥有的文件。它目前工作的非常好,除了一个小问题:security 扩展属性。guest 可能想在文件系统中操作这些属性,但 host 可能会阻止 virtiofsd 进行这些更改。尤其是如果 host 正在运行像 SELinux 这样的安全模块的话,这个安全模块会对这些属性按自己的判断来进行解释,它很可能不赞同 virtiofsd 所提出的改动。改变这些扩展属性都是需要 CAP_SYS_ADMIN 这个 capability 的,而 virtiofsd 没有这种 capability 却还在进行这种改动。
要解决这个问题,自然的做法是再加一层抽象层。如果配置得当的话,virtiofsd 能够在 guest 和 host 之间将扩展属性进行一下对应转换。例如,它可以把 guest 这里管理的 security 属性都转换成 host 上的 user 属性。virtiofsd 改变 user 属性并不需要任何权限,所以一切都能正常使用。
准确地说,绝大多数情况下都很正常。Goyal 指出,当 guest 进行莫名其妙的 relable (重新标记)状态时(SELinux 似乎时不时地会做这些事),就会产生错误。这里的问题在于设置特殊文件的 user 扩展属性时的限制,guest 正试图重新对某个设备文件设置 label,但 host 不同意将这些 label(已经被重新映射改为 user 扩展属性了)设置到这个特殊文件之上。这个问题就是推动 Goyal 来实现 patch 放宽限制的原因,用了这个 patch 之后,这个使用场景就没有问题了。
Casey Schaufler 声明说,他对给特殊文件分配 user 扩展属性没有问题。但他认为 virtiofsd 中的重映射机制是 "不合理的":
正如我以前所说,这引入了一个安全漏洞。它允许 host 上的非特权进程操纵 guest 的 security 状态。这是个彻底错误的做法。将这个漏洞淡化,认为只有在配置错误的情况下才能被利用,这样是不行的。不要做这个 remapping 机制。
Schaufler 和 Goyal 在这组 patch 的三个修订版中,已经在这个话题上翻来覆去讨论了无数次。Schaufler 认为,处理这种情况的唯一安全的方法是,host 方的更改需要与 guest 方的特权水平要相同。举例来说,将 security 扩展属性重新映射到受信任的命名空间(这也就需要 CAP_SYS_ADMIN 了)是可以接受的。与此同时,Goyal 继续在寻找一个不需要 virtiofsd 拥有额外权限的解决方案。
这个解决方案,最终可能会采取略微有些不同的方式,这个想法灵感来自于 David Alan Gilbert 的这个看法:
我认为真正的问题在于,user/trusted/system/security 的 "命名空间" 是一种随意的比较 hack 的实现方法,而不是一个允许你创建新的(嵌套的)命名空间并将权限与每个命名空间联系起来。
每个命名空间都背负有一些实现上特有的包袱(在 NFS 上不被信任,用户。在符号链接上有特殊的规则等等)。
Miklos Szeredi 建议,下一步(最初是由 Eric Biederman 提出的)可以调整 trusted 扩展属性,让其能在 user 名字空间中使用。如果某个 user 命名空间的拥有者是 user ID 1000,那么此命名空间中的 trusted.foo 将会在此命名空间初始化的时候就被存储成为(并可被读取到)类似 trusted<1000>.foo 这样的内容。Virtiofsd 可以在 user 命名空间中运行,并使用 trusted 扩展属性,而不需要有什么额外权限,host 上的安全模块仍然可以最终决定这些属性应该如何设置。Goyal 同意这种方法可能是可行的。
唯一的问题是,必须要有人来实现 user 命名空间的这个新的行为,这是系统中一个很复杂的部分,搞不好就容易出现 security 错误。Biederman 已经指出了 nested namespace 相关的一个潜在问题。但是,假设这个功能可以最终被安全地提供出来的话,Goyal 的原始问题应该是可以得到解决的。这就是为什么内核开发者经常总是对于某个改动的原始出发点和使用场景更加关注:一个问题的最佳解决方案往往不是所想到的第一个方案。
全文完
LWN 文章遵循 CC BY-SA 4.0 许可协议。
长按下面二维码关注,关注 LWN 深度文章以及开源社区的各种新近言论~