函数audit_expand扩展在审计缓冲区中的套接字缓冲区,扩展成功,返回可用的空间大小,扩展失败返回0,表示没有空间。参数ab表示审计缓冲区的指针,参数extra表示加到套接字缓冲区skb尾部的缓冲区空间大小。函数audit_expand列出如下:static inline int audit_expand(struct audit_buffer *ab, int extra){struct sk_buff *skb = ab->skbint ret = pskb_expand_head(skb, skb_headroom(skb), extra, ab->gfp_mask)if (ret <0) {audit_log_lost("out of memory in audit_expand")return 0}return skb_tailroom(skb)//返回可用的缓冲区空间大小}3.函数audit_log_end当进程完成了将审计记录写入审计缓冲区的 *** 作时,它调用函数audit_log_end将套接字缓冲区中的审计记录数据发送给用户空间后台进程,由后台进程写入到log文件。如果审计后台进程存在,使用netlink机制传输数据,由审计后台将套接字缓冲区中的审计记录数据写入审计文件audit.log中;如果审计后台不存在,使用函数printk记录数据,然后由日志后台进程将数据写入到日志文件中。当数据发送完成后,函数audit_log_end唤醒等待队列kauditd_wait。有些进程因为审计套接字缓冲区链表上的缓冲区数量超过上限而在队列kauditd_wait等待,当其他进程发送了数据时,应唤醒这些等待进程。函数audit_log_end列出如下:void audit_log_end(struct audit_buffer *ab){if (!ab)returnif (!audit_rate_check()) { //检查审计系统的传输速度,如果netlink机制传输速度超过上限,则返回错误audit_log_lost("rate limit exceeded")} else {if (audit_pid) { //如果审计后台的进程ID存在,使用netlink机制传输数据struct nlmsghdr *nlh = (struct nlmsghdr *)ab->skb->datanlh->nlmsg_len = ab->skb->len - NLMSG_SPACE(0)skb_queue_tail(&audit_skb_queue, ab->skb)ab->skb = NULLwake_up_interruptible(&kauditd_wait) //发送了数据,唤醒等待队列} else { //使用printk记录数据printk(KERN_NOTICE "%s\n", ab->skb->data + NLMSG_SPACE(0))}}audit_buffer_free(ab)}
LSM是Linux Secrity Module的简称,即linux安全模块。其是一种轻量级通用访问控制框架,适合于多种访问控制模型在它上面以内核可加载模块的形实现。用户可以根据自己的需求选择合适的安全模块加载到内核上实现。LSM设计思想:LSM的设计思想:在最少改变内核代码的情况下,提供一个能够成功实现强制访问控制模块需要的结构或者接口。LSM避免了利用如在systrace系统调用中的出现过的系统调用干预,因为它不能扩展到多处理器内核,并且它受制于参数替换攻击。还有LSM在设计时做了两点考虑:对不使用的人来说尽量少引入麻烦,对使用的人来说要带来效率。以Linus Torvalds为代表的内核开发人员对Linux安全模块(LSM)提出了三点要求:1、真正的通用,当使用一个不同的安全模型的时候,只需要加载一个不同的内核模块。2、概念上简单,对Linux内核影响最小,高效,并且。3、能够支持现存的POSIX.1e capabilities逻辑,作为一个可选的安全模块。还有,针对linux上提出的各种不同的Linux安全增强系统对Linux安全模块(LSM)提出的要求是:能够允许他们以可加载内核模块的形式重新实现其安全功能,并且不会在安全性方面带来明显的损失,也不会带来额外的系统开销。LSM框架结构:LSM框架主要由五部分构成:1、在特定的内核数据结构中加入安全域。2、在内核源代码中不同的关键点插入对安全钩子函数的调用。3、加入一个通用的安全系统调用。4、提供了函数允许内核模块注册为安全模块或者注销。5、5、将capabilities逻辑的大部分移植为一个可选的安全模块。安全域是一个void*类型的指针,它使得安全模块把安全信息和内核内部对象联系起来。下面列出被修改加入了安全域的内核数据结构,以及各自所代表的内核内部对象:task_struct结构:代表任务(进程)linux_binprm结构:代表程序super_block结构:代表文件系统inode结构:代表管道,文件,或者Socket套接字file结构:代表打开的文件sk_buff结构:代表网络缓冲区(包)net_device结构:代表网络设备kern_ipc_perm结构:代表Semaphore信号,共享内存段,或者消息队列msg_msg:代表单个的消息Linux安全模块(LSM)提供了两类对安全钩子函数的调用:一类管理内核对象的安全域,另一类仲裁对这些内核对象的访问。对安全钩子函数的调用通过钩子来实现,钩子是全局表security_ops中的函数指针,这个全局表的类型是security_operations结构,这个结构定义在include/linux/security.h这个头文件中。LSM接口的核心是security_ops,当系统启动时,他们被初始化为传统的DAC策略。传统DAC访问控制是指控制系统中的主体(如进程)对系统中的客体(如文件目录、文件)的访问(读、写和执行等)。自主访问控制DAC 是指主体(进程,用户)对客体(文件、目录、特殊设备文件、IPC等)的访问权限是由客体的属主或超级用户决定的,而且此权限一旦确定,将作为以后判断主体对客体是否有访问权限的依据。在加载安全模块时,我们必需先对模块进行注册,我们可以使用register_security()函数向LSM注册一个安全模块。在我们的模块被加载成功后,就可以进行访问控制 *** 作。如果此时还有一个安全模块要使用register_security()函数进行加载,则会出现错误,直到使用unregister_security()函数向框架注销后,下一个模块才可以载入。当然LSM还提供了mod_reg_security()函数和mod_unreg_security()函数,可以连续注册多个安全模块。如果有其他后来的模块需要载入,可以通过mod_reg_security()向第一个模块注册,形成支持不同策略的模块栈。注:以上出现的函数均基于2.6.22以前的版本,对于后续的版本,出现了register_security()函数未被导出或者取消掉了unregister_security()函数。LSM执行过程:根据下图的执行步骤:用户在执行系统调用时,先通过原有的内核接口依次执行功能性的错误检查,接着进行传统的DAC检查,并在即将访问内核的内部对象之前,通过LSM钩子函数调用LSM。LSM再调用具体的访问控制策略来决定访问的合法性。图三显示了LSM钩子的调用:图三:基于LSM的内核对象访问过程Lilinux安全模块(LSM)主要支持"限制型"的访问控制决策:当Linux内核授予文件或目录访问权限时,Linux安全模块(LSM)可能会拒绝,而当 Linux内核拒绝访问时,可以跳过LSM。========使用LSM实现自己的访问控制首先对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=0struct file *filpstruct nameidata ndpath = path_lookup(FILENAME,LOOKUP_FOLLOW,&nd)if(!mask)return 0if(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)========LSM(Linux Security Module)应用方法(简单例子)LSM在内核中很多地方已经插入了hook函数,并且在security.c函数中声明了security_ops结构,要实现你自己的安全模块,只需要定义你自己的struct security_operations,并且用register_security注册即可,下面举个简单例子:test.c代码如下:/** Test Linux Security Module** Author: penghuan <penghuanmail@126.com>** Copyright (C) 2010 UbuntuKylin, Ltd.** This program is free softwareyou can redistribute it and/or modify* it under the terms of the GNU General Public License version 2, as* published by the Free Software Foundation.**/#include <linux/security.h>#include <linux/sysctl.h>#include <linux/ptrace.h>#include <linux/prctl.h>#include <linux/ratelimit.h>#include <linux/workqueue.h>#include <linux/file.h>#include <linux/fs.h>#include <linux/dcache.h>#include <linux/path.h>int test_file_permission(struct file *file, int mask){char *name = file->f_path.dentry->d_name.nameif(!strcmp(name, "test.txt")){file->f_flags |= O_RDONLYprintk("you can have your control code here!\n")}return 0}static struct security_operations test_security_ops = {.name = "test",.file_permission = test_file_permission,}static __init int test_init(void){printk("enter test init!\n")printk(KERN_INFO "Test: becoming......\n")if (register_security(&test_security_ops))panic("Test: kernel registration failed.\n")return 0}security_initcall(test_init)将该文件以模块的形式放到security/下编译进内核,启用新的内核后,当你 *** 作文件test.txt时,通过dmesg命令就能再终端看到”you can have your control code here!“输出所以一般的做法是:定义你自己的struct security_operations,实现你自己的hook函数,具体有哪些hook函数可以查询include/linux/security.h文件,然后调用register_security来用你的test_security_ops初始化全局的security_ops指针楼主,我刚开始研究LSM,但网上资料太少,您这个代码,我编译成ko文件老是有警告,并且insmod时,说Unknown symbol register_security。我最近看了看内核模块变成,没有对内核进行太深入的了解。不知能否把LSM的实验步骤给出的再详细点,谢谢。你需要把代码编进内核是需要把那段源码拷到内核目录下,然后重新编译内核?。。没有不编译内核的方法吗?。。直接按照模块进行编译。另外那个test.txt放在哪个文件夹里?。是需要把那段源码拷到内核目录下,然后重新编译内核?。。没有不编译内核的方法吗?。。直接按照模块进行 ...是的,你去网上找下怎么把模块编进内核,lsm模块不能以模块方式加载,涉及安全;test.txt是测试文件,当你把代码编进内核后,用新内核启动,然后 *** 作test.txt文件,就会有输出,test.txt随便放哪里楼主,您好,我刚开始学习lsm模块,把您的模块编译进内核,新的内核加载后,register_security总是失败,请问下可能是什么原因导致的。我的内核版本是3.13.11。register_security的返回值是-11========LSM在Linux中的实现方式LSM(Linux Secure Model)一种轻量级访问控制机制.其实现方式有如在系统调用中加入一个后门....方式如下:static struct file *__dentry_open(struct dentry *dentry, struct vfsmount *mnt,struct file *f,int (*open)(struct inode *, struct file *),const struct cred *cred){struct inode *inodeint error...............................................................error = security_dentry_open(f, cred) //LSM机制实现方式,在此加入了一个LSM函数.//security_dentry_open的实现如下,相当于一个接口,对一个函数指针再//封装一下.//只返回是与否,这样的控制信息.if (error)goto cleanup_all................................................................return fcleanup_all:.................................................................return ERR_PTR(error)}//========简单封装一个指针结构体===========================int security_dentry_open(struct file *file, const struct cred *cred){int retret = security_ops->dentry_open(file, cred)if (ret)return retreturn fsnotify_perm(file, MAY_OPEN)}========利用LSM实现更安全的linuxLSM的全称是Linux Security Modules,它是linux内核中用来支持更灵活的安全策略的一个底层框架,虽然听起来比较复杂,但是可以就把它理解成一组安插在linux内核的钩子函数和一些预留的被称为安全域的数据结构,下面先说说这个框架的由来吧。linux本身的机制就保证了linux拥有更好的安全机制,但是在这个机制下面,还是隐藏了许多的问题:1、权限粒度太大。用过linux的人应该对0644这样的访问权限设置不陌生,它对能够 *** 作这个文件的用户做了限制,但是这个只是限制到了组,而没有更进一步的细分,当然,如果LSM只是用来限制这个的话,那么也就太没意思了,因为实现文件更细的控制粒度,ACL就能够很出色的完成,顺便提一下,ACL有一个分配的限制,如果哪位朋友需要用ACL进行粒度更细的访问权限控制的话,可能需要注意一下这方面的东西。2、root用户的权限太大。在linux中,root用户就是至高无上的,他拥有对机器的完全控制权限,可以做他想做的一切事情。但是很多时候,我们可能并不希望有root有这么大的权限,比如在现在比较流行的云存储中,用户肯定不希望服务提供商能够随意访问我们的文件,那么这个时候,就需要对root用户进行一定的设置了。由于这些问题的存在,所以出现了像SE Linux(Securiy Enhanced Linux )这样的增强补丁。但是每个系统对于具体安全细节的控制不尽相同, 所以Linus Tovalds 提出应该要有一个 Linux 内核所能接受的安全框架来支持这些安全策略,这个安全框架应该提供包含内核数据结构中的透明安全域以及用来控制、维护安全域 *** 作的安全钩子,于是就有了LSM。LSM在内核中的位置,可以用下图来表示:当用户态程序调用某些 *** 作系统提供的函数的时候,比如read()函数,其会对应于内核中的一个系统调用,然后该首先会进行一些常规的错误检测,接着进行DAC(Discretionary Access Control)检测,再接着它会进行LSM检测。从上图中能够看出来,LSM其实是一个非常底层的安全策略框架,利用LSM,可以接管所有的系统调用,这样,我们就能对包括root在内的所有用户的权限进行控制,并且实现粒度更细的访问权限控制。当系统初始化的时候,LSM就是一个空的框架,它不提供任何的检测,其所做的全部工作几乎就是返回0,当然,有些不带返回值的函数除外。而我们则可以针对自己特定的需求来编写LSM,然后将我们编写的LSM钩子函数,通过其数据结构struct security_operations注册到系统中去,这样,我们的LSM检测就开始起作用了。更多信息可参考《Linux就该这么学》欢迎分享,转载请注明来源:内存溢出
评论列表(0条)