Linux内核安全模块深入剖析【2.2】
8.4 扩展属性
简单是有代价的!相比于 SELinux 只用到一个扩展属性“security.selinux”, SMACK 用到的扩展属性非常多。原因是 SMACK 的策略过于简单了,简单的策略难以应付复杂的系统。为了应对层出不穷的挑战, SMACK 引入了多个扩展属性:
(1) SMACK64
这是最基本的扩展属性,文件客体的安全标签来自此属性。
(2) SMACK64EXEC
当进程执 行 exec 系统调用时, 进程的新安 全标签来自 被执行文件 的“ security. SMACK64EXEC”属性。
(3) SMACK64TRANSMUTE
这个属性作用于目录,当其值为“TRUE”时,在此目录下新建的文件/目录的安全标签(扩展属性 SMACK64)值来自此目录的安全标签(扩展属性 SMACK64)。
(4) SMACK64MMAP
这个扩展属性针对的是共享库(shared library)。通过这个标签为文件赋予了一个新的安全标签——作为共享库的安全标签。当进程通过 mmap 系统调用载入共享库文件时,文件的共享库标签不能拥有超越进程标签的操作许可。
举个例子,进程标签为 normal,一个共享库文件的共享库标签为 high。进程要访问的一个文件的标签为 secret。系统策略为:
normal secret wa high secret rwa
当进程加载共享库时就会失败,因为共享库 high 对 secret 的操作许可 rwa 超越了进程对“secret”的操作许可 wa。
SMACK 的这种设计不好理解,而且有两个潜在的问题。首先,文件成了某种意义上的主体,这在理论上不好解释;其次, mmap 系统调用不止用于加载共享库文件。
(5) SMACK64IPIN
(6) SMACK64IPOUT
这两个扩展属性是套接字专有的扩展属性, SMACK64IPIN 用于访问控制,比如判断当前进程能不能发送数据包到某个套接字。 SMACK64IPOUT 用于给发出的包(packet) 赋安全标签。
8.5 伪文件系统
SMACK 利用伪文件系统作为用户态应用和内核的接口。 SMACK 也用到了/proc/[pid]/attr目录下的文件,不过它只允许操作其中一个文件: current。除此之外, SMACK 还自创了一个名为 smackfs 的文件系统。文件系统 smackfs 中的文件按照功能可以分为两类,一类和策略相关,另一类和网络标签相关。
8.5.1 策略相关文件
(1) load
SMACK 访问控制的核心是策略。策略有两部分,一部分是所谓的系统策略,是不可更改的;另一部分是用户可配置的策略。下面首先简单介绍一下系统策略。
SMACK 预先定义了 5 个标签: ?、 ^、 *、 _和@,见表 8-1。
SMACK 预先定义了以下 7 条策略:
1)标签为“*”的主体(进程)不能对任何客体进行任何操作。
2)标签为“^”的主体(进程)可以对任何客体进行读(r)或执行(x)操作。
3)任何主体(进程)可以对标签为“_”的客体进行读(r)或执行(x)操作。
4)任何主体(进程)可以对标签为“*”的客体进行任何操作。
5)任何主体(进程)可以对标签相同的客体进行任何操作。
6)用户定义的策略所允许的操作都被允许。
7)其他操作都不被允许。
文件 load 是用来存取用户定义的策略的接口。 对此文件的写操作的要求是, 一次写入一行,
每行的格式是:
%24s%24s%5s
第一个字符串表示主体安全标签,第二个字符串表示客体安全标签,第三个字符串是操作
方式,全部操作方式是“rwxatl”,表示读、写、执行、添加、变形、锁。如果相应的操作不被
允许,就在相应的位置上填“-”。
(2) load-self
这个文件提供了一个接口,用来为进程提供额外的访问控制策略。与很多安全机制一样,
通过这个接口只能减少允许的操作。
(3) logging
这个文件接口用于控制 SMACK 的日志策略:记录失败、记录成功、都记录、都不记录。
这个文件的内容是一个整数。代码实现是:
/*
* logging functions
*/
#define SMACK_AUDIT_DENIED 0x1
#define SMACK_AUDIT_ACCEPT 0x2
extern int log_policy;
变量 log_policy 的比特位 0 对应是否记录失败事件,比特位 1 对应是否记录成功事件。
(4) access
这个伪文件接口用于检查规则的合法性。向这个文件写入一条规则,比如:
secret normal rw
然后再读取文件内容,如果内容是 ascii 字符‘1’,则前面写入的规则被内核允许,如果是 ascii字符‘0’,则前面写入的规则不被内核允许。
(5) onlycap
简单是有代价的, SMACK 策略中的存取方式没有覆盖的东西太多了,比如什么情况下可以修改安全策略。 SMACK 策略中客体也有缺失,比如:安全策略本身是不是客体,它的标签又是什么?为了解决这些问题, SMACK 的方式是引入超级标签,拥有超级标签的主体可以做诸如修改策略这样的特殊工作。
在 Linux 能力机制中有两个能力 CAP_MAC_ADMIN 和 CAP_MAC_OVERRIDE。CAP_MAC_ADMIN 的 语 义 是 : 拥 有 它 可 以 对 强 制 访 问 控 制 ( MAC ) 进 行 管 理 , CAP_MAC_OVERRIDE 的语义是:拥有它可以不受强制访问控制机制的限制。这两个能力的引入有些不合逻辑,能力机制本质上属于自主访问控制(DAC), DAC 不应该超越 MAC。
SMACK 的问题是机制过于简单,它需要引入一个类似于超级用户的角色来弥补机制的不足。 SMACK 引入了一个特殊的标签 smack_onlycap。 让这个标签和前述两个能力配合起来工作。具备 smack_onlycap 标签的进程, 如果拥有了 CAP_MAC_ADMIN 能力, 它就可以进行 SMACK策略管理工作。具备 smack_onlycap 标签的进程,如果拥有了 CAP_MAC_OVERRIDE 能力,就不受 SMACK 限制。
onlycap 文件提供对 smack_onlycap 标签进行管理的接口,写标签字符串可以修改smack_onlycap 值,写入“ -”清空 smack_onlycap。若 smack_onlycap 为空,进程只要拥有CAP_MAC_ADMIN 就可以进行 SMACK 策略管理工作,只要拥有 CAP_MAC_OVERRIDE 就可以不受 SMACK 限制。
(6) revoke-subject
通过这个文件接口写入一个标签,系统中具备这个标签的进程对所有客体都无法进行任何存取操作。
(7) change-rule
通过这个文件接口对系统现存策略进行修改。格式为:
%s %s %s %s
前两个字符串分别是主体标签和客体标签,第三个字符串是允许的操作,第四个字符串是不允许的操作。如果要修改的策略不存在,就创建新的策略。
(8) syslog
syslog 文件用来修改和查看变量 smack_syslog_label。这个变量标示一个特殊的标签,拥有这个标签可以进行 syslog 相关的操作。
8.5.2 网络标签相关文件
(1) ambient
这个文件反映的是无标签网络包的安全标签。 SMACK 依靠 IP 协议中一个未能成为标准的选项 CIPSO㊀ 来将安全标签附着于 IP 包包头之中。这就带来一个小问题:当收到一个没有CIPSO 数据的 IP 包时,此 IP 包的安全标签是什么呢?总得有什么方式来规定缺省值吧。这个缺省值的规定接口就是这个 ambient 文件。 ambient 文件的内容是一个字符串,规定了网络包的缺省标签。
(2) cipso
CIPSO 的标准㊁ 规定网络数据包携带敏感级别和敏感类别,敏感级别是一个整数,敏感类别是一个整数的集合。看起来 CIPSO 中敏感级别和敏感类别的设计来自 Bell-Lapadula 模型。而 SMACK 安全标签是一个字符串。这就需要用一种方式将二者联系起来。 cipso 文件就是做这件事的。先说对 cipso 文件的写操作,一次写入一行,每行的格式是:
%24s%4d%4d[%4d]...
第一个参数是字符串,表示 SMACK 安全标签,第二个参数是整数,为 CIPSO 的敏感级别值,第三个参数是整数,表示后续还有几个整数,这些整数是 CIPSO 的敏感类别值。举个例子:
level-3-cats-5-19 3 2 5 19
(3) direct
上面的 cipso 文件只是沟通 cipso 标签和 SMACK 标签的一座桥, 如果它是唯一的映射方式,那么为每一个 cipso 标签和 SMACK 标签都做出规定是一件很麻烦的事。在 SMACK 系统中还有更加直接的方式。
前面提到 CIPSO 标签包含级别和类别,级别是一个整数,类别是整数的集合。在实际的网络包中,每个类别是一个比特,整个类别的集合就是一个字符串。 SMACK 就直接用这个字符串来携带 SMACK 安全标签,因为 SMACK 标签也是一个字符串。不过,这就完美了吗?且慢,还有一个问题:承载类别集合的这个字符串有长度限制。看看 SMACK 代码中这段注释:
* * Maximum number of bytes for the levels in a CIPSO IP option. * Why 23? CIPSO is constrained to 30, so a 32 byte buffer is * bigger than can be used, and 24 is the next lower multiple * of 8, and there are too many issues if there isn't space set * aside for the terminating null byte. */ #define SMK_CIPSOLEN 24cipso 限制级别字符串的长度上限是 30, SMACK 进一步限制可用其中的开始 24 个字节。
当 SMACK 安全标签字符串长度低于 24 时, 直接将 SMACK 安全标签放入 cipso 级别字符串中。当 SMACK 安全标签字符串长度等于或大于 24 时,将 SMACK 安全标签转化为一个整数smk_secid,然后将 smk_secid 放入 cipso 类别字符串。为区分这两种情况,前一种情况下, cipso级别值为 smack_cipso_direct;后一种情况下, cipso 级别值为 smack_cipso_mapped。
direct 文件就是为了存取变量 smack_cipso_direct 而出现的。
(4) mapped
此文件用于存取变量 smack_cipso_mapped。
(5) doi
cipso 标准考虑到级别和类别的地域性问题, 即级别和类别在一组网络节点中的含义与在另一组网络节点中的含义是不同的。为了区分地域, cipso 标准规定 ip 的 cipso 选项中还应携带另一个信息 doi,全称是 domain of interpretation。
smackfs 的 doi 文件用来读写 doi 的值。
(6) netlabel
cipso 选项并没有成为正式标准,大多数系统没有实现它。实现了 cipso 的网络节点如何与不支持 cipso 的网络节点交互呢?首先,在这两个节点间交互的 IP 网络包不要带 cipso,其次,可以认为全部来自或发往不支持 cipso 网络节点的 ip 网络包都带有同一个安全标签。
文件 netlabel 就是用来规定来自某个或某些网络节点的网络包的网络标签。文件每一行的格式如下:
%d.%d.%d.%d label 或者 %d.%d.%d.%d/%d label 前面的格式用于单个网络节点,后面的格式用于子网。举个例子: 172.16.1.100 file-server 192.168.1.1/24 internal-subnet8.5.3 其他文件
下面要介绍一些功能和上面介绍的文件相同的文件,这些文件不同的只是输入的形式。
● access2
● cipso2
● load2
● load-self2
这些带“2”的文件接口和前面不带“2”的文件接口功能相同,只是输入格式有变。前面的文件接口要求标签的输入固定为 24 个字符,不够的补空格,长度不能超过 24。这里没有这个限制,短了就少写,长了就多写。
读到这里,你还觉得 SMACK 简单吗?
8.6 网络标签
通读 SMACK 代码,你会发现有关网络标签(netlabel)的代码占了很大部分。网络标签背后的标准是一个很早就提出但一直没有成为标准的 IETF draft㊀ ——CIPSO( Commercial IP Security Option)。大致上,这个标准草案就是利用 IP 包头的 option 空间携带一些安全信息,安全信息包括“敏感级别”和“敏感类别”。
这个标准草案写于 1992 年,二十多年过去了,它还是草案。问题在哪里呢?作者认为,它的问题主要有两个:
(1)它规定携带的安全信息是“敏感级别”和“敏感类别”,这很明显是 Bell-Lapadula 模型的产物,而 Bell-Lapadula 模型产生于 20 世纪 60 年代末 70 年代初,它的应用领域有些窄。
(2)它对安全信息本身没有相应的保护,这意味着在网络环境中任何一台计算机都有可能伪造自己发出的 IP 数据包的“敏感级别”和“敏感类别”信息。接收方无法验证接收到的网络包的“敏感级别”和“敏感类别”的正确性。
SMACK 使用了 CIPSO。对于第一个问题, SMACK 在实现中在自己的安全标签和 CIPSO标签间建立了一一对应的映射关系,可以认为 SMACK 对“敏感级别”和“敏感类别”进行了转义。对于第二个问题, SMACK 没有做任何事,只是假设在一个可信的安全的网络环境中使用 CIPSO 标签。
8.7 总结
SMACK 是打着“简单”的大旗杀入 Linux 的。分析其代码我们发现它的简单主要体现在三个地方:首先是它将主体对客体的访问方式简化了,只有读、写、执行、增加等几种;其次是它将对自身的访问控制,即作为安全机制的承载基础的标签和策略,排除出体系,将之委托于特权;最后是预制了若干标签和策略,在不自己定义标签和策略的情况下,用户也可以使用SMACK 功能。
SMACK 的主要应用领域是嵌入式系统。但是最主流的嵌入式系统 Android 并没有使用它。
8.8 参考资料
读者可参考 Documentation/security/Smack.txt。
习题
smackfs 中有一个文件 syslog,其内容是一个 SMACK 标签。拥有此标签的进程可以进行哪些 syslog 相关的操作?为什么 SMACK 要这么设计?如果不这么设计,还有什么别的方式?
