Selinux详解

一.介绍

1.1百度百科

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权限更好的访问控制。

1.2概念

安全增强型 LinuxSecurity-Enhanced Linux)简称 SELinux,它是一个 Linux 内核模块,也是 Linux 的一个安全子系统

SEAndroidGoogleAndroid 4.4上正式推出的一套以SELinux为基础于核心的系统安全机制

SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则

1.3作用

SELinux 主要作用就是最大限度地减小系统中服务进程可访问的资源(最小权限原则)。

在没有使用 SELinux 的操作系统中,决定一个资源是否能被访问的因素是:某个资源是否拥有对应用户的权限(读、写、执行)。只要访问这个资源的进程符合以上的条件就可以被访问进程理论上所拥有的权限与执行它的用户的权限相同。比如,以root用户启动Browser,那么Browser就有root用户的权限,在Linux系统上能干任何事情root 用户不受任何管制,系统上任何资源都可以无限制地访问

在使用了 SELinux 的操作系统中,决定一个资源是否能被访问的因素除了上述因素之外,还需要判断每一类进程是否拥有对某一类资源的访问权限。

这样一来,即使进程是以 root 身份运行的,也需要判断这个进程的类型以及允许访问的资源类型才能决定是否允许访问某个资源。进程的活动空间也可以被压缩到最小。

即使是以 root 身份运行的服务进程,一般也只能访问到它所需要的资源。即使程序出了漏洞,影响范围也只有在其允许访问的资源范围内,安全性大大增加。

二.SELinux Policy语言介绍

Linux中一切皆文件,而操作文件的为进程。:进程能发起动作,例如它能打开文件并操作它。而文件只能被进程操作。我们这里可以看做主体对客体进行某种动作。

1. 主体(Subject)

就是想要访问文件或目录资源的进程。想要得到资源,基本流程是这样的:由用户调用命令,由命令产生进程,由进程去访问文件或目录资源。在自主访问控制系统中(Linux 默认权限中),靠权限控制的主体是用户;而在强制访问控制系统中(SELinux 中),靠策略规则控制的主体则是进程。

可以完全等同于进程。ps:为方便理解,以下将进程视为主题

2. 对象(Object)

被主体访问的资源,也称为客体。可以是文件、目录、端口、设备

ps:为方便理解,以下将目录活文件视为对象

3. 政策和规则(Policy & Rule)

Linux 系统中进程与文件的数量庞大,那么限制进程是否可以访问文件的 SELinux 规则数量就更加烦琐,如果每个规则都需要管理员手工设定,那么 SELinux 的可用性就会极低。还好我们不用手工定义规则,SELinux 默认定义了两个策略,规则都已经在这两个策略中写好了,默认只要调用策略就可以正常使用了。这两个默认策略如下:

  • -targeted:这是 SELinux 的默认策略,这个策略主要是限制网络服务的,对本机系统的限制极少。我们使用这个策略已经足够了。
  • -mls:多级安全保护策略,这个策略限制得更为严格。

系统中通常有大量的文件和进程,为了节省时间和开销,通常我们只是选择性地对某些进程进行管制,而哪些进程需要管制,要怎么管制是有政策决定的。

一套政策里面有多个规则,部分规则可以按照需求启用或禁用(以下吧该类型的规则成为布尔型规则)

规则是模块化,可扩展的。在安装新的应用程序时,应用程序可以通过添加新的模块来添加规则,用户也可以手动地增减规则

Xx域的进程(subject)是否可以对xx类的对象(object)进行xx操作   ===>Access decisions

给文件或者进程打上安全上下文标签 ===>Transition decisions

4.安全上下文(Security Context)

安全上下文是SELinux的核心,安全上下文即标签

安全上下文分为「进程安全上下文」和「文件安全上下文」

一个「进程安全上下文」一般对应多个「文件安全上下文」

进程安全上下文和文件安全上下文对应上,进程才能访问文件。它们的对应关系由政策中的规则决定。

文件安全上下文由文件创建的位置和创建文件的进程所决定,而且系统有一套默认值,用户也可以对默认值进行设定。

需要注意的是,单纯的移动文件操作并不会改变文件的安全上下文。

安全上下文有四个字段,分别用冒号隔开。形如u:object_r:init_exec:s0

•u为user的意思。SEAndroid中定义了一个SELinux用户,值为u。
•r为role的意思。role是角色之意,它是SELinux中一种比较高层次,更方便的权限管理思路,即Role Based Access Control(基于角色的访问控制,简称为RBAC)。简单点说,一个u可以属于多个role,不同的role具有不同的权限。
•init_exec,代表该文件所属的type为init_exec。如果是进程,该字段通常称为domain。MAC的基础管理思路其实不是针对上面的RBAC,而是所谓的Type Enforcement Accesc Control(简称TEAC,一般用TE表示)。对进程来说,Type就是Domain。Domain有什么权限,都需要政策和规则说明。
•S0和SELinux为了满足军用和教育行业而设计的Multi-Level Security(MLS)机制有关。简单点说,MLS将系统的进程和文件进行了分级,不同级别的资源需要对应级别的进程才能访问。
关系示意图

