SELinux(Security-Enhanced Linux) 是美国国家安全局(NSA)对于强制访问控制的实现,是 Linux历史上最杰出的新安全子系统。NSA是在Linux社区的帮助下开发了一种访问控制体系,在这种访问控制体系的限制下,进程只能访问那些在他的任务中所需要文件。SELinux 默认安装在 Fedora 和 Red Hat Enterprise Linux 上,也可以作为其他发行版上容易安装的包得到。
SELinux 是 2.6 版本的 Linux 内核中提供的强制访问控制(MAC)系统。对于可用的 Linux安全模块来说,SELinux 是功能最全面,而且测试最充分的,它是在 20 年的 MAC 研究基础上建立的。SELinux 在类型强制服务器中合并了多级安全性或一种可选的多类策略,并采用了基于角色的访问控制概念。 [1]
大部分使用 SELinux 的人使用的都是 SELinux 就绪的发行版,例如 Fedora、Red Hat Enterprise Linux (RHEL)、Debian或 Centos。它们都是在内核中启用 SELinux 的,并且提供一个可定制的安全策略,还提供很多用户层的库和工具,它们都可以使用 SELinux 的功能。
SELinux是一种基于 域-类型 模型(domain-type)的强制访问控制(MAC)安全系统,它由NSA编写并设计成内核模块包含到内核中,相应的某些安全相关的应用也被打了SELinux的补丁,最后还有一个相应的安全策略。任何程序对其资源享有完全的控制权。假设某个程序打算把含有潜在重要信息的文件扔到/tmp目录下,那么在DAC情况下没人能阻止他。SELinux提供了比传统的UNIX权限更好的访问控制。
安全增强型 Linux(Security-Enhanced Linux)简称 SELinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统。
SEAndroid是Google在Android 4.4上正式推出的一套以SELinux为基础于核心的系统安全机制。
SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则)
SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则)。
在没有使用 SELinux 的操作系统中,决定一个资源是否能被访问的因素是:某个资源是否拥有对应用户的权限(读、写、执行)。只要访问这个资源的进程符合以上的条件就可以被访问。进程理论上所拥有的权限与执行它的用户的权限相同。比如,以root用户启动Browser,那么Browser就有root用户的权限,在Linux系统上能干任何事情。root 用户不受任何管制,系统上任何资源都可以无限制地访问。
在使用了 SELinux 的操作系统中,决定一个资源是否能被访问的因素除了上述因素之外,还需要判断每一类进程是否拥有对某一类资源的访问权限。
这样一来,即使进程是以 root 身份运行的,也需要判断这个进程的类型以及允许访问的资源类型才能决定是否允许访问某个资源。进程的活动空间也可以被压缩到最小。
即使是以 root 身份运行的服务进程,一般也只能访问到它所需要的资源。即使程序出了漏洞,影响范围也只有在其允许访问的资源范围内,安全性大大增加。
Linux中一切皆文件,而操作文件的为进程。:进程能发起动作,例如它能打开文件并操作它。而文件只能被进程操作。我们这里可以看做主体对客体进行某种动作。
1. 主体(Subject)
就是想要访问文件或目录资源的进程。想要得到资源,基本流程是这样的:由用户调用命令,由命令产生进程,由进程去访问文件或目录资源。在自主访问控制系统中(Linux 默认权限中),靠权限控制的主体是用户;而在强制访问控制系统中(SELinux 中),靠策略规则控制的主体则是进程。
可以完全等同于进程。ps:为方便理解,以下将进程视为主题
2. 对象(Object)
被主体访问的资源,也称为客体。可以是文件、目录、端口、设备等
ps:为方便理解,以下将目录活文件视为对象
3. 政策和规则(Policy & Rule)
Linux 系统中进程与文件的数量庞大,那么限制进程是否可以访问文件的 SELinux 规则数量就更加烦琐,如果每个规则都需要管理员手工设定,那么 SELinux 的可用性就会极低。还好我们不用手工定义规则,SELinux 默认定义了两个策略,规则都已经在这两个策略中写好了,默认只要调用策略就可以正常使用了。这两个默认策略如下:
系统中通常有大量的文件和进程,为了节省时间和开销,通常我们只是选择性地对某些进程进行管制,而哪些进程需要管制,要怎么管制是有政策决定的。
一套政策里面有多个规则,部分规则可以按照需求启用或禁用(以下吧该类型的规则成为布尔型规则)
规则是模块化,可扩展的。在安装新的应用程序时,应用程序可以通过添加新的模块来添加规则,用户也可以手动地增减规则
Xx域的进程(subject)是否可以对xx类的对象(object)进行xx操作 ===>Access decisions
给文件或者进程打上安全上下文标签 ===>Transition decisions
4.安全上下文(Security Context)
安全上下文是SELinux的核心,安全上下文即标签
安全上下文分为「进程安全上下文」和「文件安全上下文」
一个「进程安全上下文」一般对应多个「文件安全上下文」
进程安全上下文和文件安全上下文对应上,进程才能访问文件。它们的对应关系由政策中的规则决定。
文件安全上下文由文件创建的位置和创建文件的进程所决定,而且系统有一套默认值,用户也可以对默认值进行设定。
需要注意的是,单纯的移动文件操作并不会改变文件的安全上下文。
安全上下文有四个字段,分别用冒号隔开。形如:u:object_r:init_exec:s0
3种工作模式
Enforcing:强制模式。违反SELinux规则的行为将被阻止并记录到日志中。
Permissive:宽容模式。违反SELinux 规则的行为只会记录到日志中。一般为调试用。
Disabled:关闭SELinux。
SELinux 提供了 3 种工作模式:Disabled、Permissive 和 Enforcing,而每种模式都为 Linux 系统安全提供了不同的好处。
Disable工作模式(关闭模式)
在 Disable 模式中,SELinux 被关闭,默认的 DAC 访问控制方式被使用。对于那些不需要增强安全性的环境来说,该模式是非常有用的。
例如,若从你的角度看正在运行的应用程序工作正常,但是却产生了大量的 SELinux AVC 拒绝消息,最终可能会填满日志文件,从而导致系统无法使用。在这种情况下,最直接的解决方法就是禁用 SELinux,当然,你也可以在应用程序所访问的文件上设置正确的安全上下文。
需要注意的是,在禁用 SELinux 之前,需要考虑一下是否可能会在系统上再次使用 SELinux,如果决定以后将其设置为 Enforcing 或 Permissive,那么当下次重启系统时,系统将会通过一个自动 SELinux 文件重新进程标记。
关闭 SELinux 的方式也很简单,只需编辑配置文件 /etc/selinux/config,并将文本中 SELINUX= 更改为 SELINUX=disabled 即可,重启系统后,SELinux 就被禁用了。
Permissive工作模式(宽容模式)
在 Permissive 模式中,SELinux 被启用,但安全策略规则并没有被强制执行。当安全策略规则应该拒绝访问时,访问仍然被允许。然而,此时会向日志文件发送一条消息,表示该访问应该被拒绝。
SELinux Permissive 模式主要用于以下几种情况:
审核当前的 SELinux 策略规则;
测试新应用程序,看看将 SELinux 策略规则应用到这些程序时会有什么效果;
解决某一特定服务或应用程序在 SELinux 下不再正常工作的故障。
某些情况下,可使用 audit2allow 命令来读取 SELinux 审核日志并生成新的 SELinux 规则,从而有选择性地允许被拒绝的行为,而这也是一种在不禁用 SELinux 的情况下,让应用程序在 Linux 系统上工作的快速方法。
Enforcing工作模式(强制模式)
从此模式的名称就可以看出,在 Enforcing 模式中, SELinux 被启动,并强制执行所有的安全策略规则。
查看当前工作模式:getenforce
A101LV:/mnt # getenforce
Enforcing
修改工作模式:setenforce
更改当前的SELINUX的模式值,后面可以跟 enforcing,permissive 或者1,0。
安全增强型 Linux (SELinux) 是适用于 Linux 操作系统的强制访问控制 (MAC) 系统
A101LV:/mnt # setenforce 0
Enforcing:seLinux已经打开;
Permissive:seLinux已经关闭;
setenforce 0(permissive)设置成关闭,setenforce 1(enforcing)设置成打开
RBAC是基于TE的,而TE也是SELinux中最主要的部分。 type 是访问决定的主要组成部分。
SELinux中安全策略文件有自己的一套语法格式:
rule_name source_type target_type : class perm_set 最常见的allow的语句,格式一般为:
allow scontext tcontext:tclass perm_set : 允许scontext域的进程对tcontext类型的tclass对象去执行perm_set操作
例如:allow netd proc:file write:允许netd域中的进程对proc类型的file进行写操作
allow:TE的allow语句,表示授权。除了allow之外,还有allowaudit、dontaudit、neverallow等。netd:source type。也叫subject,domain。
proc:target type。它代表其后的file所对应的Type。
file:代表Object Class。它代表能够给subject操作的一类东西。例如File、Dir、socket等。在Android系统中,有一个其他Linux系统没有的Object Class,那就是Binder。
write:在该类Object Class中所定义的操作。
Rule Name:
rule_name一共有四种,定义如下:
1)allow:赋予某项权限;
2)allowaudit:audit含义就是记录某项操作,默认情况下SELinux只记录那些权限检查失败的操作。allowaudit则使得权限检查成功的操作也被记录。注意:allowaudit只是允许记录,它和赋予权限没有关系。赋予权限必须且只能使用allow语句。
3)dontaudit:对那些权限检查失败的操作不做记录;
4)neverallow:检查安全策略文件中是否有违反该项操作的allow语句;
Type
在任何情况下,都不应直接允许域访问以下通用标签;而应为一个或多个对象创建一个更具体的类型:也就是需要自定义type,然后让type继承自这些类型,一个type可以关联多个attribute;
socket_device
device
block_device
default_service
system_data_file
tmpfs
….
SELinux是基于Domain-Type的强制类型访问模型,Domain其实也是Type,它只是对进程类型的习惯称呼;它只是对进程类型的习惯称呼,和Type相关的命令主要由三个:
1)type:类型声明,可以直接在定义的时候,就赋予属性,type命令的完整格式为:
type type_id [attribute_id][attribute_id] …;
其中方括号中的内容为可选项,attribute_id表示与type_id相关联的属性,一个type可以关联多个attribute;
例如下面定义了一个名为shell的type,它和一个名为domain的属性(attribute)关联:
type shell, domain;// shell继承 domain,也就是说shell是一个进程
type sysfs, fs_type, sysfs_type; //sysfs 继承fs_type, sysfs_type,也就是文件
2)attribute:属性,属性其实是一个特殊的type,可以把属性看成是type的集合,为属性设置的策略,适用于所有与该属性相关联的type,如下:
attribute fs_type; # 声明fs_type属性
attribute sysfs_type; # 声明sysfs_type属性
# 允许init进程对sysfs_type类型集合的所有目录,文件执行relabelto操作
allow init sysfs_type:{ dir file lnk_file } relabelto;
注意:attributes文件中定义了SEAndroid中使用的所有属性;
3)typeattribute:单独给type赋予属性,在此之前需要先定义type类型,如下:
Typeattribute system mlstrustedsubject;
关键字 type attibute
特别注意:对于初学者而言,attribute和type的关系最难理解,因为”attribute”这个关键字实在没取好名字,很容易产生误解:
a)实际上,type和attribute位于同一个命名空间,即不能用type命令和attribute命令定义相同名字的东西;
b)其实,attribute真正的意思应该是类似typegroup这样的概念。比如将type A和attributeB关联起来,就是说type A属于attributeB中的一员;
Object Class
ObjectClass声明了进程要操作的对象类,security_classes文件定义了SEAndroid中用到的所有class;
class关键字用于声明objectclass类型:
# file-related classes
class file # 文件
class dir # 目录
class fd # 文件描述符
class lnk_file # 链接文件
class chr_file # 字符设备文件
class blk_file # 块设备文件
… …
# network-related classes
class socket
class tcp_socket
class udp_socket
…..
Perm Set
perm_set指的是某种ObjectClass所拥有的操作,以file类而言,就包括open,read, write等操作;和Object Class一样,SEAndroid所支持的permset的声明在access_vectors文件中;
SELinux规范中,定义permset有两种方式:
1)common:其命令的格式为:
commoncommon_name { permission_name … }
以下是file类对应的权限(permset),大部分各位都能猜出来是干什么的:
common file {
ioctl read write create getattr setattr lock relabelfrom relabelto
append unlink link rename execute swapon quotaon mounton }
2)class:除了common外,还有一种class命令也可以设置permset,class命令可以继承common定义的permset;
class命令的完整格式为:
class class_name [inherits common_name] {permission_name … }
inherits表示继承某个common定义的权限,如下:
class dir inherits file {
add_name remove_name reparent search rmdir open audit_access
execmod }
SELinux是经过安全强化的Linux操作系统,一些原有的命令都进行了扩展,另外还增加了一些新的命令,下面让我们看看经常用到的几个命令:
1)ls -Z命令查看文件,目录的安全属性:
root@xxx:/ # ls –Z
drwxr-x--x root sdcard_r u:object_r:rootfs:s0 storage
dr-xr-xr-x root root u:object_r:sysfs:s0 sys
drwxr-xr-x root root u:object_r:system_file:s0 system
… …
2)ps -Z命令查看进程的安全属性:
root@xxx:/ # ls -Z
u:r:rild:s0 radio 272 1 /system/bin/rild
u:r:drmserver:s0 drm 273 1 /system/bin/drmserver
u:r:mediaserver:s0 这个还是 media 274 1 /system/bin/mediaserver
u:r:installd:s0 install 283 1 /system/bin/installd
3)chcon命令更改文件的安全属性
A101LV:/mnt # ls -Z 1.txt
u:object_r:appdomain_tmpfs:s0 1.txt
chcon u:object_r:storage_file:s0 1.txt
A101LV:/mnt # ls -Z 1.txt
u:object_r:storage_file:s0 1.txt
4)restorecon命令当文件的安全属性在安全策略配置文件里面有定义时,使用restorecon命令,可以恢复原来的安全属性
restorecon 1.txt
SELinux: Loaded file_contexts
5)id命令使用id命令,能确认自己的SecurityContext
A101LV:/mnt # id
uid=0(root) gid=0(root) groups=0(root),1004(input),1007(log),1011(adb),1015(sdcard_rw),1028(sdcard_r),3001(net_bt_admin),3002(net_bt),3003(inet),3006(net_bw_stats),3009(readproc),3011(uhid) context=u:r:su:s0
6)getenforce命令得到当前SELinux的模式值
A101LV:/mnt # getenforce
Enforcing
7)setenforce命令更改当前的SELINUX的模式值,后面可以跟 enforcing,permissive 或者1,0。
安全增强型 Linux (SELinux) 是适用于 Linux 操作系统的强制访问控制 (MAC) 系统
A101LV:/mnt # setenforce 0
A101LV:/mnt # getenforce
Permissive
A101LV:/mnt # setenforce 1
A101LV:/mnt # getenforce
Enforcing
Enforcing:seLinux已经打开;
Permissive:seLinux已经关闭;
8)查看selinux权限问题
adb shell dmesg -c |grep avc
audit: type=1400 audit(16149.949:4): avc: denied { write } for pid=399 comm="init" name="vendor" dev="tmpfs" ino=988 scontext=u:r:vendor_init:s0 tcontext=u:object_r:tmpfs:s0 tclass=dir permissive=0
了解selinux基本概念后,这里简单介绍一些权限的添加方法。
进程类型定义,vendor_init.te文件中:
type vendor_init, domain, mlstrustedsubject;
给新建对象打上label
如在file.te里面添加:
type tmpfs, fs_type;
….
例如:
audit: type=1400 audit(16149.949:4): avc: denied { write } for pid=399 comm="init" name="vendor" dev="tmpfs" ino=988 scontext=u:r:vendor_init:s0 tcontext=u:object_r:tmpfs:s0 tclass=dir permissive=0
可以解读为scontext=u:r:vendor_init:s0 的主体(进程)对tcontext=u:object_r:tmpfs:s0的tclass=dir对象缺少{ write } 权限。
为了解决这个权限问题,我们添加vendor_init.te文件,内容为:
allow vendor_init tmpfs:dir { write };
注意,解决了这个问题后,可能会引入新的权限问题,我们再根据新的avc去添加。
修改之后,怎么快速验证?
mmm system/sepolicy && make sepolicy
生成out目录下,注意有两个目录:
system/etc/sepolicy---Android 原生的,建议不动。如果修改,会影响CTS
vendor/etc/sepolicy---第三方厂家修改。
特别说明:
system/sepolicy/Android.mk中定义了一些属性
BOARD_SEPOLICY_DIRS ##此宏涉及到的目录,会编译到vendor/etc/sepolicy下
PLAT_PUBLIC_POLICY ##此宏涉及到的目录,会当成system/sepolicy/public
PLAT_PRIVATE_POLICY##此宏涉及到的目录,会当成system/sepolicy/private
另外,单独编译后,会发现都会有对应的生成目录:out/target/product/xxx/vendor/etc/selinux/
Allow语句会在vendor_sepolicy.cil文件中,最后push到板子/vendor/etc/selinux下
audit(1599450077.672:2048): avc: denied { open } for comm=".android.camera" path="/dev/__properties__/u:object_r:vendor_default_prop:s0" dev="tmpfs" ino=297 scontext=u:r:platform_app:s0:c512,c768 tcontext=u:object_r:vendor_default_prop:s0 tclass=file permissive=0 app=com.android.camera
某个scontext对某个tclass类型的tcontext缺乏某个权限,我们需要允许这个权限:
我们的log重新排列一下,
scontext = u:r:platform_app
tcontex t= u:object_r:vendor_default_pro:s0
tclass = file
avc: denied { open }
得到万能套用公式如下:
在scontext所指的.te文件(例如platform_app.te)中加入类似如下allowe内容:
allow platform_app vendor_default_pro:file open;
1. 有时候avc denied的log不是一次性暴露所有权限问题,要等解决一个权限问题之后,才会暴露另外一个权限问题。比如提示缺少某个目录的read权限,加入read之后,才显示缺少write权限,要一次次一次试,一次一次加,时间成本极大。
针对dir缺少的任何权限,建议赋予create_dir_perms,基本涵盖对dir的所有权限,比如:
{ open search write read rename create rmdir getattr }等等。
针对file缺少的任何权限,建议赋予rwx_file_perms,基本涵盖对file的所有权限,比如:
包含{ open read write open execute getattr create ioctl }等等。
更多内容请参考external/sepolicy/global_macros来了解更多权限声明。
2. 要加入的权限很多时,可以用中括号,比如:
allow engsetmacaddr vfat:dir { search write add_name create};
3. 修改A位置的.te文件遇到编译错误怎么办?
(首先请排除拼写错误)说明此项权限是SELinux明确禁止的,也是Google CTS禁止的,如果产品不需要过CTS,可以修改。一般来说,编译出错的log会提示相关哪个文件哪一行出错,文件位置一定会在B里的.te文件。比如B规定了以下neverallow,
neverallow system_server sdcard_type:dir { open read write };
那么system_server是不能拥有这些权限的,如果赋予这些权限就编译报错,解决方法是根据编译错误提示的行号,把这一句注释掉即可。
4. ubuntu下面自动转换avc语句为selinux语句
grep -r avc sdcard.log > avc.log ; audit2allow -i avc.log
5. genfscon的语法是:
genfscon fs_type pathprefix [-file_type] context
把/proc/mtk_demo/demo_file文件的安全上下文设置成demo_context
genfscon proc /mtk_demo/demo_file u:object_r:demo_context:s0
6.内核模块
最终SELinux的实现是依赖于Linux提供的Linux Security Module框架简称为LSM。其实LSM的名字并不是特别准确,因为他并不是Linux模块,而是一些列的hook,同样也不提供任何的安全机制。LSM的的重要目标是提供对linux接入控制模块的支持。
Linux Security Module Framework
LSM 在内核数据结构中增加了安全字段,并且在重要的内核代码(系统调用)中增加了hook。可以在hook中注册回调函数对安全字段进行管理,以及执行接入控制。
AVC架构图
完整的selinux架构图
1:编译sepolicy模块
mmm system/sepolicy/
2:push selinux相关文件
adb push xxx/vendor/etc/selinux /vendor/etc/
adb push xxx/odm/etc/selinux /odm/etc/
adb push xxx/system/etc/selinux /system/etc/
3:重启样机即可验证