SELinux 安全性:精确控制您的 Linux 系统

最后更新: 五月27 ,2026
  • SELinux 通过标签和策略为 Linux 内核添加了强制性访问控制,超越了传统的 DAC 权限。
  • 安全上下文(用户、角色、类型、级别)和基于类型的策略可以对进程、文件和端口进行非常精细的访问控制。
  • getenforce、chcon、semanage、semodule 和 booleans 等工具有助于在生产环境中对 SELinux 进行实际管理。
  • 正确配置后,SELinux 可以通过严格限制每个服务或应用程序可以执行的操作来缓解零日漏洞和错误配置。

Linux 系统中的 SELinux 安全性

SELinux 听起来像是内核极客的专属技术,但实际上它是当今 Linux 系统中最强大的安全工具之一。如果您管理服务器、Docker 容器安全、云基础设施,甚至是略微敏感的桌面计算机,那么了解 SELinux 的工作原理至关重要,它能让您打造的系统从“配置良好”跃升至即使面对零日漏洞也难以攻破的境地。

尽管 SELinux 素以“复杂”著称,但它提供了一个非常合乎逻辑的模型:它定义了每个进程可以执行的操作以及可以与之通信的对象,如果任何操作偏离了这些规则,内核会立即停止它。SELinux 并非盲目地信任 root 用户的行为或守护进程不会出现漏洞,而是使用非常详细的标签和策略,强制执行对超级用户也适用的访问控制。

什么是 SELinux?它解决了什么问题?

安全增强型 Linux (SELinux) 是一个基于 LSM(Linux 安全模块)的 Linux 内核安全模块。它最初由美国国家安全局 (NSA) 与 Red Hat 及其他合作伙伴共同开发,自内核 2.6 版本起,它已成为内核的正式组成部分。SELinux 并非独立应用程序,而是一个内核扩展,它添加了强制访问控制 (MAC) 系统和基于角色的访问控制 (RBAC)。

与经典的 Unix 自主访问控制 (DAC)(所有者、组、其他用户和读写执行权限)不同,SELinux 中的访问决策并非基于文件所有者的选择,而是基于安全管理员设定的全局策略。DAC 仍然存在,并且具有优先权:如果 DAC 拒绝访问,SELinux 不会干预;但即使 DAC 允许访问,SELinux 仍然可以根据其策略阻止该操作。

SELinux架构清晰地分离了各个组件:一方面是负责安全决策的内核代码,另一方面是定义允许和禁止操作的策略模块。这种分离使得无需重新编译内核即可调整规则,并减少了可能影响系统安全的组件数量。

SELinux 已被 Fedora、Red Hat Enterprise Linux、CentOS 和 Scientific Linux 等发行版默认采用,并且深度集成到 Android 等系统中,用于将系统进程和应用程序限制在非常特定的域内。在 BSD 和 GNU/Linux 世界中,存在 AppArmor、TOMOYO 和 TrustedBSD(macOS/FreeBSD 上)等替代方案,但 SELinux 的优势在于它能够对所有系统对象提供极其精细的控制。

从DAC到MAC:为什么传统模式已不再适用

在传统的Unix系统中,域对象模型(Domain-Object model)通过DAC进行管理:每个文件或资源都有一个所有者和权限,任何以该用户身份运行的进程都可以对这些资源执行任何操作。这意味着,如果一个守护进程以root权限运行,任何可利用的漏洞都可能使其利用root权限控制系统的一半。

典型的例子包括:某些数据库的数据文件本应只能通过数据库管理系统 (DBMS) 进行操作,但实际上却可以被具有 root 用户 ID 的进程读取和修改;或者某些关键守护进程以过高的权限运行。程序错误、缓冲区溢出或输入验证不完善都可能使该服务成为通往整个系统的入口。

SELinux 在 DAC 之上添加了强制访问控制 (MAC)层。“强制”意味着访问控制由管理员通过策略集中定义,用户和进程都不能自行放宽这些规则。操作系统通过在允许任何相关内核操作之前对其进行评估来强制执行这些策略。

