设为首页 友情链接
在线留言 发表文章
加入收藏 广告联系

刺猬首页

| 专案技术 | 网络技术 | 图形图象 | 网络编程 | 网页设计 | 操作系统 | 服务器 | 技术白皮书 | 在线实验室 | 刺猬论坛 |
  | 数据库 | 设计赏析 | 存储频道 | 网络安全 | 私服架设 |  Solaris | 网站评估 | PC维护技巧 | 下载中心 | 博 客 |
专题: | Linux | java | cisco | 防病毒 | 刀片 | SOA | iscsi | ASP.NET | SQL | Oracle |
您现在的位置: IT公社 IT community >> 操作系统 >> FreeBSD平台 >> 教程正文 用户登录 新用户注册
专 题 栏 目
最 新 热 门
最 新 推 荐
相 关 文 章
使用FreeBSD的原因
FreeBSD启动扇区代码分析…
FreeBSD操作系统的引导
FreeBSD的boot0阶段介绍
FreeBSD操作系统的boot2…
FreeBSD系统内核对象
FreeBSD中的SYSINIT框架
调整FreeBSD的虚拟内存系…
FreeBSD 5.0硬盘安装指南
FreeBSD的Loader和内核初…
  FreeBSD 5.0的强制访问控制机制(二)         ★★★★★
FreeBSD 5.0的强制访问控制机制(二)
 

【导读】本文主要讲述FreeBSD 5.0操作系统中新增的重要安全机制,即强制访问控制机制(MAC)的使用与源代码分析,主要包括强制访问控制框架及多级安全(MLS)策略两部分内容。这一部分较系统地对MAC框架及MLS策略的源代码进行分析。

2 MAC框架与MLS策略源代码分析

与本文相关的源代码文件主要有两个,即 /usr/src/sys/kern/kern_mac.c 和 /usr/src/sys/security/mac_mls/mac_mls.c 。另外还有一些头文件如mac.h、mac_policy.h等。

2.1 MAC框架整体结构

下面是 MAC 框架的示意性结构图,当用户控制台或用户程序通过系统调用对内核对象进行访问的时候,由于内核代码中相应的位置插入了MAC框架的检查函数,于是内核就会调用MAC框架的相应检查函数来做安全性检查。MAC框架会依次调用每个挂接在MAC框架上的安全策略,以决定访问是否安全。另外,其它可能涉及到安全问题的系统事件,如初始化各种安全标记、初始化各种内核对象等,也会通知MAC框架,由它做出相应的处理。

从图中我们也可以看到,安全策略作为一个独立的KLD模块,可以独立于内核进行编译,再在使用的时候挂接到MAC框架上。要判断一次访问是否安全,MAC框架会调用所有的安全策略,只有当所有的安全策略均表示同意,MAC框架才会授权这次访问。



2.2 安全标记

安全标记是由MAC框架和各个安全策略定义的一组数据,用于描述主体或客体的安全信息,安全标记与内核描述主客体的其它数据一起存储在内核中。要实现强制访问控制,首先必须为主客体定义安全标记。不同的策略由于判断的依据不一样,可能定义的标记也不相同。作为MAC框架,当安全策略向它注册的时候,它必须把该策略使用的安全标记附加到各个内核对象上去,这样当需要调用该策略做安全性检查的时候,才能为策略提供它们自己定义和理解的安全标记。我们先给出 MAC框架与MLS策略定义的安全标记,再对之作进一步的解释。

MAC框架中安全标记的定义是这样的:



struct label {

    int l_flags;

    union {

        void    *l_ptr;

        long     l_long;

    }   l_perpolicy[MAC_MAX_POLICIES];

};

其中l_flags是一个标志,被MAC框架用来判断是否初始化了整个标记数据结构。l_perpolicy数组为每个策略定义了一个联合,这样当策略向 MAC框架注册时,它们既可以用一个long类的整数作为它们自己的安全标记,也可以使用联合中的指针指向一个它们自己定义的标记数据结构。MLS策略选择了后者。

MLS策略定义的安全标记是这们的:



struct mac_mls_element {

    u_short mme_type;

    u_short mme_level;

    u_char  mme_compartments[MAC_MLS_MAX_COMPARTMENTS >> 3];

};



struct mac_mls {

    int         mm_flags;

    struct mac_mls_element  mm_single;

    struct mac_mls_element  mm_rangelow, mm_rangehigh;

};

在mac_mls 结构中,定义了一个单一标记(mm_single)和一个标记范围(mm_rangelow,mm_rangehigh),主客体既可以使用单一标记来标识单一安全级,也可以使用标记范围来标识一个安全级范围,还可以同时使用二者。如第1章中我们使用getfmac得到的输出"mls/high"表明该文件使用的是值为"high"的单一安全标记。再比如我们使用getpmac得到的输出"mls/low(low-high)"表明进程同时使用了单一标记和标记范围。至于究竟使用的是哪种标记,由mm_flags标识。

mac_mls_element定义一个标记,它定义的标记功能很强大,既支持安全类型(mme_type变量,值为LOW、HIGH、EQUAL和UNDEFINE),也支持多达256个级别的安全级(当mme_type的值为LEVEL时,mme_level变量有效,由它定义安全级),同时还使用mme_compartments数组支持域(field),后续章节将具体讲述MLS策略是怎样使用它所定义的标记的。

当MLS策略向MAC框架注册时,它会使用MAC标记所定义的l_perpolicy数组中的一项,然后把这一项的l_ptr指针指向自己定义的mac_mls结构,这样就把自己定义的标记挂接到每个内核对象上去了。

2.3 MAC框架的实现

MAC 框架首先必须要维护一个链表,以记录所有挂接在它上面的安全策略,这个链表由下列代码定义,其意义不再详细解释,请参见kern_mac.c: static LIST_HEAD(, mac_policy_conf) mac_policy_list;

上面的代码定义一个mac_policy_conf类型的链表mac_policy_list,其类型定义如下:



    struct mac_policy_conf {

    char                *mpc_name;  /* policy name */

    char                *mpc_fullname;  /* policy full name */

    struct mac_policy_ops       *mpc_ops;   /* policy operations */

    int              mpc_loadtime_flags;    /* flags */

    int             *mpc_field_off; /* security field */

    int              mpc_runtime_flags; /* flags */

    LIST_ENTRY(mac_policy_conf)  mpc_list;  /* global list */

};

其中mpc_list成员变量是一组指针,用于形成链表。mac_policy_conf结构中最重要的一个成员是mpc_ops,我们讲过,每当有访问安全性检查时,MAC框架会把所有的检查事件如创建inode、访问inode等传递给安全策略作检查,这就是通过mpc_ops这个成员变量来进行的。也就是说,mpc_ops这个结构中记录了每个策略对各种MAC事件的处理函数。例如下面是一个来自kern_mac.c的函数:



int  mac_check_vnode_open(struct ucred *cred, struct vnode *vp, int acc_mode)

{

    int error;



    ASSERT_VOP_LOCKED(vp, "mac_check_vnode_open");



    if (!mac_enforce_fs)

        return (0);



    MAC_CHECK(check_vnode_open, cred, vp, &vp->v_label, acc_mode);

    return (error);

}

当用户试图打开一个文件时,内核就会试图打开一个vnode,在打开之前会调用这个函数,用于检查主体是否有权限打开这个vnode。MAC_CHECK宏定义如下:



#define MAC_CHECK(check, args...) do {                  \

    struct mac_policy_conf *mpc;                    \

                                    \

    error = 0;                          \

    MAC_POLICY_LIST_BUSY();                     \

    LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {         \

        if (mpc->mpc_ops->mpo_ ## check != NULL)        \

            error = error_select(               \

                mpc->mpc_ops->mpo_ ## check (args),     \

                error);                 \

    }                               \

    MAC_POLICY_LIST_UNBUSY();                   \

} while (0)

我们可以看到,代码中使用LIST_FOREACH宏来遍历安全策略链表中的每个策略,然后调用其在mpc_ops中注册的检查函数 mpo_##check。mac_policy_ops这个结构中定义了很多事件处理函数,进行细粒度的访问控制,限于篇幅,在此不一一列出。这些函数共分四类:第一类是策略本身的初始化和销毁函数;第二类是对安全标记的操作函数,包括各种内核对象的安全标记的初始化与销毁函数,以及获取与设置安全标记的接口函数;第三类是对文件系统、网络系统及进程对象的标记进行操作的事件处理函数;第四类是检查对各个内核对象的访问是否安全的检查函数。详见 mac_policy.h。

2.4 安全策略的注册

分析MLS策略,我们可以发现,安全策略向MAC框架注册是一件很简单的事情。mac_mls.c文件中花了大量篇幅定义了所有的事件处理函数,如前所述,这些函数是安全策略的核心,用于判断访问的安全性等。定义完这些函数后,在源代码的最后,把这些函数的地址填入mac_policy_ops结构中,再用一个MAC_POLICY_SET宏把mac_policy_ops结构挂接到上面提到的mac_policy_list链表中去就可以了,如下:



MAC_POLICY_SET(&mac_mls_ops, trustedbsd_mac_mls, "TrustedBSD MAC/MLS",

MPC_LOADTIME_FLAG_NOTLATE, &mac_mls_slot);

其中MPC_LOADTIME_FLAG_NOTLATE标志告诉系统这个KLD模块只能在系统初始化之前加载,这是因为MLS必须在初始化系统内核对象的时候为每个对象附加上自己定义的安全标记。具体地,系统初始化所有的内核对象之前,都会调用mac_policy_ops结构中定义的 mpo_init_XXX_label函数,MLS就是在这个函数中在该内核对象的标记里附加上自己的标记的。下面我们分析一下 MAC_POLICY_SET宏。



#define MAC_POLICY_SET(mpops, mpname, mpfullname, mpflags, privdata_wanted) \

    static struct mac_policy_conf mpname##_mac_policy_conf = {  \

        #mpname,                        \

        mpfullname,                     \

        mpops,                          \

        mpflags,                        \

        privdata_wanted,                    \

        0,                          \

    };                              \

    static moduledata_t mpname##_mod = {                \

        #mpname,                        \

        mac_policy_modevent,                    \

        &mpname##_mac_policy_conf               \

    };                              \

    MODULE_DEPEND(mpname, kernel_mac_support, 1, 1, 1);     \

    DECLARE_MODULE(mpname, mpname##_mod, SI_SUB_MAC_POLICY,     \

        SI_ORDER_MIDDLE)

逻辑也相当简单,我们来走一遍。首先定义一个mac_policy_conf结构,用于描述MLS策略,后续的操作会把这个结构加入到MAC框架所定义的 mac_policy_list列表中的。由于MLS策略本身是一个KLD模块,所以必须定义一个moduledata_t结构用于向系统注册模块,在这个结构中指明了由mac_policy_modevent函数处理模块事件,当有模块事件产生的时候将把上面定义的mac_policy_conf结构的地址传给处理函数。

mac_policy_modevent函数的核心代码如下:



case MOD_LOAD:

        if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&

            mac_late) {

            printf("mac_policy_modevent: can't load %s policy "

                "after booting\n", mpc->mpc_name);

            error = EBUSY;

            break;

        }

        error = mac_policy_register(mpc);

        break;

    case MOD_UNLOAD:

        /* Don't unregister the module if it was never registered. */

        if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)

            != 0)

            error = mac_policy_unregister(mpc);

        else

            error = 0;

        break;

当模块被LOAD的时候,会调用 mac_policy_register函数,它首先检查该模块是否已注册,如果没有,就会执行下面的代码: LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);

其中mpc为我们上面提到的mac_policy_conf结构的地址,这样到此为止,就把MLS策略添加到MAC框架的策略列表中去了。

2.5 MLS策略源代码分析

根据MLS策略,高安全级别的主体不能写低安全级别的客体,而低安全级别的主体则不能读高安全级别的客体,只有主客体的安全级别相同,才能既读又写。MLS定义了三种标记比较函数:

  1. mac_mls_dominate_single(a,b):用于检查a的单一标记的安全级是否高于b的单一标记的安全级。这个函数主要用于对内核变量的读、写、查询等事件进行安全性检查。
  2. mac_mls_single_in_range (a,b):用于检查a的单一标记的安全级是否界于b的标记范围的安全级范围之内。这个函数主要用于对改变内核对象的标记进行安全性检查,当主体改变一个客体的安全标记时,要求新旧标记的安全级别处于主体的安全级别范围之内。
  3. mac_mls_range_in_range(a,b):用于检查a的安全级范围是否落于b的安全级范围之内。这个函数主要用于改变主体安全级时,要求主体新的安全级必须落于主体当前安全级范围之内。
  4. mac_mls_equal_single(a,b):用于检查a、b的安全级是否相同。这个函数主要用于网络和设备操作。

以上函数都是调用mac_mls_dominate_element()函数来具体比较的,下面我们就分析一下这个函数,其源代码如下:



static int  mac_mls_dominate_element(struct mac_mls_element *a,

    struct mac_mls_element *b)

{

    int bit;



    switch (a->mme_type) {

    case MAC_MLS_TYPE_EQUAL:

    case MAC_MLS_TYPE_HIGH:

        return (1);



    case MAC_MLS_TYPE_LOW:

        switch (b->mme_type) {

        case MAC_MLS_TYPE_LEVEL:

        case MAC_MLS_TYPE_HIGH:

            return (0);



        case MAC_MLS_TYPE_EQUAL:

        case MAC_MLS_TYPE_LOW:

            return (1);



        default:

            panic("mac_mls_dominate_element: b->mme_type invalid");

        }



    case MAC_MLS_TYPE_LEVEL:

        switch (b->mme_type) {

        case MAC_MLS_TYPE_EQUAL:

        case MAC_MLS_TYPE_LOW:

            return (1);



        case MAC_MLS_TYPE_HIGH:

            return (0);



        case MAC_MLS_TYPE_LEVEL:

            for (bit = 1; bit <= MAC_MLS_MAX_COMPARTMENTS; bit++)

                if (!MAC_MLS_BIT_TEST(bit,

                    a->mme_compartments) &&

                    MAC_MLS_BIT_TEST(bit, b->mme_compartments))

             

[1] [2] 下一页  

频道声明:本频道的文章除部分特别声明禁止转载的专稿外,可以自由转载.但请务必注明出出处和原始作者 文章版权归本频道与文章作者所有.对于被频道转载文章的个人和网站,我们表示深深的谢意。

原始作者:佚名 录入时间:2006-10-10
信息来源:不详 投稿信箱:itqoo@126.com
教程录入:admin    责任编辑:admin 
  • 上一个教程:

  • 下一个教程:
  • 【字体: 】【发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    - 关于我们 - 合作伙伴 - 友情链接 - 广告刊登 - 投稿热线 - 在线留言版权声明联系方式 -
    IT公社版权所有 粤ICP备05127012号
    Copyrigh@2005-2006 itqoo.com.Inc All Rights Reserved  推荐分辨率 1024*768
    联系站长:E-Mail:itqoo@126.com     MSN:urchincc@hotmail.com    QQ:点击这里给我发消息
    特别感谢:亿太网络提供空间支持