6.6 MAC策略模块体系结构

  安全策略可以直接编入内核,也可以编译成独立的内核模块,在系统引导时或者运行时使用模块加载命令加载。 策略模块通过一组预先定义好的入口函数与系统交互。通过它们,策略模块能够掌握某些系统事件的发生,并且在必要的时候影响系统的访问控制决策。 每个策略模块包含下列组成部分:

6.6.1 策略注销

  策略模块可以使用 MAC_POLICY_SET() 宏来声明。 该宏完成以下工作:为该策略命名(向系统声明该策略提供的名字);提交策略定义的 MAC 入口函数向量的地址; 按照策略的要求设置该策略的加载标志位,保证 MAC 框架将以策略所期望的方式对其进行操作; 另外,还可能请求框架为策略分配标记状态 slot 值。

static struct mac_policy_ops mac_policy_ops =
{
        .mpo_destroy = mac_policy_destroy,
        .mpo_init = mac_policy_init,
        .mpo_init_bpfdesc_label = mac_policy_init_bpfdesc_label,
        .mpo_init_cred_label = mac_policy_init_label,
/* ... */
        .mpo_check_vnode_setutimes = mac_policy_check_vnode_setutimes,
        .mpo_check_vnode_stat = mac_policy_check_vnode_stat,
        .mpo_check_vnode_write = mac_policy_check_vnode_write,
};

  如上所示,MAC 策略入口函数向量,mac_policy_ops, 将策略模块中定义的功能函数挂接到特定的入口函数地址上。 在稍后的“入口函数参考”小节中,将提供可用入口函数功能描述和原型的完整列表。 与模块注册相关的入口函数有两个:.mpo_destroy.mpo_init。 当某个策略向模块框架注册操作成功时,.mpo_init将被调用,此后其他的入口函数才能被使用。 这种特殊的设计使得策略有机会根据自己的需要,进行特定的分配和初始化操作,比如对特殊数据或锁的初始化。 卸载一个策略模块时,将调用 .mpo_destroy 用来释放策略分配的内存空间或注销其申请的锁。 目前,为了防止其他入口函数被同时调用,调用上述两个入口函数的进程必须持有 MAC 策略链表的互斥锁:这种限制将被放开, 但与此同时,将要求策略必须谨慎使用内核原语,以避免由于上锁次序或睡眠造成死锁。

  之所以向策略声明提供模块名字域,是为了能够唯一标识该模块,以便解析模块依赖关系。选择使用恰当的字符串作为名字。 在策略加载和卸载时,策略的完整字符串名字将经由内核日志显示给用户。另外,当向用户进程报告状态信息时也会包含该字符串。

6.6.2 策略标志

  在声明时提供标志参数域的机制,允许策略模块在作为模块被加载时,就自身特性向 MAC 框架提供说明。 目前,已经定义的标志有三个:

MPC_LOADTIME_FLAG_UNLOADOK

表示该策略模块可以被卸载。 如果未提供该标志,则表示该策略模块拒绝被卸载。 那些使用安全标记的状态,而又不能在运行时释放该状态的模块可能会设置该标志。

MPC_LOADTIME_FLAG_NOTLATE

表示该策略模块必须在系统引导过程时进行加载和初始化。 如果该标志被设置,那么在系统引导之后注册该模块的请求将被 MAC 框架所拒绝。 那些需要为大范围的系统对象进行安全标记初始化工作,而又不能处理含有未被正确初始化安全标记的对象的策略模块可能会设置该标志。

MPC_LOADTIME_FLAG_LABELMBUFS

表示该策略模块要求为 Mbuf 指定安全标记,并且为存储其标记所需的内存空间总是提前分配好的。 缺省情况下,MAC 框架并不会为 Mbuf 分配标记存储,除非系统中注册的策略模块中至少有一个设置了该标志。 这种做法在没有策略需要对 Mbuf 做标记时,显著地提升了系统网络性能。另外,在某些特殊环境下,可以通过设置内核选项, MAC_ALWAYS_LABEL_MBUF,强制 MAC 框架为 Mbuf 的安全标记分配存储,而不论上述标志如何设置。

注意: 那些使用了 MPC_LOADTIME_FLAG_LABELMBUFS 标志但没有设置 MPC_LOADTIME_FLAG_NOTLATE 标志的 策略模块必须能够正确地处理通过入口函数传入的值为 NULL 的 Mbuf 安全标记指针。 这是因为那些没有分配标记存储的处理中的 Mbuf 在一个需要 Mbuf 安全标记的策略模块加载之后, 其安全标记的指针将仍然为空。 如果策略在网络子系统活跃之前被加载(即,该策略不是被推迟加载的),那么所有的 Mbuf 的标记存储的分配就可以得到保证。

6.6.3 策略入口函数

  MAC 框架为注册的策略提供四种类型的入口函数: 策略注册和管理入口函数; 用于处理内核对象声明周期事件,如初始化、 创建和销毁,的入口函数; 处理该策略模块感兴趣的访问控制决策事件的入口函数; 以及用于管理对象安全标记的调用入口函数。 此外, 还有一个 mac_syscall() 入口函数, 被策略模块用于在不注册新的系统调用的前提下, 扩展内核接口。

  策略模块的编写人员除了必须清楚在进入特定入口函数之后, 哪些对象锁是可用的之外, 还应该熟知内核所采用的加锁策略。 编程人员在入口函数之内应该避免使用非叶节点锁, 并且遵循访问和修改对象时的加锁规程, 以降低导致死锁的可能性。 特别地, 程序员应该清楚, 虽然在通常情况下, 进入入口函数之后, 已经上了一些锁, 可以安全地访问对象及其安全标记, 但是这并不能保证对它们进行修改( 包括对象本身和其安全标记) 也是安全的。 相关的上锁信息,可以参考 MAC 框架入口函数的相关文档。

  策略入口函数把两个分别指向对象本身和其安全标记的指针传递给策略模块。 这样一来,即使策略并不熟悉对象内部结构,也能基于标记作出正确决策。 只有进程信任状这个对象例外:MAC 框架总是假设所有的策略模块是理解其内部结构的。

本文档和其它文档可从这里下载:ftp://ftp.FreeBSD.org/pub/FreeBSD/doc/.

如果对于FreeBSD有问题,请先阅读文档,如不能解决再联系<questions@FreeBSD.org>.
关于本文档的问题请发信联系 <doc@FreeBSD.org>.