内核使用 LSM 钩子,在每次敏感系统调用(例如打开文件、创建套接字、挂载文件系统、通过进程间通信等)时查询 SELinux。在每个决策点,SELinux 会根据已加载的策略以及主体和客体的安全上下文来评估操作。如果策略没有明确授予权限,则无论进程是否具有 root 权限,该操作都会被拒绝。

运行模式:强制模式、允许模式和禁用模式

SELinux 可以以三种截然不同的运行状态运行,了解这些状态对于避免在生产环境中出现异常至关重要:

  • 强制执行SELinux 已启用并完全强制执行策略。所有规则不允许的操作都将被阻止并记录日志。
  • 允许的SELinux 已激活,加载策略并为文件系统添加标签,但是 不阻止 它只会将交易记录为被拒绝的交易。这非常便于调试和调整策略。
  • 残疾人SELinux 已禁用。未应用任何策略,也未执行任何标记操作。系统采用经典的 DAC 模型。
  如何解锁笔记本电脑上的 BIOS 密码

要快速临时切换强制模式和宽松模式,可以使用`setenforce`命令,其中模式值指定为 0(宽松模式)或 1(强制模式)。需要注意的是,此更改是临时性的:下次重启后,模式将恢复为配置中定义的模式。

如果需要永久性更改,则需要编辑文件。 /etc/selinux/配置 (或某些发行版中的 /etc/sysconfig/selinux)并调整该指令的值 SELINUX=disabled|permissive|enforcing这些更改将在下次启动时应用,并且在许多情况下,将涉及重新标记文件系统。

要检查 SELinux 的活动模式,可以使用getenforce或sestatus等命令。前者仅返回 Enforcing、Permissive 或 Disabled;后者提供更完整的 SELinux 状态、已加载策略和活动模块的摘要信息。

安全上下文和标签系统

SELinux 的核心是其安全标签或上下文系统。每个文件、进程、网络端口、套接字、设备等都关联着一个上下文,用于描述其使用方式。该上下文由多个字段组成,这些字段共同构成了 SELinux 对该对象的理解。

上下文的一般格式为user_u:role_r:type_t:level,具体格式会根据策略有所不同(尤其是在使用 MLS/MCS 时)。每个字段都有其特定用途:SELinux 用户、角色、类型(指进程时也称为域)以及敏感级别或类别。

实际上,最关键的要素是类型(第三个字段),因为绝大多数策略规则都是以类型之间的关系形式构建的。例如,允许类型为 httpd_t 的进程访问标记为 httpd_sys_content_t 的文件,或者允许特定域与标记为 http_port_t 的套接字通信。

这些上下文以如下方式存储: 扩展文件系统属性因此,使用支持扩展属性(xattrs)的文件系统(例如 ext4、XFS 等)至关重要。对于进程而言,当前上下文和其他相关上下文通过伪文件系统暴露出来。 /proc/<pid>/attr/ 在 current、exec、fscreate、prev、sockcreate 或 keycreate 等文件中。

在具有针对性政策的系统中,典型的应用场景示例包括:

  • system_u:object_r:httpd_sys_content_t:s0 适用于由 Apache 或 Nginx 提供的 Web 内容。
  • system_u:object_r:home_user_t:s0 用于用户主目录。
  • system_u:system_r:httpd_t:s0 针对 Web 服务器本身的执行域。

分解 SELinux 上下文的组成部分

当您遇到像unconfined_u:unconfined_r:unconfined_t:s0-s0:c0.c1023这样的上下文时,它可能看起来像象形文字,但每一部分都对应于 SELinux 及其参考策略中的一个特定概念。

El SELinux 用户 (按惯例加后缀) _u这与 /etc/passwd 中的 Unix 用户不同。SELinux 维护着自己的用户数据库,并将其映射到 Linux 用户。一个 SELinux 用户可以包含多个 Unix 用户,因为其设计理念是使 MAC 层独立于 DAC。

