1、SELinux整体架构
1.1 SELinux基本概念
SELinux由NSA发布,之后,Red Hat、Network Associates、Secure Computing Corporation、Tresys Technology以及Trusted Computer Solutions等公司及研究团队都为SELinux的发展做出了重要的贡献。
SELinux本质是一个Linux内核安全模块,可在Linux系统中配置其状态。
SELinux的状态分为3种,即disabled、permissive和enforcing。
- (1)disabled状态:指在Linux系统中不启用SELinux模块的功能。
- (2)permissive状态:指在Linux系统中,SELinux模块处于Debug模式,若操作违反策略系统将对违反内容进行记录,但不影响后续操作。
- (3)enforcing状态:指在Linux系统中,SELinux模块有效,若操作违反策略,SELinux模块将无法继续工作。
SELinux涉及的重要概念如下。
(1)主体
主体是访问操作的发起者,是系统中信息流的启动者。主体通常指用户或代表用户意图的进程。
通常,主体是访问的发起者,但有时也会成为访问或受控的对象。
一个主体可以向另一个主体授权,一个进程可能会控制几个子进程,这时受控的主体或子进程就是一种客体。
(2)客体
客体相对主体而存在,通常客体是指信息的载体或从其他主体或客体接收信息的实体,即访问对象。
(3)访问控制分类
管理方式的不同形成不同的访问控制方式。
通常,访问控制方式分为两类:自主访问控制(DAC, Discretionary Access Control)和强制访问控制(MAC, Mandatory Access Control)。
(4)域
域决定了系统中进程的访问,所有进程都在域中运行。本质上**,域是一个进程允许的操作列表,决定了一个进程可以对哪些类型进行操作**。SELinux中域的概念相当于标准Linux中uid的概念。
(5)类型
类型与域的概念基本相似,但是,域是相对进程主体的概念,类型是相对目录、文件等客体的概念。类型分配给一个客体,并决定哪个主体可以访问该客体。
(6)角色
角色决定了可以使用哪些域。具体哪些角色可以使用哪些域,需要在策略配置文件中预先定义。如果在策略配置文件中定义了某个角色不可以使用某个域,在实际使用中将会被拒绝。
(7)身份
身份属于安全上下文的一部分,身份决定了本质上可以执行哪个域。
(8)安全上下文
安全上下文是对操作涉及的所有部分的属性描述,包括身份、角色、域、类型。
(9)策略
策略是规则的集合,是可以设置的规则。
策略决定一个角色的用户可以访问什么,哪个角色可以进入哪个域,哪个域可以访问哪个类型等。
1.2、SELinux内核架构
最早期的SELinux是Linux系统一个增强安全的补丁集,其后为解决每个系统对安全的细节控制不尽相同的问题,Linux安全框架(LSM, Linux Security Modules)被提出,使SELinux可作为可加载的安全模块运行。
LSM是一个底层的安全策略框架,Linux系统利用LSM管理所有的系统调用。SELinux通过LSM框架整合到Linux内核中。LSM在Linux内核中的位置如图所示。
![](https://ucc.alicdn.com/images/user-upload-01/e84c1d42befc482aa037371ff9402e65.png
当用户进程执行系统调用时,进程首先遍历Linux内核现有的逻辑寻找和分配资源,进行一些常规的错误检查,然后进行DAC自动访问控制。
自主访问控制(DAC, Discretionary Access Control)
进程仅在内核访问内部对象之前,由LSM的钩子询问LSM模块可否访问,LSM模块处理该策略问题并回答可以访问或拒绝访问。
LSM框架主要包括安全服务器、客体管理器和访问向量缓存。LSM模块架构如图所示。
安全服务器负责策略决定,安全服务器使用的策略通过策略管理接口载入。
客体管理器负责按照安全服务器的策略决定强制执行它管理的资源集。
对于内核,客体管理器可以理解为一个内核子系统,负责创建并管理内核级的客体,包括文件系统、进程管理和System V进程间通信(IPC, Inter-Process Communication)。
访问向量缓存(AVC, Access Vector Cache)提升了访问确认的速度,并为LSM钩子和内核客体管理器提供了SELinux接口。
1.3、SELinux策略语言
SELinux架构中,对于内核资源,策略通过策略管理接口载入SELinux LSM模块安全服务器中,从而决定访问控制。
SELinux的优势是其策略规则不是静态的,用户必须按照安全目标的要求自行编写策略。使用和应用SELinux本质上就是编写和执行策略的过程。
策略在策略源文件中描述。策略源文件名称为policy.conf,其文件结构包括以下几点。
- (1)类别许可,指安全服务器的客体类别,对于内核而言,类别直接关系内核源文件,**许可指针对每个客体类别的许可。**通常,SELinux策略编写者不会修改客体的类别和许可定义。
- (2)类型强制声明,包括所有的类型声明和所有的TE(Type Enforcement,类型强制)规则,是SELinux策略中最重要的部分。
- (3)约束,是TE规则许可范围之外的规则,为TE规则提供必要的限制。多级安全(MLS)是一种约束规则。
- (4)资源标记说明,指对所有客体都必须添加的一个“安全上下文”标记,是SELinux实施访问控制的前提。
SELinux根据资源标记说明处理文件系统标记以及标记运行时创建的临时客体规则。
SELinux策略大而复杂,由一个个小的策略模块构成。
策略模块的生成一般采用源模块法。源模块法支持单策略的开发,并通过一组shell脚本、m4宏和Makefile一起合并成为文本文件。
多个策略模块集合组成策略源文件,即policy.conf,策略源文件是文本文件,通过策略编译器checkpolicy编译为二进制文件policy.xx(xx为版本号),并通过策略装载函数security_load_policy载入内核且实施访问控制。
使用源模块构造和载入SELinux策略的全过程如图所示。
- 首先,通过源模块法生成一个个策略模块,策略模块聚合形成一个大的策略源文件policy.conf;
- 其次,策略源文件policy.conf通过策略编译器checkpolicy,生成可被内核读取的二进制文件policy.xx;
- 最后,policy.xx通过策略装载函数security_load_policy载入内核空间并实施访问控制。
目前,在SELinux策略上常见的是单策略组合。
2、SELinux关键技术
SELinux是基于域—类型模型(domain-type)的安全访问控制策略。对用户权限和进程权限的最小化控制,使受到攻击后即使进程权限或用户权限被夺,仍不会对整个系统造成重大影响,从而保证系统的高安全性。
技术特征上,SELinux从强制访问控制(MAC, Mandatory Access Control)、类型强制(TE, Type Enforcement)、domain迁移、**基于角色的访问控制(RBAC, Role Base Access Control)**4个方面建立一种加强的安全访问控制策略。
(1)强制访问控制MAC
强制访问控制MAC区别于自主访问控制DAC而存在,强制访问控制MAC基于策略实施对所有客体的访问,这些策略由管理员统一定制,一般用户无更改权限。
(2)类型强制TE
**类型强制TE对每个进程均赋予最小的权限。**类型强制TE的特点是对所有的进程都赋予一个domain的标签,并对所有的文件都赋予一个type的文件类型标签。Domain标签能够执行的操作由AV规则在策略中设定。
(3)domain迁移
domain迁移可防止权限升级,domain迁移的概念可用如下例子很好地说明。
众所周知,SELinux中所有的进程都在域中运行。假设进程A在Domain A内运行,进程B在Domain B内运行。若要使B程序在Domain A中执行,就需要使用domain迁移,否则运行B程序时,其默认继承Domain B。
(4)基于角色的访问控制RBAC
基于角色的访问控制RBAC,可使在SELinux中用户只被赋予最小的权限。在SELinux中,用户被划分成一些role,策略决定哪些role可以执行哪些domain。role可以迁移,但只能按照策略的规定进行迁移。
1 强制访问控制
在终端安全领域,强制访问控制(MAC)是访问控制方式之一。
通过访问控制方式操作系统可约束主体的能力、发起访问或对客体执行某种操作。
主体通常是一个进程或线程,
客体通常指文件、目录、TCP/UDP端口、共享内存段或IO设备等。
主体和客体均有自己的安全属性。当主体试图访问客体时,操作系统内核将强制执行策略(即许可规则)检查主体和客体的安全属性,并决定访问是否可以发生。任何主体对任何客体的操作都需按照策略进行检测,以决定是否允许操作。
操作系统不同的管理方式就形成了不同的访问控制方式。访问控制方式主要分为两种:自主访问控制和强制访问控制。
- (1)自主访问控制(DAC, Discretionary Access Control)
自主访问控制由主体自身对自己的客体进行管理,由主体自身决定是否将自身所拥有的客体访问权授予其他主体。在自主访问控制方式下,一个用户可以自主选择哪些用户共享他的文件。 - (2)强制访问控制(MAC, Mandatory Access Control)
强制访问控制方式将系统中的信息分密级和类进行管理,以保证每个用户只能访问那些被标记可以被他访问的信息。
在强制访问控制方式下,主体和客体都被标记了固定的安全属性(如安全级、访问权限等),在每次访问发生时,系统都将检测主体和客体的安全属性,以确定该主体是否有权限访问该客体。
强制访问控制和自主访问控制的区别在于,强制访问控制的安全策略由安全策略管理员集中控制,用户不能够重写策略;然而,自主访问控制允许用户进行决策和指定安全属性。
传统UNIX系统的用户、组和读写执行权限属于自主访问控制。
自主访问控制方式的一个根本弱点是不能识别自然人与计算机程序之间最基本的区别。因此,如果一个用户被授权允许访问,意味着其全部程序也被授权访问,那么恶意程序也将具有同样的访问权。因此,自主访问控制机制中主体容易受到来自多种多样恶意软件的攻击。
然而强制访问控制方式的多层安全模型可以避免来自恶意程序的攻击,强制访问控制将每个用户及文件都赋予一个安全访问级别,如最高秘密级(Top Secret)、秘密级(Secret)、机密级(Confidential)及无级别级(Unclassified)。
其级别高低为T>S>C>U,系统将根据主体和客体标记的访问级别来决定访问模式。访问模式包括以下4种。
- (1)下读(Read down):用户级别大于文件级别的读操作;
- (2)上写(Write up):用户级别小于文件级别的写操作;
- (3)下写(Write down):用户级别大于文件级别的写操作;
- (4)上读(Read up):用户级别小于文件级别的读操作。
通过安全访问级别和访问模式,强制访问控制方式提供了一种灵活的可配置的访问方式,避免了自主访问控制方式容易受到恶意程序攻击的劣势。
Bell-Lapadula安全模型(如图所示)旨在通过不上读和不下写的原则保证数据的安全性。
不上读是指不允许低安全级别的用户读取高敏感度的信息,不下写是指不允许高敏感度的信息写入低敏感度区域,即从安全角度,禁止信息从高安全级别流向低安全级别。
强制访问控制方式通过这种安全梯度标签来实现信息的单向流通。
Biba安全模型则旨在通过不下读和不上写的原则保证数据的完整性。不下读是指不允许高完整性的用户读取低完整性的信息,不上写是指不允许低完整性的信息写入高完整性的区域,如图所示。
在实际应用中,数据的完整性保护主要是为了避免应用程序修改某些重要的系统程序或系统数据库。
2 类型强制
类型强制(TE)的概念与访问控制有关,类型强制的执行是MAC的先决条件,执行TE规则使强制访问控制优先于自主访问控制实施,并且使TE成为一个补充的RBAC。
类型强制是对操作系统进行细粒度的控制,它不仅可以通过程序的执行来控制,还可以通过域转换或授权机制来控制。 类型强制对系统所有的进程都赋予一个domain的标签,并对所有的文件都赋予一个type的文件类型标签。domain标签能够执行的操作由AV规则在安全策略中设定。
SELinux策略就是一套声明和规则定义的类型强制TE策略。一个定义良好、严格的TE策略包括上千个TE规则,TE规则表明所有由内核暴露的允许对资源的访问权,这意味着每个进程对每个资源的访问都必须有一条以上的允许的TE访问规则。
TE规则数量很多,但所有的规则基本上都属于两类:访问向量(AV, Access Vector)规则、类型规则。
(1)访问向量规则
SELinux中没有默认的超级用户,root用户只存在于标准Linux中,即在SELinux中默认没有访问。
SELinux中的访问是由主体的类型(即域)和客体的类型使用访问向量规则allow指定的。
访问向量规则是按照对客体类别的访问许可指定其具体含义的规则,SELinux策略语言支持4类访问向量规则。
- 1)allow:表示允许主体对客体执行允许的操作。
- 2)dontaudit:表示允许主体对客体执行允许的操作且不记录其操作,即不记录违反规则的决策信息,并且违反规则后不影响操作继续运行。
- 3)auditallow:表示允许主体对客体执行允许的操作且记录其操作,即记录违反规则的访问决策信息,并且违反规则后不允许操作继续运行。
- 4)neverallow:表示不允许主体对客体执行指定的操作。
虽然上述4种规则的用途不一样,但语法相同,每个规则均需包含以下5个元素。
- ①规则名称:allow、dontaudit、auditallow和neverallow中的一种。
- ②源类型:授予访问的类型,通常是进程的域类型。
- ③目标类型:客体的类型,被授权可以访问的类型。
- ④客体类别:客体的类别。
- ⑤许可:表示主体对客体访问时允许的操作类型(也叫访问向量)。
访问向量规则语法如下。
规则名称 源类型 目标类型:客体类别 访问向量
如allow user_t bin_t : file { read execute },该规则的意思是允许任何安全上下文中具有类型user_t的进程对任何安全上下文中具有类型为bin_t的普通文件进行read和execute访问权。
(2)类型规则
类型规则是在创建客体或在运行过程中重新标记客体时指定其默认类型,它仅提供一个新的默认类型标记。
在策略语言中定义了两种类型规则。
- 1)type_transition:在创建客体时或在域转换过程中重新标记客体时指定其默认的类型。
- 2)type_change:SELinux的应用程序执行标记时指定其默认类型。
与访问向量规则一样,每条类型规则有不同的作用,但语法相同,每条类型规则都具有下列5个元素。
- ①规则名称:type_transition或type_change之一。
- ②源类型:创建或拥有进程的类型。
- ③目标类型:包含新的或重新标记的客体类型。
- ④客体类别:新创建的或重新标记的客体的类别。
- ⑤默认类型:新创建的或重新标记的客体的单个默认类型。
类型规则语法大部分和AV规则类似,不同之一在于类型规则中没有许可,不指定访问权或审核,不同之二是客体类别没有关联目标类型,相反,客体类别指的是将要被默认类型标记的客体。
类型规则语法如下:
规则名称 类型集 类型集:类别集 单个默认类型
最简单的类型规则包括源默认类型、目标默认类型和客体类别。
如type_transition user_t passwd_exec_t: process passwd_t,该规则的意思是当一个类型为user_t的进程执行类型为passwd_exec_t的文件时,进程类型将会尝试转换,除非有其他请求,否则默认转换到passwd_t。
3 domain迁移——防止权限升级
SELinux中所有的进程都在域中运行。
假设在用户环境中运行点对点下载软件azureus,当前进程的domain是fu_t。若用户考虑到安全问题,想在azureus_t域中运行此进程。当用户在terminal里用命令启动azureus,此时该进程的domain就会默认继承实行shell的fu_t。
而domain迁移可以让azureus在用户指定的azureus_t中运行,在安全方面,这种做法更可取,不会影响到fu_t。
以下是domain迁移指示的例子。
domain_auto_trans(fu_t, azureus_exec_t, azureus_t),意思是在fu_t domain里执行被标为azureus_exec_t的文件时,domain从fu_t迁移到azureus_t。
Domain迁移只有在同时满足下面的3个条件时才允许进行。
- (1)进程的新的域类型对可执行文件类型有entrypoint访问权,即allow passwd_t passwd_exec_t: file entrypoint。
- (2)进程的当前(或旧的)域类型对入口文件类型有execute访问权,即allow user_t passwd_exec_t : file {getattr execute}。
- (3)进程当前的域类型对新的域类型有transition访问权,即allow user_tpasswd_t: process transition。
4 基于角色的访问控制RBAC
在一个组织中,角色因为各种不同的功能而被创建。**特定的角色被赋予特定的权限执行某种特定的操作。**组织成员或其他系统用户被指定为特定的角色,并通过这些角色分配获得计算机权限来执行计算机特定的系统功能。
SELinux用户不直接和域类型(权限)关联,而是用户与角色关联,角色与域类型关联,从而使用户与域类型关联。 SELinux中的RBAC特性依赖并支持TE特性,通过在安全上下文中控制域类型、角色和用户的关联实现对TE策略更多的约束,也就是说,域转换受用户的角色约束,并最终约束了用户的总体权限。
RBAC的优点在于,首先简化了管理策略的复杂度:一个系统可能只有3个或4个角色,但有成千上万的用户和域类型,如果直接将域类型与用户进行关联,会导致管理非常困难,而将域类型分配给一个具有描述类型(如普通用户域类型)特权集的角色,然后将这些角色分配给用户,管理将大大简化;其次,角色仅仅是一组域类型的集合,可以方便地与用户建立联系。SELinux中的角色允许限制用户的访问**,对于任何进程,同一时间只有一个角色**(即进程安全上下文中的角色)处于活动状态。
RBAC定义了3类主要的规则。
- 规则1:角色分配,只有当主体被选择或被分配角色时,才可行使权限。
- 规则2:角色授权,主体的有效角色必须被授权给该主体。
- 规则3:权限授权,只有当某个权限被授权给主体的有效角色时,主体才可以行使该权限。
上述规则2与规则1配合,可确保用户只可承担他们被授权的角色。规则3与规则1和规则2配合,确保用户只可以行使他被授权的权限。
在RBAC中,主体、角色、权限(域类型)是一对多的关系,一个主体可以有多个角色,一个角色可以有多个主体,一个角色可以有很多权限,一个权限可以分配给多个角色,一个操作可以被分配很多权限,一个权限可以分配给多个操作。
SELinux中除了object_r外,没有内置任何其他的角色,与类型一样,角色也需在策略中进行声明,与角色有关的有4个策略语句如下。
- 角色声明语句;
- 角色allow规则;
- 角色转换规则;
- 角色控制语句。
(1)角色声明语句
角色声明语句(role)声明一个角色标识符,完整的角色声明语法如下。
role角色名称types类型集;如role user_r types user_t;roleuser_r types passwd_t。
上述语句将域类型user_t和passwd_t与角色user_r关联起来。
(2)角色allow规则
角色allow规则语法如下。
allow角色名 角色名;如allow cashier_r mgr_r,指角色为mgr_r的进程转换到一个角色名为cashier_r的进程。
(3)角色转换规则
与类型相似,程序在执行过程中角色可能发生变化。同类型转换用type_transition规则,角色转换使用role_transition规则。role_transition规则在作用和语法上与type_transition很类似,角色转换规则语法如下。
role_transition角色集 类型集 角色;
如role_transition sysadm_r http_exec_t system_r,指当一个角色为sysadm_r的进程执行一个类型为http_exec_t的文件时,SELinux会尝试将其转换为system_r角色。
(4)角色控制语句
角色控制语句(dominance)按照其他角色声明一个角色,角色控制语句可创建角色之间的层次关系,“高层角色”可能会自动继承所有与角色关联的类型,完整的角色控制语句语法如下。
dominance {role角色名称{角色集}};
如dominance { role a_r { role b_r; role c_r { role d_r; } } }。
上述语句中角色定义如下:
- d_r只有它自己的类型;
- c_r它的类型和d_r的类型;
- b_r只有它自己的类型;
- a_r它自己的类型和所有b_r, c_r和d_r的类型。
任何添加到控制语句后的高层角色的类型没有通过dominance语句继承下来,因此,在上述例子中,如果在dominance语句后面给d_r角色添加了一个类型,c_r和a_r角色并不继承该新类型。
以上就是关于SeLinux的全部内容,期待后续空了能做一个详细的展开。下一篇看看SEAndroid!
参考资料
- 移动互联网时代的智能终端安全