第 10 章 使用 SELinux
10.1. SELinux 入门
SELinux(Security Enhanced Linux)提供了一个额外的系统安全层。SELinux 从根本上回答问题:<subject> do <action> to <object>?,例如:Web 服务器是否可以访问用户主目录中的文件?
10.1.1. SELinux 简介
系统管理员一般无法通过基于用户、组群和其它权限(称为 Discretionary Access Control,DAC)的标准访问策略生成全面、精细的安全策略。例如,限制特定应用程序只能查看日志文件,而同时允许其他应用程序在日志文件中添加新数据。
Security Enhanced Linux(SELinux)实施强制访问控制(MAC)。每个进程和系统资源都有一个特殊的安全性标签,称为 SELinux 上下文(context)。SELinux 上下文有时被称为 SELinux 标签,它是一个提取系统级别细节并专注于实体的安全属性的标识符。这不仅提供了在 SELinux 策略中引用对象的一个一致方法,而且消除了在其他身份识别系统中可能存在的模糊性。例如,某个文件可以在使用绑定挂载的系统中有多个有效的路径名称。
SELinux 策略在一系列规则中使用这些上下文,它们定义进程如何相互交互以及与各种系统资源进行交互。默认情况下,策略不允许任何交互,除非规则明确授予了相应的权限。
请记住,对 SELinux 策略规则的检查是在 DAC 规则后进行的。如果 DAC 规则已拒绝了访问,则不会使用 SELinux 策略规则。这意味着,如果传统的 DAC 规则已阻止了访问,则不会在 SELinux 中记录拒绝信息。
SELinux 上下文包括以下字段: user(用户)、role(角色)、type(类型)和 security level(安全级别)。在 SELinux 策略中,SELinux 类型信息可能是最重要的。这是因为,最常用的、用于定义允许在进程和系统资源间进行的交互的策略规则会使用 SELinux 类型而不是 SELinux 的完整上下文。SELinux 类型以 _t
结尾.例如,Web 服务器的类型名称是 httpd_t
。通常位于 /var/www/html/
中的文件和目录的类型上下文是 httpd_sys_content_t
。通常位于 /tmp 和
/var/tmp/
中的文件和目录的类型上下文是tmp_t
。Web 服务器端口的类型上下文是 http_port_t
。
有一个策略规则允许 Apache(作为 httpd_t
运行的 Web 服务器进程)访问 /var/www/html/
和其他 Web 服务器目录(httpd_sys_content_t
)中通常找到的文件和目录。策略中没有针对通常位于 /tmp 和
中的文件的允许规则,因此不允许访问。有了 SELinux,即使 Apache 被破坏并且恶意的脚本可以访问,它仍然无法访问 /var/tmp
//tmp
目录。
图 10.1. 通过 SELinux 以安全的方式运行 Apache 和 MariaDB 的示例。
如上例所示,SELinux 允许以 httpd_t
身份运行的 Apache 进程访问 /var/www/html/
目录,并且拒绝同一进程访问 /data/mysql/
目录,因为 httpd_t 和
类型上下文没有允许规则。另一方面,作为 mysqld_db_t
mysqld_t
运行的 MariaDB 进程能够访问 /data/mysql/
目录,SELinux 也正确拒绝类型为 mysqld_t 的进程,以访问标记为
的 httpd_
sys_content_t/var/www/html/
目录。
其它资源
-
selinux(8)man
page 和apropos selinux
命令列出的 man page. -
安装
selinux-policy-doc
软件包时,man -k _selinux 命令列出的 man
page。 - The SELinux Coloring Book 可帮助您更好地了解 SELinux 基本概念。。
- SELinux Wiki FAQ
10.1.2. 运行 SELinux 的好处
SELinux 提供以下优点:
- 所有进程和文件都被标记。SELinux 策略规则定义了进程如何与文件交互,以及进程如何相互交互。只有存在明确允许的 SELinux 策略规则时,才能允许访问。
- SELinux 提供精细的访问控制。传统的 UNIX 通过用户的授权、基于 Linux 的用户和组进行控制。而 SELinux 的访问控制基于所有可用信息,如 SELinux 用户、角色、类型以及可选的安全级别。
- SELinux 策略由系统管理员进行定义,并在系统范围内强制执行。
- SELinux 可以缓解权限升级攻击。进程在域中运行,因此是相互分离的。SELinux 策略规则定义了如何处理访问文件和其它进程。如果某个进程被破坏,攻击者只能访问该进程的正常功能,而且只能访问已被配置为可以被该进程访问的文件。例如:如果 Apache HTTP 服务器被破坏,攻击者无法使用该进程读取用户主目录中的文件,除非添加或者配置了特定的 SELinux 策略规则允许这类访问。
- SELinux 可以强制实施数据保密性和完整性,并可以防止进程不受不受信任的输入的影响。
SELinux 旨在增强现有的安全解决方案,而不是替换 antivirus 软件、安全密码、防火墙或其他安全系统。即使运行 SELinux,仍需要遵循好的安全实践,如保持软件更新、使用安全的密码、使用防火墙。
10.1.3. SELinux 示例
以下示例演示了 SELinux 如何提高安全性:
- 默认操作为 deny(拒绝)。如果 SELinux 策略规则不存在允许访问(如允许进程打开一个文件),则拒绝访问。
-
SELinux 可以限制 Linux 用户。SELinux 策略中包括很多受限制的 SELinux 用户。可将 Linux 用户映射到受限制的 SELinux 用户,以便利用其使用的安全规则和机制。例如,将 Linux 用户映射到 SELinux
user_u
用户,使得 Linux 用户将无法运行,除非有其他配置的用户 ID(setuid)应用程序,如sudo
和su
。 - 增加进程和数据的分离。SELinux 域(domain)的概念允许定义哪些进程可以访问某些文件和目录。例如:在运行 SELinux 时,除非有其他配置,攻击者将无法侵入 Samba 服务器,然后使用 Samba 服务器作为攻击向量读取和写入其它进程使用的文件(如 MariaDB 数据库)。
-
SELinux 可帮助缓解配置错误带来的破坏。在区传输(zone transfer)过程中,不同的 DNS 服务器通常会在彼此间复制信息。攻击者可以利用区传输来更新 DNS 服务器使其包括错误的信息。当在 Red Hat Enterprise Linux 中使用 BIND(Berkeley Internet Name Domain)作为 DNS 服务器运行时,即使管理员没有限制哪些服务器可执行区传输,默认的 SELinux 策略也会阻止区文件 [1] 通过 BIND
named
守护进程本身或其它进程,使用区传输。 -
如果没有 SELinux,攻击者可以利用漏洞在 Apache Web 服务器上路径遍历,并使用特殊元素(如
../
)访问存储在文件系统中的文件和目录。如果攻击者尝试对使用了强制模式运行 SELinux 的服务器进行攻击,SELinux 会拒绝对httpd
进程不能访问的文件的访问。虽然 SELinux 无法完全阻止这型的攻击,但它可以有效地缓解它。 -
使用强制(enforcing)模式的 SELinux 可以成功防止利用 kernel NULL pointer dereference operators on non-SMAP platforms (CVE-2019-9213) 安全漏洞进行攻击。攻击者可以利用
mmap
功能中的一个漏洞(不检查 null 页面的映射)将任意代码放在本页中。 -
deny_ptrace
SELinux boolean 和使用 enforcing 模式的 SELinux 的系统可以防止利用 PTRACE_TRACEME 安全漏洞 (CVE-2019-13272) 进行的攻击。这种配置可以防止攻击者获得root
特权。 -
nfs_export_all_rw
和nfs_export_all_ro
SELinux 布尔值提供了一个易于使用的工具,以防止错误配置网络文件系统 (NFS),如意外地共享了/home
目录。
其它资源
- SELinux 作为操作系统的一个安全基础 - 实时优势和示例 (红帽知识库)
- 使用 Ansible 强化 SELinux (红帽知识库)
- 使用 Ansible playbook 进行 SELinux 强化的 selinux-playbooks Github 存储库
10.1.4. SELinux 构架和软件包
SELinux 是一个内置在 Linux 内核中的 Linux 安全模块(LSM)。内核中的 SELinux 子系统由安全策略驱动,该策略由管理员控制并在引导时载入。系统中所有与安全性相关的、内核级别的访问操作都会被 SELinux 截取,并在加载的安全策略上下文中检查。如果载入的策略允许操作,它将继续进行。否则,操作会被阻断,进程会收到一个错误。
SELinux 决策(如允许或禁止访问)会被缓存。这个缓存被称为 Access Vector Cache(AVC)。通过使用这些缓存的决定,可以较少对 SELinux 策略规则的检查,这会提高性能。请记住,如果 DAC 规则已首先拒绝了访问,则 SELinux 策略规则无效。原始审计消息记录到 /var/log/audit/audit.log
中,它们以 type=AVC
字符串开头。
在 RHEL 8 中,系统服务由 systemd
守护进程控制;systemd 启动
和停止所有服务,用户和进程使用 systemctl
实用程序与 systemd
通信。systemd
守护进程可以参考 SELinux 策略,检查调用进程的标签以及调用者尝试管理的单元文件标签,然后询问 SELinux 是否允许调用者访问。这个方法可控制对关键系统功能的访问控制,其中包括启动和停止系统服务。
systemd
守护进程也充当 SELinux 访问管理器。它检索运行 systemctl
的进程的标签,或向 systemd
发送 D-Bus
消息的进程标签。然后守护进程会查找进程要配置的单元文件标签。最后,如果 SELinux 策略允许进程标签和单元文件标签之间的特定访问,systemd
可以从内核检索信息。这意味着,SELinux 现在可以限制需要与 systemd
交互特定服务的被破坏的应用。策略作者也可以使用这些精细的控制来限制管理员。
如果进程正在向另一个进程发送 D-Bus
消息,如果 SELinux 策略不允许这两个进程 的 D-Bus
通信,则系统将打印 USER_AVC
拒绝消息,并且 D-Bus 通信超时。请注意,两个进程之间的 D-Bus 通信可以双向运行。
为了避免不正确的 SELinux 标记和后续问题,请确保使用 systemctl start 命令启动
服务。
RHEL 8 提供以下用于 SELinux 的软件包:
-
策略:
selinux-policy-targeted
、selinux-policy-mls
-
工具:policy
coreutils
、policycoreutils-gui
、libselinux-utils
、policycoreutils-python-utils
、setools-console
、checkpolicy
10.1.5. SELinux 状态和模式
SELinux 可使用三种模式之一运行: enforcing(强制)、permissive(宽容)或 disabled(禁用)。
- Enforcing 模式是默认操作模式,在 enforcing 模式下 SELinux 可正常运行,并在整个系统中强制实施载入的安全策略。
- 在 permissive 模式中,系统会象 enforcing 模式一样加载安全策略,包括标记对象并在日志中记录访问拒绝条目,但它并不会拒绝任何操作。不建议在生产环境系统中使用 permissive 模式,但 permissive 模式对 SELinux 策略开发和调试很有帮助。
- 强烈建议不要使用禁用(disabled)模式。它不仅会使系统避免强制使用 SELinux 策略,还会避免为任何持久对象(如文件)添加标签,这使得在以后启用 SELinux 非常困难。
使用 setenforce
实用程序在 enforcing 模式和 permissive 模式之间变化。使用 setenforce
进行的更改在重启后不会保留。要更改为强制模式,请以 Linux root 用户身份输入 setenforce 1
命令。要更改为 permissive 模式,请输入 setenforce 0
命令。使用 getenforce
工具来查看当前的 SELinux 模式:
# getenforce
Enforcing
# setenforce 0 # getenforce Permissive
# setenforce 1 # getenforce Enforcing
在 Red Hat Enterprise Linux 中,您可以在系统处于 enforcing 模式时,将独立的域设置为 permissive 模式。例如,使 httpd_t 域为 permissive 模式:
# semanage permissive -a httpd_t
请注意,permissive 域是一个强大的工具,它可能会破坏您系统的安全性。红帽建议谨慎使用 permissive 域,如仅在调试特定情境时使用。