Selinux详解_第1张图片

解释一下这张示意图:当主体想要访问目标时,如果系统中启动了 SELinux,则主体的访问请求首先需要和 SELinux 中定义好的策略进行匹配。如果进程符合策略中定义好的规则,则允许访问,这时进程的安全上下文就可以和目标的安全上下文进行匹配;如果比较失败,则拒绝访问,并通过 AVC(Access Vector Cache,访问向量缓存,主要用于记录所有和 SELinux 相关的访问统计信息)生成拒绝访问信息。如果安全上下文匹配,则可以正常访问目标文件。当然,最终是否可以真正地访问到目标文件,还要匹配产生进程(主体)的用户是否对目标文件拥有合理的读、写、执行权限。

我们在进行 SELinux 管理的时候,一般只会修改文件或目录的安全上下文,使其和访问进程的安全上下文匹配或不匹配,用来控制进程是否可以访问文件或目录资源;而很少会去修改策略中的具体规则,因为规则实在太多了,修改起来过于复杂。不过,我们是可以人为定义规则是否生效,用以控制规则的启用与关闭的。

2.1SELinux工作模式

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)设置成打开

2.2TE介绍

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进行写操作
allowTEallow语句,表示授权。除了allow之外,还有allowauditdontauditneverallow等。netdsource type。也叫subjectdomain

proctarget type。它代表其后的file所对应的Type

file:代表Object Class。它代表能够给subject操作的一类东西。例如FileDirsocket等。在Android系统中,有一个其他Linux系统没有的Object Class,那就是Binder

write:在该类Object Class中所定义的操作

Rule Name

  rule_name一共有四种,定义如下:

  1allow:赋予某项权限;

  2allowauditaudit含义就是记录某项操作,默认情况下SELinux只记录那些权限检查失败的操作。allowaudit则使得权限检查成功的操作也被记录。注意:allowaudit只是允许记录,它和赋予权限没有关系。赋予权限必须且只能使用allow语句。

  3dontaudit:对那些权限检查失败的操作不做记录

  4neverallow:检查安全策略文件中是否有违反该项操作的allow语句;

Type

 任何情况下,都不应直接允许域访问以下通用标签;而应为一个或多个对象创建一个更具体的类型:也就是需要自定义type,然后让type继承自这些类型一个type可以关联attribute

socket_device

device

block_device

default_service

system_data_file

tmpfs

….

SELinux是基于Domain-Type的强制类型访问模型,Domain其实也是Type,它只是对进程类型的习惯称呼它只是对进程类型的习惯称呼,和Type相关的命令主要由三个

 1type:类型声明,可以直接在定义的时候,就赋予属性,type命令的完整格式为

  type type_id [attribute_id][attribute_id] ;

其中方括号中的内容为可选项,attribute_id表示与type_id相关联的属性一个type可以关联多个attribute

例如下面定义了一个名为shelltype,它和一个名为domain的属性(attribute)关联:

  type shell, domain;// shell继承 domain,也就是说shell是一个进程

  type sysfs, fs_type, sysfs_type; //sysfs 继承fs_type, sysfs_type,也就是文件

2attribute:属性,属性其实是一个特殊的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中使用的所有属性;

3typeattribute:单独给type赋予属性,在此之前需要先定义type类型,如下:

  Typeattribute system mlstrustedsubject;

 关键字           type      attibute

  特别注意:对于初学者而言,attributetype的关系最难理解,因为”attribute”这个关键字实在没取好名字,很容易产生误解:

  a)实际上,typeattribute位于同一个命名空间,即不能用type命令和attribute命令定义相同名字的东西;

  b)其实,attribute真正的意思应该是类似typegroup这样的概念。比如将type AattributeB关联起来,就是说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有两种方式:

  1common:其命令的格式为:

  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 }

  2class:除了common外,还有一种class命令也可以设置permsetclass命令可以继承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操作系统,一些原有的命令都进行了扩展,另外还增加了一些新的命令,下面让我们看看经常用到的几个命令:

1ls -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

… …

2ps -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

3chcon命令更改文件的安全属性

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

4restorecon命令当文件的安全属性在安全策略配置文件里面有定义时,使用restorecon命令,可以恢复原来的安全属性

restorecon 1.txt                                                                                                                                                         

SELinux: Loaded file_contexts

5id命令使用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

6getenforce命令得到当前SELinux的模式值

A101LV:/mnt # getenforce

Enforcing

7setenforce命令更改当前的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

EnforcingseLinux已经打开;         

PermissiveseLinux已经关闭

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:s0tclass=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 deniedlog不是一次性暴露所有权限问题,要等解决一个权限问题之后,才会暴露另外一个权限问题。比如提示缺少某个目录的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中注册回调函数对安全字段进行管理,以及执行接入控制。

Selinux详解_第2张图片

                                                  AVC架构图

Selinux详解_第3张图片

                                           完整的selinux架构图 

八.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:重启样机即可验证

你可能感兴趣的:(安卓系统开发,Selinux,策略语言,Policy语言介绍)