El SELinux 角色 (带后缀 _r这定义了用户或域可以采用哪些角色。如果严格按照此规则使用,则称为完全基于角色的访问控制 (RBAC)。大多数文件对象使用 object_r 角色,而 system_r、user_r、staff_r 或 sysadm_r 等角色则根据进程必须承担的安全上下文应用于进程。

El SELinux 类型或域 (后缀 _t实际上,类型是关键要素。类型描述了对象的类别或进程的执行域。策略则规定了类型之间允许哪些交互:哪些域可以读取、写入、执行或与其他类型的对象通信。

当启用多级安全(MLS) 或多类别安全 (MCS) 策略时,会使用级别和类别。敏感度是分层的(例如,s0、s1 等),而类别则不是分层的(c0、c1、c2 等)。在高度关键的环境中(例如,某些政府机构),它们用于确保数据只能向下读取,并且只能写入到同一级别或更高级别,并根据非常具体的隔离区对数据进行隔离。

SELinux策略:目标性、严格性、MLS/MCS和模块化

SELinux 的安全机制取决于加载的策略。策略本质上是一组规则,用于描述哪些域可以对哪些类型的数据执行哪些操作,以及其他元素(例如转换规则、标签规则等)。发行版通常会打包标准策略,因此您无需从头开始编写所有内容。

最常见的策略称为目标策略。在这种模式下,只有特定的进程(主要是网络服务和高风险守护进程,例如 Apache、Nginx、DNS、代理、SNMP、syslog 等)在受限域中运行。所有其他用户进程都在“非受限”域中运行,这些域基本上应用标准的 Linux 安全机制,并记录某些操作。

还有一种严格的策略,几乎所有流程都受到特定策略的约束。这种策略安全性更高,但如果模型理解不透彻,维护起来也会困难得多,因为标签或规则中的任何差异都可能扰乱标准工作流程。

对于高安全环境,存在多层/多类别安全 (MLS/MCS)策略,该策略利用敏感性和类别来实施更精细的控制。这些策略通常用于非常严格的军事或行政环境,由于其操作复杂性高,很少在特定情况之外使用。

现代策略采用模块化方式分发。与使用单一的整体式策略文件不同,针对特定服务使用独立的模块,从而大大简化了管理和更新。这些模块通过诸如semodule和semanage module之类的工具进行管理,允许您安装、移除、启用或禁用策略的某些部分,而无需每次都重新编译整个策略。

  如何在Linux系统中监控和管理CPU、GPU和RAM的使用情况

SELinux 如何决定:主体、对象、类和权限

当一个进程(主体)尝试访问一个资源(对象)时,SELinux 会提出这样一个概念性问题:“类型为 X 的域能否对属于 C 类的类型为 Z 的对象执行操作 Y?”。然后,SELinux 会通过策略中定义的规则来寻找答案。

在大多数发行版和 Android 使用的“类型强制 (TE)”策略中,每个对象都属于一个类(文件、目录、fifo_file、tcp_socket、进程等),该策略定义了每个类可以拥有的权限:读取、写入、执行、绑定、连接、获取属性、打开等等。

TE 规则的表达非常直接。一个简单的例子是:

允许 httpd_t http_port_t:tcp_socket name_bind;

根据这条规则,策略表明 httpd_t 域中的进程可以对标记为 http_port_t 的 TCP 套接字执行 name_bind 操作。这种方法侧重于对象类型和类,而不是具体路径,从而避免在移动文件或更改目录结构时出现意外情况。

例如,在 Android 系统中,SELinux 属性用于将类型分组到更通用的标签(例如`appdomain`)下,这样一条规则就可以应用于多个域(例如 `untrusted_app`、`isolated_app` 等),而无需重复定义。此外,像 `rw_file_perms` 这样的宏也用于对一些常见的文件权限进行分组,从而减少因疏忽而导致的错误。

内部状态、AVC 和拒绝登记

当发生访问请求时,SELinux 首先会查询访问向量缓存 (AVC),该缓存存储最近的访问决策以加快处理速度。如果缓存中已有决策,则直接使用;否则,会查询防火墙(SELinux 在内核中的内部组件),防火墙会根据策略以及主体和客体上下文来评估操作。

如果没有明确允许所请求操作的规则,则默认拒绝。这种“默认拒绝”的理念是 SELinux 的核心支柱之一,也是它能够有效抵御宽松配置错误的关键所在。

当强制模式下发生拒绝操作时,内核会记录一条类型为“ avc:被拒绝 在系统日志中。根据发行版的不同,它可能出现在…… /var/log/audit/audit.log在 /var/log/messages 或者被 auditd 守护进程捕获。这些消息包括进程上下文(scontext)、对象上下文(tcontext)、类、请求的操作以及其他对调试非常有用的数据。

在宽松模式下,操作被允许,但仍会生成事件 avc: denied,并标记为 permissive=1。这对于构建和调整策略来说非常宝贵,因为它允许您在不中断正常运行的情况下,了解如果强制执行哪些操作会导致系统崩溃。

将 SELinux 集成到发行版和 Android 系统中

在 Linux 服务器和桌面生态系统中,SELinux 默认启用。 Fedora、RHEL、CentOS 及其衍生版本Debian 和 Ubuntu 的内核和软件包都提供了完整的支持,但激活通常是可选的,需要安装诸如 selinux-basics、selinux-policy-default 和 auditd 之类的软件包,然后进行全局重新标记。 fixfiles relabel.

Android 最初在 4.3 版本中以宽松模式集成了 SELinux,在 4.4 版本中过渡到部分使用(仅用于 installd、netd、vold 和 zygote 等关键域),并从 Android 5.0 开始完全集成。Android 的策略侧重于使用类型和属性隔离应用程序、系统服务和敏感进程,旨在最大限度地减少任何组件遭到入侵的影响。

Android 使用诸如 untrusted_app 类型(用于区分普通应用程序进程)、appdomain 属性(用于对应用程序域进行分组)以及 MLS/MCS 类别(用于隔离应用程序之间以及物理用户之间的数据)等概念。所有这些机制协同工作,即使被入侵的应用程序获得了非常广泛的用户权限,也能防止其逃出沙箱。

重要提示:Android 简化了 SELinux 模型,忽略了用户、角色和高级敏感度设置。它只有一个 SELinux 用户 (u)、两个基本角色(r 代表主体,object_r 代表对象),并且敏感度始终为 s0。数据隔离的关键在于类别设置。

与 AppArmor 和其他 LSM 的比较

在许多讨论中,SELinux 和 AppArmor之间的比较不可避免地会出现,因为它们都是 Linux 安全模块,并且都提供 MAC(监控、授权和检查)。然而,它们的实现方式截然不同,在为您的环境选择其中一种之前,了解这一点非常重要。

SELinux 定义了一种以对象及其类型为中心的策略:系统中的每个对象(文件、进程、套接字、端口、设备、进程间通信等)都被分配一个标签。访问决策基于主体和客体上下文,而无需依赖确切的文件路径。这使得系统在面对目录结构变化或替代文件系统视图(chroot、容器、绑定挂载等)时更加稳定。

另一方面,AppArmor 采用的是以任务为中心、基于路径的策略。它为每个程序定义配置文件,指定程序可以访问哪些文件路径、端口等,以及拥有哪些权限。AppArmor 配置起来更直观,对于不想成为 SELinux 专家的管理员来说也更友好,但它的控制粒度稍低,并且更依赖于文件系统结构。

  如何判断你的路由器是否存在 WPSplinter 漏洞

两者都遵循默认拒绝的原则,但实现方式不同:AppArmor 默认只拒绝其配置文件覆盖的任务,而 SELinux 在严格模式下会将拒绝范围扩大到整个系统和所有已标记的对象。因此,SELinux 通常提供更深层次的限制,但代价是策略更加广泛和复杂。

用于管理 SELinux 的实用工具

使用 SELinux 依赖于一系列命令行工具,这些工具简化了模式、标签、布尔值和策略模块的管理。虽然乍一看工具繁多,但几个实用程序就能满足大多数日常任务的需求。

要查看文件和进程的安全上下文,您可以使用该选项。 -Z 在诸如 ls、ps 或 id 等常用命令中。例如: ls -Z 除了 DAC 权限外,它还会显示每个文件的 SELinux 上下文,让您可以快速检查标记是否符合预期。

`chcon`(“更改上下文”)命令允许您手动修改文件的整个上下文,或仅修改特定部分(角色、类型、范围),可以使用 `-r`、`-to` 和 `-l` 等选项。它适用于一次性更正,但请务必记住,如果使用 `restorecon` 或 `fixfiles` 等工具根据策略重新应用标签,则您的更改可能会丢失。

semanage工具堪称运行时策略管理的瑞士军刀。通过各种子命令,您可以管理持久文件上下文 (fcontext)、Linux 和 SELinux 用户之间的登录映射 (login)、SELinux 用户及其角色 (user)、标记端口 (port)、布尔值,甚至策略模块。所有这些操作都无需从源代码重新编译整个策略。

要检查和更改布尔值(策略中用于启用或禁用规则块的小开关)的状态,除了`setsebool` 布尔值本身之外,还需要使用`getsebool`和`setsebool`函数。一个典型的布尔值是 `httpd_enable_homedirs`,启用后,它允许 Web 服务器访问用户的主目录(例如 `~user/public_html/`)。

最后,像fixfiles这样的命令允许您根据定义的规则强制对文件系统进行完全重新标记,而semodule 则负责安装、列出、启用或禁用由参考策略或管理员打包和分发的策略模块 (.pp)。

创建和调整自定义策略

当应用程序没有自己的 SELinux 模块,或者你需要更具体的限制时,就该着手创建自定义策略了。这听起来可能很复杂,但只要仔细遵循特定步骤,整个工作流程其实相当清晰。

第一步是确保相关对象(可执行文件、数据目录、套接字等)都已标记了正确的类型。这可以通过使用 ` semanage fcontext`定义文件上下文规则,并使用 `restorecon` 应用这些规则来实现,同时使用正则表达式来涵盖整个目录树。

然后,系统通常会针对该机器(或在某些情况下,针对特定域)启用宽容模式,应用程序可以正常运行,同时 SELinux 会记录所有可能发生的` avc: denied` 语句。这些日志通常使用audit2allow等工具进行分析,用于提取候选规则。

每个应用程序的引用策略通常以三个文件的形式组织:一个包含 TE 规则(允许、类型、域类型等)的 .te 文件,一个包含文件上下文规则的 .fc 文件,以及一个包含其他模块可以重用的公共接口的 .if 文件。所有这些都使用 make 编译成 .pp 模块,并使用 semodule 加载。

切勿盲目信任 audit2allow 的所有建议:它往往过于宽松。理想情况下,您应该手动审核建议的规则,在适当情况下创建新类型以区分敏感数据和无关数据,并且,如果被拒绝的操作并非至关重要,请考虑使用 dontaudit 规则来停止记录不必要的数据,而无需授予权限。

在 SUSE Linux Micro 或 Android 等环境中,提供了额外的工具(例如,Udica,用于从 JSON 描述生成容器策略),这些工具可以自动执行部分流程,快速将策略调整到特定容器,而无需从头开始学习整个策略语言。

SELinux 的整个生态系统,包括上下文、模块化策略、布尔值和管理工具,使其成为一个极其强大且灵活的安全平台。只需投入一些初始学习时间,即可非常精确地限制每个服务或应用程序的权限,从而大幅增强系统抵御漏洞利用、恶意软件和人为错误的攻击面。

Linux 加固 SELinux
相关文章:
使用 SELinux 加固 Linux:完整实用指南