Linux权限控制:selinux详解及调试技巧

1,117 阅读8分钟

背景

Linux的默认访问控制是DAC(Discretionary Access Control),自主访问控制,其特点是资源的拥有者可以对资源进行任意的操作,如读、写、执行等。其实现逻辑是进程准备操作资源时,Linux内核会比较进程的UID和GID,如果权限允许,则可以进行相应的操作。这种方式的问题是,如果一个进程以root身份运行,即意味着它能够对系统的任何资源进行操作,而不被限制。如果我们安装了有漏洞或有恶意的软件,系统存在安全问题。由此,我们需要另外一种安全访问控制机制MAC(Mandatory Access Control),强制访问控制。selinux就是MAC的一种,Android也采用这种增强的安全访问控制机制。

SELinux

Security Enhanced Linux(SELinux) 为Linux 提供了一种增强的安全机制,其本质就是回答了一个“Subject是否可以对Object做Action?”的问题,例如进程是否可以读写persist分区某文件夹下的文件?其中进程就是Subject而文件就是Object,写入对应的就是Action。 与DAC的区别是,MAC使用文件的方式直接规定进程对资源的操作权限,且配置文件被编译到rom中,通过指令或程序无法对sepolicy进行修改。

理解selinux的核心思想

  • Subject:在SELinux里指的就是进程,也就是操作的主体。
  • Object: 操作的目标对象,例如文件
  • Action: 对Object做的动作,例如 读取、写入或者执行等等
  • Context: Subject和Object都有属于自己的Context,也可以称作为Label。Context由几个部分组成,分别是SELinux User、SELinux Role、SELinux Type、SELinux Level

用户程序执行的系统调用(例如读取文件),都要被SELinux依据安全策略进行检查。如果安全策略允许操作,则继续,否则将会抛出错误信息给应用程序。SELinux决策的同时还需要Subject和Object的Context信息,确定所属的User、Role和Type等信息,以此查询对应的安全策略进行决策

SELinux 依靠标签来匹配操作和规则。标签用于决定允许的事项,系统中,无论是文件、进程,还是套接字等都拥有标签。SELinux 在做决定时需参照两点: 1)这些对象分配的标签 2)定义这些对象如何交互的规则

标签

标签在selinux中指明了subject或object的一些属性,其格式如下

user:role:type:mls_level
user:
    system_u:表示系统程序
    user_u:代表一般使用者账号相关的身份
role:
    object_r:代表文件或目录等文件资源
    system_r:代表的是进程
type:
    type在文件资源上是类型
    type在进程则成为领域(domain)
mls_level:
    级别,仅在策略支持MCS或者MLS时才显示;
    单个安全级别,其中包含敏感级别和零个或多个类别(例如s0:c0,s7:c10.c15)等
    由两个安全级别组成的范围,两个安全级别之间使用连字符分开
#Android中的MLS的sensitivity level只有一个,即s0

标签由*.xxx_contexts文件定义

#flashlight file
/sys/devices/platform/soc/c42d000.qcom,spmi/spmi-0/0-01/c42d000.qcom,spmi:qcom,pm8550@1:qcom,flash_led@ee00/leds/led:torch_[0-3](/.*)       u:object_r:sysfs_led_torch:s0

查看标签

  1. 查看进程的标签 img_v2_932523f5-696f-47c9-a37d-cb777d30767l.png 以camera的provider为例,u:r:hal_camera_default:s0为其标签;
  2. 查看文件的标签 ls -Z
  3. 可以通过chcon指令来修改标签,chcon lable files

规则

allow domains types:classes permissions;
domains:一个进程或一组进程的标签,也成为域类型,它只是进程的类型
Type:一个对象或一组对象的标签
Class:要访问的对象的类型,如文件、套接字等
Permission:要执行的操作,如write,read,exec等

规则写在.te文件中

#read/write flashlight file
allow system_app sysfs_leds:dir { search }; //允许system_app标签下的进程在sysfs_leds标签下对文件夹进行搜索
allow system_app sysfs_led_torch:dir    r_dir_perms;//读文件夹
allow system_app sysfs_led_torch:file   rw_file_perms;//读写文件
allow system_app sysfs_flashlight:file  rw_file_perms;//读写文件

SELinux的运行模式

三个运行模式:

  1. Disable:禁用SELinux,不会给任何资源打lable;将SELinux重新启用时,会给资源重新打lable
  2. Permissive:如果有违反SELinux的操作,SELinux会向log中写入拒绝信息,但不会正真拒绝操作
  3. Enforcing:SELinux的正常状态,会实际禁用违反策略的操作

更改运行模式

//查看当前SELinux运行模式
adb shell getenforce
//设置为Permissive
adb shell setenforce 0
//设置为Enforcing
adb shell setenforce 1

SELinux Policy写法

