分类: 网络与安全
2009-09-24 13:33:00
在新的基于RHEL一般都自带了selinux,多数情况下我们把selinux禁用了,事实上既然RHEL要集成它,必然有他的优点和长处,我们通过下文来了解selinux,也许你会喜欢用上它。
英文原文来自
by Russell Coker
翻译:胡智江
主要内容
介绍:
SELinux概览:
SELinux深入研究:
Fedora中策略的实现:
Fedora的缺省SELinux策略:
更多关于SELinux的资料:
关于作者和译者:
介绍:
当今世界,无处不在高速互联网连接、如备有无线接入点的咖啡馆和在网上到处传播的各种黑客工具使得出于对计算机安全的考虑成为老生常
谈。出于解决安全问题,NSA在Linux社区的帮助下开发了一种访问控制体系,在这种访问控制体系的限制下,进程只能访问那些在他的任务中所需要文件。
这种体系叫做 Security-Enhanced Linux或简化为SELinux。
SELinux概览:
SELinux是一种基于 域-类型 模型(domain-type)的强制访问控制(MAC)安全系统,它由NSA编写并设计成内核模块包含到内核中,相应的某些安全相关的应用也被打了SELinux的补丁,最后还有一个相应的安全策略。
众所周知,标准的UNIX安全模型是”任意的访问控制”DAC。就是说,任何程序对其资源享有完全的控制权。假设某个程序打算把含有潜在重要信息的文件仍到/tmp目录下,那么在DAC情况下没人能阻止他!
而MAC情况下的安全策略完全控制着对所有资源的访问。这是MAC和DAC本质的区别。
SELinux里实现的MAC允许程序在/tmp目录下建立文件,也允许这个文件按照UNIX权限字的要求对全世界可读,但是当UNIX许可检查应用后, SELinux许可检查还要进一步判断对资源的访问是否被许可。
换
句话说,尽管某些UNIX文件的权限被设定为0777但是你也许仍然会被禁止读,写和执行该UNIX文件。在只有DAC的情况下,用户可以查看或更改属于
他的任何文件。SELinux则可以限制每一个进程对各种资源的访问,和访问的权级。就是说当一个程序在使用含有敏感数据时,这些数据会被禁止写入那些低
权级进程可读的文件中。
SELinux提供了比传统的UNIX权限更好的访问控制。
例如,管理员可以只允许一个应用程序添加记录到一个日志文件但不允许其重写或者删除该日志文件的内容。虽然ext2和ext3文件系统有一个 append-only标签(使用chattr设置),但是这属性不区分某一个进程(不能在为一个访问 append-only的同时,又允许另一个进程据有完全可写的权利);另一方面,一个应用程序可以被允许在一个文件夹中建立文件和向其写入数据,但不能 删除文件:这种特性是没有SELinux的普通的Linux内核所不能做到的。还有,网络应用程序可以绑定到其需要的端口上(如BIND的53端口),但 不能绑定其它端口。
域-类型模型意味着在安全域中运行着的每一个进程和每一个资源(一般文件、目录文件和套接字等)都有一个与之相联系的”类型”(type)。
在这基础之上建立了一系列规则,这些规则列出了某个域可以在每一个类型上执行的所有动作。 域-类型模型的一个优点就是我们可以对策略进行分析,从而判断出哪些信息有可能外溢。在标准的UNIX环境中,用户一般可以使用ps命令来互相查看彼此的 进程列表,然而这也会为攻击者提供有价值的信息。甚至就算完全阻止用户使用ps命令,信息还是会意外的或故意的泄露,其实在一个给定的UNIX环境中,哪 些信息会发生泄露是无法判断的。
而在SELinux情况下,我们会有很多工具用来分析SELinux策略并判断哪些信息泄露是可能的。举个例子,假如有两个应用程序被允许向一个日 志文件添加数据,且他们互相不能直接通信。那么如果一个其中进程又获得了对该日志的读权限的话,那么一个单方通信就有可能形成。
对访问/etc/shadow文件做访问限制是个很好的例子,通过该例子我们可以看出策略分析的好处。
如果你装了Fedora Core
3,并且选择了严格的SElinux策略配置,那么将会有17个域被允许访问shadow_t(/etc/shadow的type),其中有9个域据有写
权利。这17个域中有2个可以从用户域(user domain)进入,他们是/usr/bin/passwd和
/sbin/unix_chkpwd(一个为无特权应用程序提供密码检查的辅助程序,比如向锁屏程序就需要使用到unix_chkpwd)。这17个域中
的某些域是为一些不常见的应用程序准备的(如radius_t域就是为RADIUS服务器准备的),所以,也就是说,就算除去这个不常用的域,一般的系统
中还有16个可访问的域能够访问/etc/shadow呢!
值得注意的是,Fedora发型版的SELinux策略已经变得越来越灵活;未来版本的策略也许会使何以访问/etc/shadow的域超过17 个,这取决于可调节选项的实际配置。还要注意的是,17这个数字是基于严格的策略设定之后而得出的,实际上一个默认的安装会大于这个数字。
在一个没有SE的机器上,任何以root身份运行的进程都可以访问/etc/shadow文件。这意味着任何被”SETUID root”的二进制代码或以root身份运行的网络服务守护进程,它们所产生的任何安全问题都将会是灾难性的。
SELinux允许我们限制这些守护进程只访问其所需:
BIND只能在53端口提供服务、DHCP服务器可以使用原始套接字(raw network access)、DHCP客户端也可以使用原始套接字并可以改变网络接口,但是它们谁都别想访问/etc/shadow,/home,/root等等这些重要的资源。
所以,在SElinux的情况下,如果BIND受到了危害,它最多也就是发送一些伪造的报文罢了。如果DHCPD受到了危害,最坏的可能就是你的ip地址分配被搞乱。这比root权力被远程滥用好多了!
大家很清楚,一个进程可以援引另一个进程。
在这种情况下,拿DHCPD为例,DHCPD也许会尝试援引 /sbin/unix_chkpwd对密码进行强力攻击。(But even that potential vulnerability is closed):SELinux能够提供”过渡”规则,这种规则可以用来判断各种域间过渡是否合法。有了”过渡”规则以后,由用户执行的屏幕保护程序可以 顺利过渡到/sbin/unix_chkpwd这样一个特权域,然而DHCPD就别想了。
上述这些限制功能可以使你对系统的状态了如指掌。如果你发现你的DHCP服务器有BUG,那你只要简单的升级DHCP服务器到新版本并且确定每一个客户端都能正常获得IP地址就可以了。可是如果没有SE的话,你还要考虑你的新服务器是否已被黑客入侵并擦除了痕迹。
SElinux 对不同的域做了严格的隔离。我以前运行一个Debian系统有两年时间,在这期间我开放了他的root密码。最近两个月我在一个Fedora系统上做同样 的事情。但这两个系统已经抵抗住了很多次以root身份的攻击(见http /play.html)。(译者注:这里有一些作者对其playmachine的介绍被忽略了)
为了给RHEL4做代码测试,Fedora core 2已经尝试集成了SELinux,但是默认是关闭的。而且将来RHEL和Fedora Core的SE还会有非常大的差别的。我们计划在RHEL中,将把SELinux的策略设置的比Fedora Core要严格,我们相信这样做也符合用户的要求。未来的Fedora版本的SELinux策略将会越来越严格,但再严格也不会超过RHEL。
SELinux深入研究:
SELinux的策略数据库控制着SELinux的方方面面。它可以判断一个程序可能会运行在哪个域中,还可以说明某个域可以访问哪些资源。这种规 定被叫做规则,一个典型的策略往往拥有100,000条规则。别被这数字吓坏,我们根本不必去关心它,因为当我们撰写策略时,我们可以使用高级宏,这些高 级宏的一行就能生成10,000条规则。除了宏以外,还有一些工具,使用他们可以分析这些生成的规则是否能达到你对安全的要求。其实再和设置每个文件的 UNIX 权限位这样的工作比起来,这100,000个规则也是相当小的工作量了。
Fedora Core
2安全策略的目标是满足大多数用户无需改动就可以工作的要求,但也有一些普通的简单的选项可以调节策略,一般都是简简单单的一行选项。比如是否允许用户通
过dmesg阅读内核的日志,是否允许管理员(sysadm_r)直接通过SSH登陆或登陆图形会话,还有是否允许用户绑定TCP套接字。
那
100,000个左右的规则存储在一个大约2.6MB的文件中,当系统启动时随内核一起装入内存并占用同样大小(大约2.6MB)的内核空间。
Fedora Core 3默认的strict策略有着多余290,000条规则,占用7MB的内核空间。Fedora Core
3默认的target策略有大约5,000条规则,占用150K的内核空间。
目前,SELinux并没有在内存使用方面进行优化;但现在对这些优化工作已经有了计划和一些降低内存使用的方法。如果你不打算使用某些守护进程, 你可以简单的将其对应的策略文件删除以便获得占用空间更少的策略。2003年,在Ottawa举办的一次Linux讨论会上,我提交过一篇文章,那是关于 我在把 SELinux移植到HP iPAQ PDA上所做的工作的文章(在http //archive.linuxsymposium.org/ols2003/Proceedings/可以获得)。
证明我可以使SELinux(且选择 strict策略)很好的工作在一台只有 64 MBs的RAM 和32 MBs 存储空间的小平台上,并且我相信我还可以使它运行在更小的平台上。针对Fedora Core2系统,我们只把目光定位在目前最常见的硬件平台,从而得出了默认的策略配置。但那些使用老机器的用户们也许会希望配置出最小限度的策略以便减少 内存使用和提高性能。
在使用了SELinux的系统中,每一个进程的上下文都包含三个组成部分:一个ID(identity),一个角色(role)和一个域(domain)
ID是指这个进程的所有者,就是UNIX账户,但前提是这个账户必须被预先编译到SELinux策略中去使SELinux认识这个账户,不然的话 SELinux默认地将那些未知的系统进程ID记为 system_u ,将那些未知的用户进程ID记为 user_u;角色用来判断某个处于此角色的ID可以进入哪些域,还用来防止某个处于此角色的ID进入其它不该进入的域。比如, user_r角色就不允许进入 sysadm_t (重要的系统管理域)。
换句话说就是,那些只有 user_u ID的进程只能扮演 user_r 这个角色,而 user_r 这个角色 永远不能被许可进入 sysadm_t 域。从而,那些只有 user_u 这个ID的人是别想进入 sysadm_t 域的。这些特色在缺省的Fedora Core2策略中并没有完全使用,当前我们只是把努力花在制定守护进程上,而对用户域的策略限制的很少(targeted策略没有对用户登陆做任何限 制)。
一个安全上下文可以像 identity:role:domain 这样一种描述符的方式简明的表现出来。
比如,典型的系统管理上下文可以表示成 root:sysadm_r:sysadm_t 。任何可以被访问的对象都可以这样来表示。值得注意的是,”域”其实也是和一个进程相对应的一个”类型”。所以当检查某个进程是否有权向另一个进程发送信 号(比如为ps命令检阅/proc文件系统)时,接受信号的进程的”域”就会充当”域-类型”模型中的”类型”的角色,从而完成”域-类型”的规则检查。 即完成了进程间通信权限的检查。由于对于文件还没有使用角色这个机制,所以目前每个文件都被规定为object_r 角色(这个角色只是占个位置罢了,对策略没有任何影响)。
文件的ID就是文件创建者的ID。constraints 策略源文件中使用这个方式来判断一个访问是否有权改变某个文件的上下文描述符。除非被访问的文件的描述符中的ID字段和访问该文件的进程的所有者ID字段 相同,无论是改变前还是改变后,否则进程无权改变一个文件的上下文描述符。
例如,一个拥有 rjc:user_r:user_t 描述符的进程可以将一个拥有 rjc:object_r:user_games_rw_t 描述符的文件的描述符改为rjc:object_r:user_games_ro_t ,但是它无权改变一个拥有 john:object_r:user_games_rw_t 描述符的文件的任何属性。
要想查看当前运行的进程的上下文描述符,可以使用ps命令并加入 “-Z”选项,如例一:”ps ax -Z的输出”:
PID CONTEXT COMMAND
1634 root:user_r:user_t -bash
1662 root:user_r:user_t ps ax -Z
Example 1. Example Output of ps ax -Z
要想查看目录下的文件的上下文描述符,可以使用ls命令并加入 “-Z”选项,如例一:”ls -Z的输出”:
drwxr-xr-x root root system_u:object_r:bin_t bin
drwxr-xr-x root root system_u:object_r:boot_t boot
drwxr-xr-x root root system_u:object_r:device_t dev
drwxr-xr-x root root system_u:object_r:etc_t etc
drwxr-xr-x root root system_u:object_r:home_root_t home
drwxr-xr-x root root system_u:object_r:root_t initrd
drwxr-xr-x root root system_u:object_r:lib_t lib
drwx—— root root system_u:object_r:lost_found_t lost+found
drwxr-xr-x root root system_u:object_r:default_t misc
drwxr-xr-x root root system_u:object_r:mnt_t mnt
drwxr-xr-x root root system_u:object_r:usr_t opt
?——— ? ? oracle
dr-xr-xr-x root root proc
drwxr-x— root root system_u:object_r:user_home_dir_t root
drwxr-xr-x root root system_u:object_r:sbin_t sbin
drwxr-xr-x root root selinux
drwxr-xr-x root root system_u:object_r:default_t srv
drwxr-xr-x root root sys
drwxrwxrwt root root system_u:object_r:tmp_t tmp
drwxr-xr-x root root system_u:object_r:usr_t usr
drwxr-xr-x root root system_u:object_r:var_t var
Example 2. Example Output of ls -Z
值得注意的是:对于那些没有指定上下文的文件(一般是指那些不支持rwx标签的文件系统,如/sys、/proc、/selinux),ls命令就
不会显示其上下文。对于不能用stat命令查看当前状态的那些文件系统。ls命令返回”?———”,其所有者和所有组也被标记为”?”,同样的,他的上下
文也不会显示。
如例三所示,id命令将返回当前shell的上下文
uid=0(root) gid=0(root) groups=0(root),1(bin),2(daemon),3(sys),4(adm),6(disk),10(wheel) context=root:user_r:user_t
Example 3. Example Output of the id Command
如果你的SELinux系统使用了strict 策略,你会发现应用程序做一些不正常的事情是很容易发生的。你经常会发现某些程序中会有些bug,这些bug使程序做那些你的SELinux策略不允许其做的其它事情。
SELinux
要求进程的上下文只有在被执行的”那一刻”才允许改变。新进程的域和角色信息可以从exec系统函数的上下文和文件类型中自动获得。进程也可以在执行
exec之前被指明上下文。这些过程自然受SELinux策略的控制,因为ID,角色和域都受SELinux策略的控制。
Fedora中策略的实现:
从 Fedora Core 3 开始,SELinux的策略数据存储于/etc/security/selinux/X/src/policy/目录下(X指你选则的策略,可以是 “strict” 或者 “targeted”)。在这个目录中,你可以使用”make load”来编译并装在策略。也就是用那个命令将策略编译成二进制格式并装在到内核中,并立即生效。除了装如内核,该命令还将策略的二进制格式存储到 /etc/selinux/X/policy/policy.YY文件中,这里X指你选则的策略,可以是”strict” 或者 “targeted”,YY是策略的版本号(Fedora Core 3支持最新的版本是18)。这是为了在系统开机的第一时间,init可以迅速装载策略到内核。/etc/selinux/config这个配置文件用来告 诉init那些策略需要装载。
当你启动一个SELinux时,init所做的第一件事就是挂载/proc文件系统,并判断SELinux是否被激活。init通过 selinuxfs文件系统类型来判断内核中是否有SELinux,如果内核中没有SELinux或者内核参数中 selinux=0 这一项,那么系统就会以一种叫做 non-SE的状态被继续引导启动。如果发现了SELinux,那么/selinux虚拟文件系统将被创建,然后,init通过 /selinux/policyvers来检查内核所支持的SELinux版本。最后,相应的策略数据 /etc/selinux/X/policy/policy.YY就会被装在到内核中去了。
当策略被装载完之后,所有正在运行着的进程(指的就是init和内核的所有线程)都将被指定 system_u:system_r:kernel_t 这样一种上下文(内核线程其实无论在什么时间被创建,其上下文都是system_u:system_r:kernel_t )。当init装载完策略之后,它还要重新执行自己。策略中有一个规则叫domain_auto_trans(kernel_t, init_exec_t, init_t)。他的意思就是当 kernel_t 域执行了一个据有 init_exec_t 类型的可执行文件(如/sbin/init),那么该执行文件对应的进程的域就会自动过渡到 init_t 域(这是/sbin/init正确的所在域)。当这些都完成之后,init就继续完成那些通常的任务来完成机器的启动。内核线程自始至终都以 kernel_t 这个类型运行。
文件和目录的上下文存储于扩展属性当中 (XATTRs)。更多关于XATTRs的信息请参考attr(5), getfattr(1) 和 setfattr(1)的manpage。
简单的说,一个XATTR就是硬盘上某个文件的所有权,它由文件名和其它一些信息组成。对于每个 persistent
文件系统来说,它的每个文件或目录的SELinux上下文就存储在
security.selinux属性当中。虽然/proc文件系统不是persistent
文件系统,但SELinux还是在幕后为其文件和目录做了上下文标记,只是不能用getxattr获得罢了。和它对比,devpts文件系统(应用于
/dev/pts Unix98伪终端)中各个文件(各个伪终端)的上下文是可以通过getxattr来获得的,并可以通过 setxattr
来更改每个设备的上下文(以便sshd等类似程序可以更改tty设备的上下文)。对于那些拥有固定存储的文件系统(ext2, ext3,
Reiserfs, XFS, vfat, 等等) 有两种选择用于设定文件上下文:
第一种:文件系统的类型就规定了其内部每一个文件英据有统一的上下文;
第二种:使用 XATTRs 为每个文件标记不同上下文。例如,在iso9660(CD-ROM)文件系统中的每一个文件的上下文都是system_u:object_r:iso9660_t ,这被称做 genfs标记。
Ext2, ext3 和XFS支持 XATTRs 而且 Fedora 系统也支持安全标记名字空间,所以Fedora默认使用 XATTRs 来标记文件的上下文,但这也是可选方法之一。因为 直到 Reiser4发布之前 ,Hans Reiser对 支持XATTR没多大兴趣,所以Fedora的 ReiserFS 文件系统不能很好的支持SELinux标记操作。也就是说,使用 ReiserFS 文件系统作为SELinux的根文件系统是不可能的事情。
XFS有一个与XATTRs相关的重要的问题:如果XATTRs不能被装入超级块(inode),那么它们就会被装入数据块,每一个超级块就要使用 一个数据块用来装 SELinux XATTR 。建立XFS时,mkfs.xfs在默认情况下创建的数据块大小为4096,超级块大小为256(要是用于安装 SELinux XATTR ,大约缺少30字节)。这就是说,默认的XFS文件系统中,每一个超级块要占用4096字节用来装载 SELinux XATTR ,这对于磁盘空间来说是严重的浪费!当你使用”-i size=512″选项创建一个XFS文件系统时,超级块的大小就变成了512字节,这样就可以将SELinux XATTR 装入超级块,即节省了空间,又提高的性能。512字节的超级块也有可能给其它操作带来好处。所以,如果你使用XFS并且打算将来使用 SELinux 的话,将超级块的大小规定为512字节肯定是个好主意。
如果你使用的是较新的内核(如最新的Fedora内核或标准2.6.8.1内核)并且使用最新的mount工具,那么当你挂载一个文件系统时,有一 个选项可以用来为整个文件系统指定上下文标签。比如你要挂载的文件系统是一个邮件池(mail spool),你可以使用”-o context=system_u:object_r:mail_spool_t”选项来挂载他,这样会将其内部的全部文件的上下文标记为 system_u:object_r:mail_spool_t。如果你的这个邮件池很大,而且还是XFS文件系统,这个方法还可以避免上一段所讨论的 inode大小的问题。甚至对于ext3那样的对XATTRs 开销较小的文件系统来说,使用context=选项挂载文件系统也会进一步减少开销,也可以避免为已经建立的文件系统重新设置 SElinux上下文(如果文件系统中文件较多的话,会浪费很长的时间)。
Fedora的缺省SELinux策略:
在Fedora Core 3系统中,缺省的策略是”targeted “策略。对于此种选择人们议论纷纷,问题在于我们希望能使尽可能多得人使用SELinux。如果人们觉得这玩意太可怕并且妨碍了人们做他们想做的事,那么 人们会把它关掉。所以我们在这个时候宁愿为大多数人提供适量的保护策略,也不会为了少部分人而提供严格的保护策略。缺省的Fedora Core 3安装会激活 SELinux 并使用”targeted “策略,你也可以通过运行 system-config-securitylevel 这个程序将策略改为更加严格的 “strict “策略。
如果你安装了策略的源文件包,那么策略的源文件就在/etc/selinux/X/src/policy/目录里面(X指你选则的策略,可以是 “strict” 或者 “targeted”)在这个目录下有一个叫作domains/program/的子目录,里面为每一个守护进程对应了一个.te文件。你可以删去那些你 不使用也不打算使用的守护进程所对应的.te文件,从而减少内核内存空间的使用,并提高性能。比如,你的系统没有BIND服务,你完全可以删掉 named.te 文件。然后如果你使用”make load”命令重新装载策略到内核的话,内核对内存的使用量就会减少。然而也要小心,如果你误删了其它文件,那么你的系统将不能正常启动进入 enforcing模式。所以目前,这种调节最好还是由内行来做。
刚开始接触SElinux的你,要注意一个内核参数,它用来决定你系统的内核运行于 强制(enforcing )模式还是自由(permissive)模式,那就是”enforcing”参数。在自由模式下SELinux只是记录他该做什么,而事实上并不做任何动 作。在强制模式下SElinux会来真格的。如果你的策略有错误,在强制模式下系统可能会阻止你登陆!所以正常情况下你应改在启动时传 enforcing=1 给内核,当你的SELinux策略有问题时,你可以临时传enforcing=0给内核来查错。在/etc/selinux/config这个init的 配置文件中相应的有一个选项,通过设置它,也可以使系统进入自由模式。
如果你打算中止使用SELinux,你可以使用 selinux=0
这个内核参数。这会关闭SELinux的全部功能,就好像你的内核并没有把SElinux机制编译进去一样。所以当系统出了问题时,比如系统崩溃,有些人
就用此方法进行理事的恢复工作,但是我并不赞成这种做法。当你临时使用 selinux=0
进入系统后,你所建立的任何文件将不会拥有SELinux上下文标记。这就意味着,如果你替换了诸如/etc/passwd
或/etc/shadow等重要文件,那么下一次进入SELinux时,系统就不会正常的工作。这不是严重的问题,当你从CD引导时,做系统恢复时,或使
用一个不支持 XATTRs备份软件恢复系统时,同样的问题也会发生。这个问题虽然可以通过为受到影响的文件系统重新标记上下文来解决,但是使用
enforcing=0 来代替 selinux=0 不是更好吗?
你可以编辑/etc/selinux/config来临时关闭SELinux。
Fedora Core 2的释放是SELinux一次重要的发展。他是第一套提供对SELinux完整支持的主流Linux发行版本。Fedora Core 3 也是一个重要的里程碑,因为他是第一套将SELinux作为默认安装选项的Linux发行版本。
Red
Hat Enterprise Linux 4 见会跟随 Fedora Core 的开发步伐,其对SELinux的支持也会得到进一步的发展。当
RHEL 4 发布时,她将会从 Fedora Core 系统和在Fedora 上学习SELinux的用户那里获得非常大的益处。
你可以在 irc.freenode.net的 IRC服务器上的#fedora-selinux频道找到对SELinux的支持。还有 Fedora SELinux邮件列表 。我经常挂在#fedora-selinux上面,并也订阅了邮件列表,我期望着在那里回答您提出的任何问题。
更多关于SELinux的资料:
NSA site for Security-Enhanced Linux:
Fedora Core SELinux FAQ:
IRC channel for SELinux in Fedora Core: irc.freenode.net, #fedora-selinux
Mailing list for SELinux in Fedora Core:
SELinux play machine:
关于作者和译者:
Russell Coker 从2003年就为RedHat的 SELinux 工程工作。在那之前他是一个独立的顾问并在闲暇时间研究SELinux。他第一次了解SELinux 是在 2001 年Ottawa Linux 讨论会上,当时 NSA 的Pete Loscocco 针对SELinux做了一个演讲。在2002 的OLS 上他介绍了他如何将SELinux移植到Debian Linux上. 作为移植工作的一部分, 他还撰写了用于支持所有他使用的程序的策略, 这些策略后来成为了SELinux策略的主要来源. 在OLS2003 和 Linux Kongress 2002上他也发表了文章。