我们今年正在庆祝 SELinux 诞生 10 周年。真令人难以置信。 SELinux 最初在 Fedora Core 3 中引入,后来在 Red Hat Enterprise Linux 4 中引入。对于那些从未使用过 SELinux,或者想要了解其解释的人...
SELinux 是一个标签系统。每个进程都有一个标签。操作系统中的每个文件/目录对象都有一个标签。甚至网络端口、设备和潜在的主机名都被分配了标签。我们编写规则来控制进程标签对对象标签(如文件)的访问。我们称之为策略。内核强制执行这些规则。有时这种强制执行被称为强制访问控制 (MAC)。
对象的所有者无权决定对象的安全属性。标准的 Linux 访问控制,所有者/组 + 权限标志(如 rwx),通常被称为自主访问控制 (DAC)。SELinux 没有 UID 或文件所有权的概念。一切都由标签控制。这意味着可以设置一个没有全能 root 进程的 SELinux 系统。
注意: SELinux 不会让您绕过 DAC 控制。SELinux 是一种并行的强制执行模型。应用程序必须同时获得 SELinux 和 DAC 的允许才能执行某些活动。这可能会给管理员带来困惑,因为进程会收到“权限被拒绝”的错误。管理员看到“权限被拒绝”意味着 DAC 出了问题,而不是 SELinux 标签。
类型强制执行
让我们进一步了解标签。SELinux 的主要模型或强制执行称为类型强制执行。基本上,这意味着我们根据进程的类型定义进程上的标签,并根据文件系统对象的类型定义文件系统对象上的标签。
类比
想象一个系统,我们在对象上定义类型,例如猫和狗。猫和狗是进程类型。
*所有卡通均由 Máirín Duffy 创作
我们有一类对象,它们想要与之交互,我们称之为食物。我想给食物添加类型,猫粮和狗粮。
作为策略编写者,我会说狗有权吃狗粮,而猫有权吃猫粮。在 SELinux 中,我们会将此规则写入策略。
allow cat cat_chow:food eat;
allow dog dog_chow:food eat;
有了这些规则,内核将允许猫进程吃标记为 cat_chow 的食物,并允许狗吃标记为 dog_chow 的食物。
但是在 SELinux 系统中,一切默认都被拒绝。这意味着如果狗进程试图吃猫粮,内核会阻止它。
同样,猫也不允许碰狗粮。
真实世界
我们将 Apache 进程标记为 httpd_t,并将 Apache 内容标记为 httpd_sys_content_t 和 httpd_sys_content_rw_t。假设我们有信用卡数据存储在标记为 msyqld_data_t 的 mySQL 数据库中。如果 Apache 进程被黑客入侵,黑客可以控制 httpd_t 进程,并且将被允许读取 httpd_sys_content_t 文件并写入 httpd_sys_content_rw_t。但是,即使该进程以 root 身份运行,黑客也不允许读取信用卡数据 (mysqld_data_t)。在这种情况下,SELinux 减轻了入侵的影响。
MCS 强制执行
类比
上面,我们对狗进程和猫进程进行了类型化,但是如果您有多个狗进程会发生什么:Fido 和 Spot。您想阻止 Fido 吃 Spot 的 dog_chow。
一种解决方案是创建许多新类型,例如 Fido_dog 和 Fido_dog_chow。但是,这将很快变得难以管理,因为所有狗都具有几乎相同的权限。
为了处理这个问题,我们开发了一种新的强制执行形式,我们称之为多类别安全 (MCS)。在 MCS 中,我们在标签中添加了另一个部分,我们可以将其应用于狗进程和狗粮。现在我们将狗进程标记为 dog:random1 (Fido) 和 dog:random2 (Spot)。
我们将狗粮标记为 dog_chow:random1 (Fido) 和 dog_chow:random2 (Spot)。
MCS 规则规定,如果类型强制执行规则没问题,并且随机 MCS 标签完全匹配,则允许访问,否则拒绝访问。
Fido (dog:random1) 试图吃 cat_chow:food 被类型强制执行拒绝。
Fido (dog:random1) 被允许吃 dog_chow:random1。
Fido (dog:random1) 被拒绝吃 Spot 的 (dog_chow:random2) 食物。
真实世界
在计算机系统中,我们经常有许多进程都具有相同的访问权限,但我们希望将它们彼此隔离。我们有时称之为多租户环境。这方面最好的例子是虚拟机。如果我有一个服务器运行许多虚拟机,其中一个被黑客入侵,我希望阻止它攻击其他虚拟机和虚拟机镜像。但是在类型强制执行系统中,KVM 虚拟机被标记为 svirt_t,镜像被标记为 svirt_image_t。我们有规则规定 svirt_t 可以读取/写入/删除标记为 svirt_image_t 的内容。通过 libvirt,我们不仅实现了类型强制执行隔离,还实现了 MCS 隔离。当 libvirt 即将启动虚拟机时,它会选择一个随机 MCS 标签,例如 s0:c1,c2,然后将 svirt_image_t:s0:c1,c2 标签分配给虚拟机将需要管理的所有内容。最后,它将虚拟机作为 svirt_t:s0:c1,c2 启动。然后,SELinux 内核控制 svirt_t:s0:c1,c2 不能写入 svirt_image_t:s0:c3,c4,即使虚拟机被黑客控制并接管。即使它以 root 身份运行。
我们在 OpenShift 中使用类似的隔离。每个 gear(用户/应用程序进程)都以相同的 SELinux 类型 (openshift_t) 运行。策略定义了控制 gear 类型访问权限的规则,并使用唯一的 MCS 标签来确保一个 gear 不会与其他 gear 交互。
观看这个短视频,了解如果 Openshift gear 变为 root 会发生什么。
MLS 强制执行
SELinux 强制执行的另一种形式,使用频率较低,称为多级安全 (MLS);它在 60 年代开发出来,主要用于可信操作系统,如 Trusted Solaris。
主要思想是根据进程将要使用的数据级别来控制进程。机密进程不能读取绝密数据。
MLS 与 MCS 非常相似,只是它在强制执行中添加了支配概念。MCS 标签必须完全匹配,而一个 MLS 标签可以支配另一个 MLS 标签并获得访问权限。
类比
现在我们不谈论不同的狗,而是看看不同的品种。我们可能有灰狗和吉娃娃。
我们可能希望允许灰狗吃任何狗粮,但吉娃娃如果试图吃灰狗狗粮可能会噎住。
我们想将灰狗标记为 dog:Greyhound,将其狗粮标记为 dog_chow:Greyhound,,并将吉娃娃标记为 dog:Chihuahua,将其食物标记为 dog_chow:Chihuahua。
使用 MLS 策略,我们将使 MLS 灰狗标签支配吉娃娃标签。这意味着 dog:Greyhound 被允许吃 dog_chow:Greyhound 和 dog_chow:Chihuahua。
但是 dog:Chihuahua 不允许吃 dog_chow:Greyhound。
当然,即使 MLS 类型灰狗支配暹罗猫,dog:Greyhound 和 dog:Chihuahua 仍然被类型强制执行阻止吃 cat_chow:Siamese。
真实世界
我可以有两个 Apache 服务器:一个以 httpd_t:TopSecret 运行,另一个以 httpd_t:Secret 运行。如果 Apache 进程 httpd_t:Secret 被黑客入侵,黑客可以读取 httpd_sys_content_t:Secret,但将被阻止读取 httpd_sys_content_t:TopSecret。
但是,如果运行 httpd_t:TopSecret 的 Apache 服务器被黑客入侵,它可以读取 httpd_sys_content_t:Secret data 以及 httpd_sys_content_t:TopSecret。
我们在军事环境中使用 MLS,在军事环境中,用户可能只允许查看机密数据,但同一系统上的另一个用户可以读取绝密数据。
结论
SELinux 是一个强大的标签系统,内核控制着授予各个进程的访问权限。其主要特点是类型强制执行,其中规则定义了基于进程的标记类型和对象的标记类型允许进程访问的权限。还添加了两个额外的控制来隔离具有相同类型的进程,称为 MCS(完全隔离)和 MLS(允许进程支配)。
插图由 Máirín Duffy 创作。 获取涂色书!
有关 SELinux 的更多信息,请阅读我的博客 danwalsh.livejournal.com 并关注我的 Twitter @rhatdan。
27 条评论