安全策略文件,selinux的核心,编写安全策略文件的语言被称为SELinux Policy语言。 MAC的基本管理单位是TEAC(Type Enforcement Access Control)

RULE_VARIANT SOURCE_TYPES TARGET_TYPES:CLASSES PERMISSION
如:
allow system_app sysfs_leds:dir { search };

RULE_VARIANT
allow:赋予某项权限。 allowaudit:audit含义就是记录某项操作。默认情况下是SELinux只记录那些权限检查失败的操作。allowaudit则使得权限检查成功的操作也被记录。注意,allowaudit只是允许记录,它和赋予权限没关系。赋予权限必须且只能使用allow语句。
dontaudit:对那些权限检查失败的操作不做记录。
neverallow:用来检查安全策略文件中是否有违反该项规则的allow语句。
get_prop
get_prop($1,$2)添加TE策略,使得1可以get标签类型1可以get标签类型2对应的文件/进程
set_prop
set_prop($1,$2)添加TE策略,使得1可以set标签类型1可以set标签类型2对应的文件/进程

SOURCE_TYPES&TARGET_TYPES

type
类型声明语法:type 类型名称 [alias 别名集 ] 属性集 • 别名集 如果有多个别名,可在一对大括号中用空 格将各个别名区别开来,如:alias {aliasa_t aliasb_t} 。
• 属性集 如果同时指定多个属性标识符,属性之间使用逗号进行分隔,如:type bin_t,file_type,exec_type;

PERMISSIONS
指的是classes所被允许的操作,例如,以file为例,其PERMISSIONS就包含read,write,create,open和rename等。

MLS
TE,RBAC基本满足了“平等社会”条件下的权限管理,但它无法反映现实社会中等级的概念。为此,SELinux又添加了一种新的权限管理方法,即Multi-Lever Security,多等级安全。
多等级安全信息也被添加到SContext(也就是前面说的标签)中。所以,在MLS启用的情况下(注意,你可以控制SELinux启用MLS还是不启用MLS),完整的SContext由:

  • MLS未启用前:user_u:role_r:type_t。
  • MLS启用后:user:role:type:sensitivity[:category,…]- sensitivity [:category,…]。

SEAndroid其实就是安卓平台的SELinux,SELinux除了基于角色的访问控制机制(RBAC)和基于类型的访问控制机制外,还支持基于安全等级访问控制机制(MLS)。因此SEAndroid也继承此特性。

一般情况下,实施SELinux主要是基于类型进行访问控制策略的配置,但是安卓默认使用了MLS。虽然大部分情况下,只需要基于类型进行策略的编写即可满足要求,但是由于MLS默认是打开的,某些情况下会对访问、以及我们的策略配置造成影响,所以需要对MLS机制的原理和配置方法有所了解。

security level,由两部分组成
sensitivity[:category,...] - sensitivity [:category,...]

  • low security level:表明当前Security Context所对应的对象的当前安全级别。
  • high security level:表明当前Security Context所对应的对象的最高可能获得的安全级别

sensitivity
用sensitivity关键字定义一个sens_id,alias指定别名。

sensitivity sens_id alias [ alias_id ];

在SELinux中,真正设置sensitivity级别的是由下面这个关键词表示,括号内最左边的s0级别最低,依次递增,直到最右边的sn级别最高

dominance {s0 s1 s2.....sn}

category
category和sensitivity不同,它定义的是类别,类别之间是没有层级关系的

category cat_id alias alias_id;

senstivity和category一起组成了一个security level,由关键字level声明

level sens_id [ :category_id ];#category_id是可选的

举例: 1)level s0:c0.c255; 其中sensitivity为s0,category从c0,c1,c2一直到c255

2)重新理解前面的标签,u:r:shell:s0 ,其中Low Security Level等于High Security Level,而且Security Level没有包含Category

mlsconstrain
mlsconstrain语法和constrain基本一致

mlsconstrain class perm_set expression;

expression新增如下内容:

  • l1,l2:小写的L。l1表示源的low senstivity level。l2表示target的low sensitivity。
  • h1,h2:小写的H。h1表示源的high senstivity level。h2表示target的high sensitivity。
  • l和h的关系,包括dom,domby,eq和incomp。

MLS在安全策略上有一个形象的描述叫no write down和no read up,意思是高级别的东西不能往低级别的东西里边写数据,低级别不能读高级别的东西。

SEAndroid
SEAndroid中的MLS:
系统中只有一个sensitivity level,即s0。
系统中有1024个category,从c0到c1023。

具体定义在system/sepolicy/private/mls_decl文件中

调试技巧(需要有root权限)

  1. 若某操作执行失败,如写入文件、设置property等,若怀疑是权限相关问题,可以将SELinux设置为Permissive,观察问题是否存在 a. 若存在,则与selinux无关 b. 不存在,则配置需要的selinux文件

参考

Android SELinux: source.android.com/docs/securi…