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 -ZExample 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 varExample 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_tExample 3. Example Output of the id Command

如果你的SELinux系统使用了strict 策略,你会发现应用程序做一些不正常的事情是很容易发生的。你经常会发现某些程序中会有些bug,这些bug使程序做那些你的SELinux策略不允许其做的其它事情。
SELinux 要求进程的上下文只有在被执行的"那一刻"才允许改变。新进程的域和角色信息可以从exec系统函数的上下文和文件类型中自动获得。进程也可以在执行 exec之前被指明上下文。这些过程自然受SELinux策略的控制,因为ID,角色和域都受SELinux策略的控制。