内核角 - SELinux 中的文件系统标签
随着 NSA Security-Enhanced Linux 现在集成到 2.6 内核中并进入发行版,越来越多的人可能会安装 SELinux 并进行实验。 鉴于不断增长的用户群,本文将更详细地介绍 SELinux 下的文件系统标签。 这是一篇中级文章。 尽管下一节提供了对某些 SELinux 概念的简要回顾,但可以在在线资源部分找到指向更详细信息的指针。 特别是,建议将 Faye Coker 的介绍性文章 [LJ, August 2003] 作为起点。
在 SELinux 中,重要的对象(例如任务、inode 和文件)被分配一个安全上下文,这是一个封装与对象关联的安全属性的标签。 在标准 SELinux 下,此标签是以冒号分隔的 ASCII 字符串,由身份、角色和类型的值组成。
这些标签由一个称为安全服务器的内核组件分配,该组件使用加载到安全策略数据库中的规则。 我的工作站上 /etc/shadow 文件的安全上下文标签是
system_u:object_r:shadow_t
其中system_u和object_r是用于文件的通用身份和角色值。 shadow_t 是文件的类型,它是一种确定如何访问文件的属性。 例如,一个进程的标签会像这样
root:staff_r:staff_t
这里的 SELinux 身份是 root,由 SELinux 分配,作为比标准 UNIX 身份更永久的身份形式。 角色是 staff_r,表示该进程具有分配给该角色的所有权限。 分配给进程的类型是 staff_t。 对于进程,type 属性指示允许它如何访问对象并与其他进程交互。 进程的 type 属性通常被称为域。
SELinux 使用这些安全上下文标签在进程和对象之间做出访问控制决策,但这到底是如何发生的? SELinux 在核心内核代码中的战略位置设置了钩子,例如在用户即将读取文件时。 这些钩子允许 SELinux 跳出内核的正常流程,请求扩展的访问控制决策。 访问控制决策通常在进程(例如,cat)和对象(例如,/etc/shadow)之间针对特定权限(读取)做出。
决策请求被发送到访问向量缓存 (AVC),AVC 将请求传递给安全服务器进行解释。 安全服务器查询安全策略数据库并确定一个结果,该结果缓存在 AVC 中并返回给 SELinux 钩子。
然后,SELinux 钩子允许流程继续或返回 EACCES,具体取决于决策结果。 分配给进程和对象的安全上下文标签用于做出这些访问控制决策。
有关此过程的简化视图,请参阅图 1。
以下代码演示了用户在真实系统中看到的安全上下文标签的使用方式
$ id -Z root:staff_r:staff_t $ cat /etc/shadow cat: /etc/shadow: Permission denied
审计日志记录如下
avc: denied { read } for pid=13653 exe=/bin/cat name=shadow dev=hda6 ino=1361441 scontext=root:staff_r:staff_t tcontext=system_u:object_r:shadow_t tclass=file
翻译:带有安全上下文标签的 cat 程序root:staff_r:staff_t被拒绝读取带有标签的文件的权限system_u:object_r:shadow_t.
SELinux 不了解 cat 或 /etc/shadow 的含义。 它只关心它们各自的安全上下文标签、目标对象的类(在本例中,它是一个文件)以及正在请求的权限。
SELinux 设计的一个重要方面是标签封装了对象的所有安全属性,并且它们仅由内核中的安全服务器和用户空间中的 libselinux 解释。 内核代码和用户空间的其余部分只是将标签作为不透明数据传递。 新的安全属性可以添加到标签中,而无需重新编译应用程序或重新设计核心 SELinux 代码。
在典型的基于 Linux 磁盘的文件系统中,每个文件都由一个 inode 唯一标识,该 inode 包含文件的关键元数据,包括 UNIX 所有权和访问控制信息。 当内核引用文件时,其 inode 从磁盘读取到内存中。 标准 UNIX 权限检查仅使用 inode 中存在的信息。 SELinux 扩展了标准 UNIX 安全性,并使用安全上下文标签来做出扩展的访问控制决策。
Linux 实现了扩展属性,也称为 EA 或 xattr。 这些是与文件关联的名称/值对,作为对基于 inode 的常规属性的扩展。 EA 允许以标准化的方式将功能添加到文件系统中,以便属性的接口与文件系统无关。 EA 功能的示例包括访问控制列表 (ACL)、与文件数据一起存储的字符集元数据和 SELinux 安全上下文标签。
EA 存储在命名空间中,允许单独管理不同类的 EA。 ACL 存储在 system.posix_acl_access 和 system.posix_acl_default 命名空间中。 SELinux 安全上下文标签存储在 security.selinux 命名空间中。 有关 Linux 下 EA 的更多信息,请参阅 attr(5)。
可以使用 getfattr(1) 和 setfattr(1) 实用程序手动管理 EA。 例如,要查看文件的 SELinux 安全上下文标签
$ getfattr -n security.selinux /tmp/foo getfattr: Removing leading '/' from absolute path names # file: tmp/foo security.selinux="root:object_r:sysadm_tmp_t\000"
注意 EA 安全命名空间的规范。 提供了一个名为 getfilecon(1) 的包装实用程序,用于 SELinux。 它可以避免您指定 EA 命名空间,并且它具有更清晰的输出。
基于文本的标签的使用确保了有意义的、人类可读的安全属性与文件数据一起存储。 如果文件系统安装在不同的系统上,则可以保留或翻译这些标签,这可能会使用不同的安全策略。 一个反例是将文件的所有者存储为文件 inode 中的数字 UID 的方式。 UID 通常通过 /etc/passwd 映射到一个有意义的值; 它在不同的系统上可能没有相同的含义。
为了使文件系统支持 SELinux 安全上下文标签,它需要 EA 支持和一个用于 EA 安全命名空间的处理程序。 目前,此类文件系统包括 ext3、ext2、XFS 和 ReiserFS; 后者使用外部补丁。 此外,devpts 文件系统有一个虚拟安全处理程序,允许基于 EA 访问 ptys 的内核标签。
那么,文件何时被标记? 在 SELinux 系统安装期间,通常使用 setfiles(8) 实用程序来标记支持 EA 安全标签的文件系统中的所有文件。 包管理工具(如 RPM)也可能在安装期间标记文件,而系统管理员通常需要使用 chcon(1) 或 setfilecon(1) 手动设置安全上下文。
SELinux 文件系统标签的演变
2000 年 SELinux 的第一个版本使用了一种不同于本文讨论的扩展属性方法的文件系统标签机制。 持久安全 ID (PSID)(安全上下文标签的整数表示)存储在 ext2 inode 的未使用字段中。 每个文件系统上的映射文件由 SELinux 用来通过 inode 查找文件的 PSID,然后将 PSID 映射到安全上下文标签。
这种方法的缺点是需要单独修改每个文件系统才能支持 PSID。 因此,对于上游内核中的扩展安全性来说,这不是一个好的通用解决方案。
通过 LSM 项目,为 Linux 内核实现了一个通用的访问控制框架。 由于 LSM 中未使用任何特定于文件系统的钩子,因此 SELinux 放弃了修改后的文件系统方法,并将 PSID 存储在映射文件旁边的普通文件中。 这使得 SELinux 可以纯粹用作 LSM 应用程序,而无需内核修补。 它还允许标记适用于更多文件系统,但在性能和一致性方面并不理想。 从内核内部访问文件仍然存在普遍问题。
作为将 SELinux 合并到主线内核的过程的一部分,在获得更多社区反馈后,SELinux 转向了当前基于扩展属性的文件系统标签模型。 扩展属性为应用程序提供了一个标准 API,从而消除了使用自定义系统调用来操作安全标签的需要,同时文件系统也可以通过 EA 命名空间提供的分离来被其他安全模块以类似的方式使用,即使在同一文件系统上也是如此。
创建文件时,安全策略中的匹配规则通常描述如何根据父目录和当前任务的安全上下文分配标签。 这是一个例子
$ id -Z root:staff_r:staff_t $ ls -dZ /tmp drwxrwxrwt+ root root system_u:object_r:tmp_t /tmp $ touch /tmp/hello $ getfilecon /tmp/hello /tmp/hello root:object_r:staff_tmp_t
在这种情况下,安全策略包含一条规则,该规则声明由 staff_t 在标记为 tmp_t 的目录中创建的文件必须标记为 staff_tmp_t 类型。 如果没有显式规则,则文件将标记为父目录的上下文。
特权应用程序可以通过将安全上下文写入 /proc/self/attr/fscreate 来覆盖上述规则。 然后,此安全上下文用于标记任何新创建的文件。 setfscreatecon(3) 库函数封装了此操作。
如果文件系统在使用前未正确标记,或者在未启用 SELinux 的情况下在文件系统上创建文件,则可能存在未标记的文件。 在后一种情况下,SELinux 内核在内部为 AVC 调用分配一个默认上下文给未标记的文件,但它不会尝试在磁盘上重新标记它们。 要手动恢复安全上下文标签,请使用 restorecon(8)。
正在开发一个类似 fsck 的实用程序,用于管理已创建未标记文件的情况。 为了在启动时运行,此实用程序将确保所有文件在系统进入多用户模式之前都已正确标记。
在前一节中,我们讨论了既支持磁盘上的 EA 又具有 EA 安全命名空间处理程序的文件系统的文件标签。 当正常安装此类文件系统时,据说它使用 xattr 标签行为。
当文件系统由 SELinux 初始化时,例如在安装时,会生成一条日志消息,内容为
SELinux: initialized (dev hda6, type ext3), uses xattr
这个uses xattr子句表示文件系统使用上述 xattr 标签行为。
许多文件系统不支持扩展属性 (EA),即使支持,也并非所有都有安全命名空间处理程序。对于磁盘文件系统,可能是因为还没有人完成相关的编码工作,或者扩展属性对于像 vfat 这样的传统文件系统来说根本没有意义。
Linux 下已经发展出大量的伪文件系统。文件系统正成为越来越受欢迎的用户-内核 API 机制。其中最明显的是 procfs,它是用户空间和各种内核组件之间的接口。由于 procfs 的历史悠久,它积累了大量的冗余代码,因此鼓励新的用户-内核文件系统 API 通过单独的文件系统来实现。这些文件系统驻留在内核中,并且没有内在的扩展属性支持。示例包括 usbfs、sysfs 和 selinuxfs。
对于这些不支持扩展属性的情况,根据每个文件系统类型的安全策略规则,使用各种标签行为进行管理。
过渡 SID 标签行为用于 devpts、tmpfs 和 shmfs 文件系统。这些文件系统中的文件在内核中按需标记,基于当前任务的安全上下文和策略中为文件系统指定的安全上下文。
devpts 是一个特殊的过渡 SID 文件系统。它通过一个虚拟的 EA 安全处理程序提供对 ptys 的 EA API 访问。特权应用程序(例如 sshd)使用此功能来重新标记 ptys,覆盖过渡 SID 标签。
任务 SID 标签行为只是使用与当前任务相同的安全上下文来标记文件。它用于在 pipefs 和 sockfs 文件系统中分别创建的管道和套接字。
genfs_contexts 标签行为用于不适合 xattr、过渡 SID 和任务 SID 标签的文件系统。在安全策略中,安全上下文标签被分配给文件系统/路径名对。路径名组件的目的是允许对文件系统进行更细粒度的标签管理。此功能对于 procfs 尤其重要,因为它包含了可读和可写的内核数据,包括 sysctl 接口。
大多数不支持 EA 的文件系统都使用 genfs_contexts 标签,通常将整个文件系统设置为单个安全上下文。常见的例子包括 sysfs、vfat、nfs 和 usbdevfs。
2.6.3 内核包含的一个新特性是挂载点标签,也称为上下文挂载。其主要目的是允许使用挂载选项指定整个文件系统的安全上下文。挂载点标签可以应用于任何类型的文件系统,并且会覆盖其正常的标签行为。
挂载点标签的一个具体用途是允许在挂载时分别标记不同的 NFS 挂载。它也适用于临时挂载不支持 EA 安全标签的文件系统,以及挂载在其他地方标记的具有 EA 标签的文件系统。后者在取证工作中可能很重要。
没有标签的传统文件系统也可能需要在启用 SELinux 的操作系统下挂载。即使文件系统类型支持 EA 安全标签,我们可能也不想将持久的安全上下文标签添加到这些文件系统。挂载点标签允许我们分配未写入磁盘的内核驻留标签。
由于挂载点标签是一个新特性,并且没有广泛的文档记录,让我们更详细地讨论它。
在内核中启用 SELinux 后,为挂载点标签提供了三个新的挂载选项
context:导致文件系统上的每个文件以及文件系统本身都使用指定的安全上下文进行标记。上述讨论的 /proc/self/attr/fscreate API 被该文件系统忽略。这会覆盖现有的标签行为,将其更改为挂载点标签。使用此选项时,用户对文件系统标签是只读的,但策略指定的标签转换仍然在具有 EA 安全标签支持的文件系统上运行。
fscontext:将聚合文件系统(即文件系统本身)的标签设置为指定的安全上下文。这允许对文件系统进行更细粒度的控制,允许它们的标签在每个挂载的基础上设置,而不是在策略中指定的每个文件系统类型的基础上设置。由于 context 选项也实现了此功能,因此这两个选项不能一起使用。此选项仅适用于具有 EA 安全标签支持的文件系统。聚合文件系统安全上下文用于在特定文件系统内创建文件、挂载和卸载文件系统、访问文件系统属性以及重新标记文件系统本身期间做出的访问控制决策。
defcontext:为未标记的文件设置默认安全上下文,而不是策略中指定的值。与 fscontext 选项一样,它仅适用于具有 EA 标签支持的文件系统,并且如果已指定 context,则无效,因为它也实现了此功能。
在内核中,SELinux 在 mount(2) 期间解析并剥离安全挂载选项,并将正常选项传递给特定于文件系统的代码。正常的文件系统不需要知道安全选项,因此,它们不需要被修改。这是可能的,因为大多数文件系统使用文本名称/值对作为挂载选项,SELinux 可以轻松地操作它们。
具有二进制挂载选项数据的文件系统,包括 NFS、SMBFS、AFS 和 Coda,需要作为特殊情况处理。在这些文件系统中,只有 NFSv3 在 SELinux 开发的这个阶段得到支持。
这是一个 context 选项如何运行的示例,因为它可能是三个挂载选项中最常用的。一张带有日志文件的软盘已到达我们的办公桌,我们想将它挂载到我们的 SELinux 机器上,并对其运行一些日志分析软件。由于策略的配置方式,这些文件需要标记为 system_u:object_r:var_log_t,以便日志分析软件能够正常工作。以这种方式挂载还可以帮助为软盘上的数据提供一个沙箱,允许 SELinux 保护操作系统和软盘的内容免受彼此的影响。
让我们挂载磁盘
$ mount -v -t vfat \ -o context=system_u:object_r:var_log_t \ /dev/fd0 /mnt/floppy /dev/fd0 on /mnt/floppy type vfat (context=system_u:object_r:var_log_t)
审计日志说了什么?
SELinux: initialized (dev fd0, type vfat), uses mountpoint labeling
这条消息看起来很有希望。接下来,我们验证磁盘上的文件是否按预期标记。通常,您会使用 getfilecon(1),但 getfattr(1) 具有更明确的错误消息
$ getfattr -n security.selinux /mnt/floppy/access_log /mnt/floppy/access_log: security.selinux: Operation not supported
这里发生了什么?一个ls -Z也显示该文件具有空安全上下文
$ ls -Z /mnt/floppy/access_log -rwxr-xr-x+ root root (null) /mnt/floppy/access_log
软盘上的 vfat 文件系统没有 EA 支持,并且其安全上下文标签纯粹发生在内核中。事实证明,这种内核内标签工作正常,但用户空间工具无法在 EA API 中查看标签。这是当前 EA 实现的一个限制,尚未得到优雅地解决。
但是,有一种偷偷摸摸的方法可以通过使用审计日志来查看文件上的标签,审计日志总是在记录访问消息时记录目标对象的安全上下文。
使用 getfattr(1) 会生成以下审计记录
avc: denied { getattr } for pid=12354 exe=/usr/bin/getfattr path=/mnt/floppy/access_log dev=fd0 ino=132 scontext=root:staff_r:staff_t tcontext=system_u:object_r:var_log_t tclass=file
因此,该文件按照传递给 mount 命令的 context 挂载选项正确标记 (system_u:object_r:var_log_t)。
虽然可以将安全上下文标签分配给 NFS 挂载的文件系统,但它们仅在内核中本地运行,以进行访问控制决策。没有标签通过网络与文件一起传输。这方面的工作一直在推进,对 NFSv2/v3 协议和代码进行了特定于 SELinux 的修改。更进一步,预计 NFSv4 的集成将涉及通过命名属性(属于更具可扩展性的 NFSv4 规范的一部分)在线进行标签。这将允许 NFS 客户端和服务器都为联网文件实现 SELinux 安全性。对其他联网文件系统的支持也会很有用,与 Trusted BSD 的 SELinux 端口的互操作性也是如此。
备份和恢复
使用 SELinux 的系统管理员需要更改的众多任务之一是备份和恢复。创建归档时,如何在归档中保留安全上下文标签?答案是使用高度灵活的 star(1) 实用程序,它具有扩展属性支持。
要操作带有安全上下文标签的归档,请使用 xattr 选项。创建归档时,您还需要指定 exustar 格式。例如
$ star -xattr -H=exustar -c -f cups-log.star /var/log/cups
创建一个 /var/log/cups 目录的归档,保留文件上的安全上下文标签。
要提取,只需使用 xattr 选项
$ star -xattr -x -f cups-log.star $ ls -Z var/log/cups/ -rw-r--r--+ root sys system_u:object_r:cupsd_log_t error_log -rw-r--r--+ root sys system_u:object_r:cupsd_log_t error_log.1
正如您所看到的,安全上下文标签已被保留。
本文的资源: /article/7689。
James Morris (jmorris@redhat.com) 是来自澳大利亚悉尼的内核黑客,目前在波士顿为 Red Hat 工作。他是 SELinux、Networking 和 Crypto API 的内核维护者;LSM 开发人员和 Netfilter Core Team 的荣誉成员。