【2013年11月21日 51CTO外电头条】今年我们已经迎来SELinux的十岁生日,回想十载发展历程真有种如梦似幻之感。SELinux最早出现在Fedora Core 3当中,其后又登陆红帽企业Linux 4。对于从未使用过SELinux或者希望进一步确认其基础定义的朋友们,请接着往下看。
SElinux是一套标签系统。每个进程都拥有自己的标签,操作系统中的每个文件/目录对象都拥有自己的标签。甚至包括网络端口、设备以及潜在主机名也被分配到了标签。我们通过编写规则来控制对某个进程标签乃至对象标签的访问,这就是所谓管理政策。SELinux内核会强制执行这些规则,有时候我们将这种方案称为强制访问控制(简称MAC)。
对象的拥有者无权超越对象的安全属性。标准Linux访问控制、所有/组+权限标记(例如rwx)通常被称为自主访问控制(简称DAC)。SELinux中不存在UID或者文件所有权概念。所有事物都由标签机制进行控制。这意味着SELinux系统可以在不涉及高权限root进程的前提下实现设置。
备注: SELinux并不会取代DAC控制。SELinux是一种并行执行模式,应用程序必须在同时符合SELinux与DAC的要求之后才能正常执行。这可能会让管理人员们在遇到权限被拒绝的状况时感到有些混乱。管理员权限被拒绝意味着DAC方面出了问题,但这肯定与SELinux标签无关。
- 类型强制
让我们进一步了解标签机制。SELinux的主要模式或者强制手段被称为"类型强制"。这意味着我们需要根据进程的实际类型为其定义标签,而文件系统对象的标签也同样基于其类型。
比喻
让我们假设有这样一套系统,其中需要定义的对象类型分为猫(cat)或狗(dog)。一只猫与一条狗构成进程类型。
现在我们的一类对象希望与所谓“食物”(food)进行互动。食物也需要分为不同类型,也就是猫食与狗食。
作为政策的制定者,我打算采取这样的处理方式:dog有权吃掉dog_chow食物,猫则有权吃掉cat_chow食物。在SELinux中,我们会把这条规则写入政策。
- 允许猫进程吃掉cat_chow:food;
- 允许狗进程吃掉dog_chow:food;
有了这些规则,系统内核将允许猫进程吃掉拥有cat_chow标签的食物,而狗进程则吃掉拥有dog_chow标签的食物。
但在默认情况下,SELinux系统会阻止一切执行请求。这意味着如果狗类进程试图吃掉cat_chow,内核会对此加以阻止。
与之类似,猫进程也不允许接触狗进程的食物。
实际情况
我们将Apache进程标签为httpd_t,并将Apache内容标签为httpd_sys_content_t与httpd_sys-content_rw_t。假设我们把信用卡数据保存在一套MySQL数据库当中,其标签为mysqld_data_t。如果某个Apache进程并侵入,黑客就能够获得httpd_t进程的控制权并获准读取httpd_sys_content_t文件的内容、向httpd_sys_content_rw_t当中写入数据。然而黑客仍然无法读取信用卡数据(mysqld_data_t),即使被侵入的进程以root权限运行。在这种情况下,SELinux能够显著缓解由侵入活动带来的安全威胁。
- MCS强制
比喻
在前面提到的状况里,我们输入了狗与猫两种进程类型。不过如果狗进程又分为两种:Fido与Spot,我们又不希望Fido去动Spot的dog_chow,情况又会发生怎样的变化?
一种解决方案当然是创建大量新类型,例如Fido_dog与Fido_dog_chow。不过这种作法很快就将失去可行性,因为所有狗类进程都拥有近乎相同的权限。
为了解决这个难题,我们开发出一种新的强制形式,我们将其称为多类别安全(简称MCS)。在MCS当中,我们为标签加入另一种组成部分,并将其应用到狗进程与dog_chow food当中。现在我们把狗进程分别标记为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标签的内容。在虚拟机标签机制当中,我们不仅要采用类型强制方案,同时也要通过MCS对其加以区分。当虚拟机组即将启动一套虚拟机系统时,会为其选择一个随机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当中也使用类似的隔离机制。每个组件(包括用户/应用程序进程)都以同样的SELinux类型加以运行(openshift_t)。政策定义规则、规则决定如何控制与组件类型及独特MCS标签相关的访问活动,从而确保不同组件之间无法交互。
感兴趣的朋友可以点击此处查看一段小视频,了解如果某个Openshift组件拥有root权限将引发怎样的状况。
- MLS强制
这是SELinux的另一种强制形式,但使用的频繁要低得多,这就是多级安全(简称MLS);它诞生于上世纪六十年代,主要被用于Trusted Solaris等受信操作系统。
其主要思路在于以数据被使用的层级为基础进行进程控制。也就是说,secrect进程无法读取top secret数据。
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。
当然,dog:Greyhound与dog:Chihuahua仍然受到类型强制的影响而无法吃掉cat_chow:Siamese,即使在MLS当中灰狗类型对暹罗猫类型拥有支配权。
真实情况
假设我拥有两台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:Secrect与httpd_sys_content_t:TopSecret的内容都将暴露在黑客面前。
我们将MLS机制用于军事环境下,即某位用户只获准查看secret数据,而另一位处于同一系统下的用户则可以查看top secret数据。
总结
SELinux是一套强大的标签系统,通过内核对每一个单独进程进行访问控制。其中最主要的功能就是类型强制,其中规则的作用是根据进程与对象双方的标签类型来判断某个进程是否有权读取相应的对象。此外另有两种控制机制,其中MCS负责对同类进程进行彼此区分,而MLS则允许一种进程拥有指向另一种进程的支配权限。
原文链接:http://opensource.com/business/13/11/selinux-policy-guide#.UoWMDG-jYlE.sinaweibo