本文为CoryXie原创译文,转载及有任何问题请联系cory.xie#gmail.com。
本文分析FreeBSD 10.0【 http://xrefs.info/freebsd-10.0/ 】的MAC Framework的整体流程。
在【/usr/src/sys/security/mac/mac_framework.c】中有如下一段注释,描述了MAC Framework实现的三大功能:
也就是说,1)可以按照不同的安全保护策略,实现不同的策略模块,并通过在<security/mac/mac_policy.h> 中定义的接口向MAC Framework注册;2)各内核子系统可以通过<security/mac/mac_framework.h>中定义的与各子系统相关的接口来请求MAC Framework进行安全判定;3)MAC Framework在接收到安全判定请求时,会循序调用已经注册的各个策略模块的判定函数,实现安全判定;4)提供了用户空间接口用于设置受控资源对象的安全属性(label state)。
MAC代码布局
整体而言,FreeBSD的MAC相关代码位于【/usr/src/sys/security/】目录下面。其中mac目录是框架本身,audit目录是负责安全审计的模块(Common Criteria要求),其他目录是实现不同的MAC策略。
其中,【/usr/src/sys/security/mac/】目录如下:
MAC框架启动
通过查看【/usr/src/sys/security/mac/mac_framework.c】模块的SYSINIT()找到模块的入口如下:
也就是说,MAC策略模块分为动态策略模块(链入mac_policy_list且在遍历时需上锁)和静态策略模块(链入mac_static_policy_list且在遍历时无需上锁)。
MAC策略注册
MAC策略是通过mac_policy_register()向MAC Framework注册的。
该mac_policy_register()函数的前面部分:
函数mac_policy_register()的第二部分如下:
全局变量mac_slot_offsets_free类型为int,限定了最多只支持32个不同策略,下面的注释解释了原因。因为MAC Framework维护了一个bitmask,每个注册的MAC策略在该bitmask上都对应一个位,并且卸载时该位不会被回收,从而能保证这些槽位不会被重用。这一点是跟Label相关的设计。
在调用mac_policy_xunlock()解锁并返回之前,对mac_policy_update()的调用很关键。
MAC策略更新
下面是mac_policy_getlabeled()函数的代码:
而对这个函数的调用在VFS的getnewvnode()函数中:
MAC标签分配
这里的mac_labelzone_alloc()仅仅是从一个专用于label的UMA zone中分配一块内存(struct label)。
实际的对这个label的初始化在代码MAC_POLICY_PERFORM(vnode_init_label, label)中完成。MAC_POLICY_PERFORM()的定义如下:
我们以mac_biba.c中实现的biba_init_label()函数来看看具体的某个MAC策略是如何初始化一个label的(实际上应该是初始化该label对应于该MAC策略的部分)。
显然,这里的SLOT_SET()是要将biba_alloc()返回的指针设置到label中l_perpolicy[]数组对应于biba_slot的位置。
而这个biba_slot变量来源于下面的MAC_POLICY_SET():
还记得前面在分析mac_policy_register()时有段代码是得到这个注册的MAC策略对应的槽位slot号么?
MAC策略检查
例如,mac_vnode_check_open()函数的调用位置如下:
其中,【/usr/src/sys/kern/vfs_vnops.c】中的调用如下:
那么回到mac_vnode_check_open(),我们看看具体是如何检查的: