LSM实现访问控制

来源:互联网 发布:中文波斯语翻译软件 编辑:程序博客网 时间:2024/05/22 17:39
首先对LSM 进行简单介绍。虽然linux下的各位基本都知道一些,但是还要罗嗦一下。
LSM中文全称是linux安全模块。英文全称:linux security module.
LSM是一种轻量级、通用的访问控制框架,适合多种访问控制模型以内核模块的形式实现。其特点是通用、简单、高效、支持POSIX。1e能力机制。
LSM的架构图如下:

通过系统调用进入内核之后,系统首先进行传统的权限检查(传统权限检查主要是基于用户的,用户通过验证之后就可以访问资源),通过之后才会进行强制访问控制。(强制访问控制是不允许主体干涉的一种访问控制,其采用安全标识、信息分级等信息敏感性进行访问控制。并且通过比较主体的级别和资源的敏感性来确定是否允许访问。比如说系统设置A用户不允许访问文件B,即便A是文件B的所有者,访问也是受限制的。)从图上看来,LSM实现访问控制主要通过安全模块的钩子函数实现。

LSM框架主要由五部分组成:这个网上资料很多。
在关键的特定内核数据结构中加入了安全域;
在内核源码中不同的关键点处插入对安全钩子函数的调用;
提供了一个通用的安全系统调用;
提供了注册和注销函数,使得访问控制策略可以以内核模块方式实现;
将capabilities逻辑的大部分功能移植为一个可选的安全模块。

我们这里重点结合源码对LSM框架进行解释。我使用的源码是3.5.4
首先介绍安全域字段,它是一个空类型的指针,在内核中的很多内核结构中都存在,比如inode、superblock、dentry、file等等。类型字段为void * security;
那么安全域怎么和安全模块中的信息关联起来?
当安全模块加载之后,安全域中的指针便指向安全模块中的安全信息。这里以selinux为例进行介绍。
内核里面security/selinux/include/objsec.h中定义了不同对象的安全信息,格式为XXX_security_strut.

上面的文件的安全信息里面包含打开文件描述符时的安全ID、文件所有者的安全ID等等。
要联系安全模块中安全信息和安全域需要几个控制钩子函数。这些钩子函数实现了对内核关键信息的设置和管理。这里主要介绍alloc_security、free_security。
selinux里面通过实现安全信息空间分配实现关联。比如以文件安全信息为例

这里分配空间成功之后,通过file->f_security = fsec实现了关联。

撤销关联是在安全模块卸载之后调用file_free_security.


这里具体通过设置file->f_secrity为NULL,然后释放安全信息结构实现。

现在来看看内核如何实现selinux的访问控制。这里主要就是实现LSM里面的钩子函数了。LSM里面给出了结构体security_operations,里面给出了很多钩子函数,实现了相关钩子函数就可以实现访问控制了。

上面的函数就实现了file_permission钩子函数。可以看下inode结构体的获得,感受内核是通过文件->目录项->inode。该函数主要实现自己的访问控制策略就OK 了。
哪selinux来说,在获得文件安全ID之后,主要对掩码和文件打开时相关的安全信息进行检测,符合就通过访问控制。

selinux基本实现了LSM里面的所有钩子函数,待钩子函数实现后,对LSM里面钩子域进行填充就OK了。



做完以上这些还需要注册安全模块到LSM,这里注册和注销使用了register_security和unregister_security
比如selinux在注册时使用语句register_security(&selinux_ops)实现。


接下来通过上面的分析我们可以实现简单的基于LSM的访问控制。
#include <linux/kernel.h>
#include <linux/init.h>
#include <linux/module.h>
#include <linux/fs.h>
#include <linux/security.h>
#include <linux/types.h>
#include <asm/uaccess.h>
#include <linux/fcntl.h>
#include <linux/uaccess.h>
#include <linux/file.h>
#include <linux/namei.h>

static int lsm_test_file_permission(struct file *file,int mask)
{
    int path=0;
    struct file *filp;
    struct nameidata nd;

    path = path_lookup(FILENAME,LOOKUP_FOLLOW,&nd);
    
    if(!mask)
            return 0;

    if(path)
    {
        printk("lookup file failed!\n");
        return -1;
    }

    filp = filp_open("/home/yuyunchao/code/sb.c",O_RDONLY,0);
    {
    printk("open failed!\n");
    }
    return 0;
}

static struct security_operations lsm_test_security_ops = {
    .file_permission = lsm_test_file_permission,
};

static int __init lsm_file_init(void)
{    
    if(register_security(&lsm_test_security_ops)){
        printk("register error ..........\n");
        return -1;
    }
   
    printk("lsm_file init..\n ");
    return 0;
}

static void __exit lsm_file_exit(void)
{
    if(unregister_security(&lsm_test_security_ops)){
        printk("unregister error................\n");
        return ;
    }

    printk("module exit.......\n");
}

MODULE_LICENSE("GPL");
module_init(lsm_file_init);
module_exit(lsm_file_exit);



0 0
原创粉丝点击