SELinux在所有内核资源上提供增强的访问控制,在它目前的格式下,SELinux是通过LSM框架合并到内核中的。
LSM框架的思想是允许安全模块以插件形式进入内核,以便更严格地控制Linux默认的基于身份的任意访问控制(DAC)安全性。LSM在内核系统调用逻辑中提供了一套钩子(hooks),这些钩子通常放在标准Linux访问检查后、且内核调用访问真实资源之前,下图举例说明了LSM框架的基础。
SELinux作为一个LSM模块载入内核,在访问被允许之前进行额外的访问确认。LSM框架的一个分支是只有当标准Linux访问(DAC)检查成功后SELinux才会生效。
SELinux LSM模块架构如下图所示:
客体管理器负责对它们管理的资源集强制执行安全服务器的策略决定,对于内核,你可以认为客体管理器是一个内核子系统,它创建并管理内核级客体。内核客体管理器的实例包括文件系统、进程管理和System V进程间通信(IPC)。在LSM架构中,客体管理器是通过LSM钩子描绘的,这些钩子分散在内核子系统各个地方,调用SELinux LSM模块做出访问决定。然后,LSM钩子通过允许或拒绝对内核资源的访问强制执行这些决定。
SELinux架构的第三方组件是访问向量缓存(AVC),AVC缓存是安全服务器为后面的访问检查准备的,目的是为了提升访问确认的速度。AVC还为LSM钩子和内核客体管理器提供了SELinux接口。
从上面的架构中,看到了在SELinux架构中策略是如何被使用的,对于内核资源,策略被载入SELinux LSM模块安全服务器用于产生访问控制的决定,SELinux的一个优势是它的策略规则不是静态的,相反,人们(或大多数人)必须自己编写策略并确保它达到了安全目标的要求,其实使用和应用SELinux就是编写和理解策略。
策略源文件(policy.conf)的组织如下图所示:
• 类别和许可
定义了安全服务器的客体类别和每个客体类别的许可,对于内核而言,这些类别直接关系到内核源文件,通常,作为一名SELinux策略编写者,你可能永远不会修改客体类别和许可定义,将在后面的客户类别和许可章节详细描述。
• 类型强制声明
它是一个SELinux策略中最重要的一部分,也是策略编写者花费时间最多的一部分,它包括所有的类型声明和所有的TE规则(包括所有的allow,type_transition和其他TE规则)。
• 约束
约束是在TE规则许可范围之外对TE策略提供了更多的限制,例如:多级安全(MLS)策略就是约束的一种实现。
• 资源标记说明
所有客体都必须用一个“安全上下文”标记SELinux以实施访问控制,这部分告诉SELinux如何处理文件系统标记以及标记运行时创建的临时客体规则,另一个独立有关的机制叫做“文件上下文”文件,它用于在永久文件系统上初始化文件、目录和其他客体的安全上下文标记。
checkpolicy编译policy.conf(文本文件)生成policy.xx(xx为版本号,二进制文件),SELinux将通过函数security_load_policy载入policy.xx并实施访问控制。
目前SELinux策略常见的类型是单策略,它是一个由checkpolicy构造的单二进制策略文件,它直接载入内核,因为SELinux策略通常比较大而且非常复杂,与软件类似,它们是由一些比较小的叫做模块的单元构成的,有多种方法产生策略模块,最原始也是最广泛使用的方法叫做源模块法,它支持单策略的开发,源模块通过一组shell脚本、m4宏和Makefiles一起合并为文本文件,策略模块实际上是被集合到一块然后聚成一个大的源文件(即policy.conf),然后由checkpolicy进行编译,编译完成后就成为内核可读的二进制文件了。
使用源模块构造和载入SELinux策略过程如下图所示:
SELinux在内核中以一个LSM模块的形式实现,SELinux使用LSM钩子控制对内核资源的访问,访问决定由SELinux安全服务器(SS: Security Server)产生,它是SELinux LSM模块的一部分,安全策略由安全服务器通过一个具有特权的用户空间接口载入内核,AVC为访问确认提供性能增强。
SELinux框架也支持通过libselinux库对用户空间客体进行管理,内核安全服务器直接提供访问确认,而程序库包括每一个进程AVC,这个方法需要内核保留策略所有用户空间管理器以及所有用户空间客体类别。
策略服务器架构通过提供用户空间安全服务器增强支持用户空间客体管理器,用户空间安全服务器实施所有与用户空间客体有关的策略,从而减轻内核的负担,因为内核需要知道用户空间客体类别和策略规则,策略服务器对策略本身也会提供细粒度的访问控制,允许策略管理分布更广。
SELinux策略越来越大和复杂,它们必须以模块的形式进行构造,最常用的一种方法是使用源模块,所有的模块都以一个单独的模块进行构造。
第二个模块性方法提供了载入式模块,策略块可以不依赖其他模块进行构造,在系统上安装时才进行合并,在载入式模块中,基础模块的创建某种程度上与单策略类似,但基础模块可以更小,新添加的软件包将以独立的载入式模块形式安装它们的策略。
checkpolicy是策略编译器,它获取一个完整的策略源文件(policy.conf)并进行语法和语义的校验,然后创建一个二进制策略文件(policy.xx),对于载入式模块而言,checkpolicy编译基础策略模块,然后,checkmodule程序编译每一个载入式模块。