SeLinux简单总结

1.什么是SeLinux

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

SELinux 主要由美国国家安全局开发。2.6 及以上版本的 Linux 内核都已经集成了 SELinux 模块。

In Android 4.4 → Android 7.0, SELinux 策略文件(sepolicy、file_contexts.bin、property_contexts 等)包含在 rootfs img中:

image.png

SELinux for Android 7.x.

image.png

Figure 2 . SELinux build logic.

sepolicy 文件由多个源文件组成:


image.png

Android 8.0 更新了 SELinux 以便与 Treble 配合使用,后者可将较低级别的供应商代码与 Android 系统框架分离开来。此版本更新了 SELinux 政策以允许设备制造商和 SOC 供应商更新自己的政策部分、构建自己的映像(vendor.img、boot.img 等),然后更新这些映像而不受平台影响,反之亦然。


image.png

2.为什么要使用SeLinux

2.1 DAC

DAC(Discretionary Access Control)自主式权限控制

image.png

参与的对象有3种:主体(subject)、客体(object)、规则(policy)。

权限判定过程大概如下:

1、主体拥有自己的凭证来标识自己的身份。在DAC中,主体通常是进程,而凭证是进程对应用的euid和egid。

2、客体拥有属性来标识自己的身份。在DAC中,客体通常是文件,而权限相关属性是文件对应的uid和gid。

3、主体对客体的操作可以称之为行为。DAC的特点就是行为比较简单,行为仅包括R(读)、W(写)、X(执行)这三种。

4、针对"主体对客体发起的行为",查询规则表来进行权限判定。DAC的UGO规则非常简单,把主体分为User、Group、Other三种类型,每种类型拥有自己的RWX mask。

DAC的权限控制策略是非常简洁,行为是简单的RWX三种,主体也很简单的就能被分为UGO三类。这种简洁造也就了DAC检查的开销非常小。

但是过于简洁也让它的权限划分粒度过大,一旦获得了root权限,几乎就是无所不能。在CPU日益高涨的今天,性能开销已经不是问题了,权限的细粒度管理更加重要,所以诞生了MAC。MAC在DAC的基础上,把行为、规则、判定结果进一步细分。所以它的权限管理粒度更细,但是开销也稍大。

DAC是Linux权限管理的基础机制。

2.2 MAC

DAC 管理太过宽松,只要想办法在 Android 系统上获取到 root 权限就可以了。那么 SELinux 是怎么解决这个问题呢?在 DAC 之外,它设计了一种新的安全模型,叫 MAC(Mandatory Access Control),翻译为强制访问控制。

MAC 的理论也很简单,任何进程想在 SELinux 系统上干任何事情,都必须在《安全策略文件》中赋予权限,凡是没有出现在安全策略文件中的权限,就不行。

2.3 DAC和MAC有什么区别?

DAC

DAC(Discretionary Access Control,自主访问控制)

DAC是传统的Linux的访问控制方式,DAC可以对文件、文件夹、共享资源等进行访问控制。

在DAC这种模型中,文件客体的所有者(或者管理员)负责管理访问控制。

DAC使用了ACL(Access Control List,访问控制列表)来给非管理者用户提供不同的权限,而root用户对文件系统有完全自由的控制权。

MAC

MAC(Mandatory Access Control,强制访问控制)

SELinux在内核中使用MAC检查操作是否允许。

在MAC这种模型中,系统管理员管理负责访问控制,用户不能直接改变强制访问控制属性。

MAC可以定义所有的进程(称为主体)对系统的其他部分(文件、设备、socket、端口和其它进程等,称为客体)进行操作的权限或许可。

DAC和MAC的其它区别

① DAC的主体是真实有效的用户和组ID,MAC的主体是安全上下文,两者的UID是各自独立的。

② DAC的访问控制模式是rwxrwxrwx,MAC的访问控制模式是user:role:type。

image.png

3.如何使用SeLinux

首先要对 Type、Class、Permissions和 安全上下文有一定的了解。

3.1 Type、Class和Permissions

MAC 基本管理单位是 TEAC(Type Enforcement Accesc Control),然后是高一级别的 Role Based Accesc Control。RBAC 是基于 TE 的,而 TE 也是 SELinux 中最主要的部分。 allow 语句就是 TE 的范畴。

根据 SELinux 规范,完整的 SELinux 策略规则语句格式为:

allow domains types:classes permissions;

  • Domain - 一个进程或一组进程的标签。也称为域类型,因为它只是指进程的类型。

  • Type - 一个对象(例如,文件、套接字)或一组对象的标签。

  • Class - 要访问的对象(例如,文件、套接字)的类型。

  • Permission - 要执行的操作(例如,读取、写入)。

= allow : 允许主体对客体进行操作

= neverallow :拒绝主体对客体进行操作

= dontaudit : 表示不记录某条违反规则的决策信息

= auditallow :记录某项决策信息,通常 SElinux 只记录失败的信息,应用这条规则后会记录成功的决策信息。

语句:
allow appdomain app_data_file:file rw_file_perms;

这表示所有应用域都可以读取和写入带有 app_data_file 标签的文件

下面来看看Android官方文档中的定义。
Android 依靠 SELinux 的类型强制执行 (TE) 组件来实施其政策。这表示所有对象(例如文件、进程或套接字)都具有相关联的类型。例如,默认情况下,应用的类型为 untrusted_app。对于进程而言,其类型也称为域。可以使用一个或多个属性为类型添加注解。属性可用于同时指代多种类型。

对象会映射到类(例如文件、目录、符号链接、套接字),并且每个类的不同访问权限类型由权限表示。例如,file 类存在权限 open。虽然类型和属性作为 Android SELinux 政策的一部分会进行定期更新,但权限和类是静态定义的,并且作为新 Linux 版本的一部分也很少进行更新。

政策规则采用以下格式:
allow source target:class permissions;

Source - 规则主题的类型(或属性)。谁正在请求访问权限?

Target - 对象的类型(或属性)。对哪些内容提出了访问权限请求?

Class - 要访问的对象(例如,文件、套接字)的类型。

Permissions - 要执行的操作(或一组操作,例如读取、写入)。

规则的一个示例如下:

allow untrusted_app app_data_file:file{ read write };

class定义在源码中。

文件路径: system/sepolicy/private/security_classes


file-related classes

class filesystem

class file  #代表普通文件

class dir   #代表目录

class fd    #代表文件描述符

class lnk_file  #代表链接文件

class chr_file  #代表字符设备文件

network-related classes

class socket   #socket

class tcp_socket

class udp_socket

......

class binder   #Android 平台特有的 binder

class zygote   #Android 平台特有的 zygote

3.2 安全上下文(Security Context)

安全上下文的结构及含义

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

image.png

常见的安全上下文如下。

file_contexts //系统中所有file_contexts安全上下文

seapp_contexts //app安全上下文

property_contexts //属性的安全上下文

service_contexts    //service文件安全上下文

genfs_contexts //虚拟文件系统安全上下文

以上文件system/sepolicy中都有对应的内容

image.png

3.3 简单使用

下面以新增一个build.prop为例说明。

当在.mk文件中,新增一个prop定义的时候,例如 PRODUCT_PROPERTY_OVERRIDES += vendor.xxx.sys.test=1

会发生无法读写vendor.xxx.sys.test这个属性的问题, 因为存在SeLinux相关的问题。

这里以set prop权限为例去说明。

3.3.1 定义type

在property.te文件中新增
type mtk_xxx_sys_prop, property_type,extended_core_property_type;
声明一个mtk_xxx_sys_prop的type,也可以说是标签。

Type对应一个或者几个attribute,Type的定义格式:
type type_name, attribute1, attribute2;

3.3.2 定义vendor.xxx.sys.test 的安全上下文

定义其type为mtk_xxx_sys_prop。

property_contexts文件中新增

vendor.xxx.sys.test u:object_r:mtk_xxx_sys_prop:s0

3.3.3 定义allow规则

允许system_appsystem_server进程

system_app.te文件中新增

set_prop(system_app, mtk_xxx_sys_prop)

system_server.te文件中新增

set_prop(system_server,mtk_xxx_sys_prop)

下面来看看set_prop函数。

alps/system/sepolicy/public/te_macros

305 #####################################

306 # set_prop(sourcedomain, targetproperty)

307 # Allows source domain to set the

308 # targetproperty.

309 #

310 define(set_prop',

311 unix_socket_connect($1, property, init)

312 allow $1 $2:property_service set;

所以根据这意思,完全可以拼凑出如下权限声明:

allow system_app mtk_xxx_sys_prop:property_service set;

允许 域为system_app的进程,对 标签 为mtk_xxx_sys_prop(其class属于property_service),执行set操作。

vendor.xxx.sys.test的安全上下文中 声明了

type(标签)为mtk_xxx_sys_prop

因此,type(域)为 system_app 的进程 可以对vendor.xxx.sys.test 执行set操作。system_server同理。

3.4 SeLinux文件的路径

关于SeLinux文件的路径,对于不同的平台,不同平台厂商也设定了不同的存放目录,以MTK平台为例:

首先,根据不同的platform共用sepolicy、platform独有、project独有,分为:

/device/mediatek/sepolicy :下面是ALL platform 都需要.

/device/mediatek/[platform]/sepolicy :其中platform为某个具体的平台,如mt6763.

/device/[customer]/[project]/sepolicy :客户和项目自定义配置, 客户可根据更新BroadConfig.mk 中BOARD_SEPOLICY_DIRS 以新增目录。

对应的,不同版本会导入不同目录下的sepolicy配置

Basic 版本 导入 [common]|[platfrom]/basic

Bsp 版本 导入 [common]|[platfrom]/basic & bsp

TK 版本(一般情况) 导入 [common]|[platfrom]/basic & bsp & full

以mt6763平台为例,导入时:

[common] 路径为:/device/mediatek/sepolicy

[platfrom] 路径为:/device/mediatek/mt6763/sepolicy/

具体的定义在BoardConfig.mk文件中。

3.5 根据log添加规则

例如报错

avc: denied { read } for pid=1494 comm=“sdcard” name=“0” dev=“nandk” ino=245281
scontext=u:r:sdcardd:s0
tcontext=u:object_r:system_data_file:s0
tclass=dir permissive=0
==============
scontext = u:r:sdcardd:s0
tcontex t= u:object_r:system_data_file:s0
tclass = dir
avc: denied { read }

可以看到有avc denied,且最后有permissive=0,表示不允许。我们的log重新排列一下

缺少什么权限: { read }权限,

谁缺少权限: scontext= u:r:sdcardd:s0

对哪个文件缺少权限:tcontext=u:object_r:system_data_file:s0

什么类型的文件: tclass=dir

某个scontext对某个tclass类型的tcontext缺乏某个权限

完整的意思: Type(域)为sdcardd的进程对type为system_data_file的dir(class)缺少read权限。

就是需要这样一条规则。

# file: sdcardd.te
allow  sdcardd  system_data_file:dir  read;

标志性 log: avc: denied { 操作权限 } for pid=7201 comm=“进程名” scontext=u:r:源类型:s0 tcontext=u:r:目标类型:s0 tclass=访问类型 permissive=0

源类型:授予访问的类型,通常是进程的域类型

目标类型:客体的类型,它被授权可以访问的类型

访问类型

操作权限:表示主体对客体访问时允许的操作类型(也叫做访问向量)。

例如添加一个service,不加权限的话会报错。

E SELinux : avc: denied { add } for service=car_model_service pid=10283 uid=1000

scontext=u:r:system_app:s0
tcontext=u:object_r:default_android_service:s0
tclass=service_manager permissive=0

 #============= system_app.te ==============
allow system_app default_android_service:service_manager add;

但是,有的时候 ,这样直接添加是违反neverallow 规则,编译是无法通过的。

#============= domain.te =============
neverallow * default_android_service:service_manager add;

这个策略的意思是,不允许 任何 进程将 Type (域)为default_android_service的service 对service_manager 做 add操作(service_manager.c中的add service 函数中会根据selinux策略来检查)。

这种时候就需要绕开neverallow规则了。给这个service 单独定义一个Type,安全上下文,然后再添加allow规则。

假设service名字定义为car_model_service(add到ServiceManager中的那个字符串"car_model_service"),接下来分3步走。

3.5.1 定义Type

# ============= service.te =============
type my_car_model_service,       service_manager_type;

3.5.2 定义安全上下文

# ============= service_contexts =============
car_model_service                  u:object_r:my_car_model_service:s0

3.5.3 定义allow规则

# ============= system_app.te =============
add_service(system_app, my_car_model_service)

编译后等于

allow system_app my_car_model_service:service_manager { add find };

要始终记得 最小权限原则。

4.调试用到的一些命令

4.1 显示SeLinux上下文

ls -Z 查看文件信息,包括SeLinux上下文,名称。

image.png

ps -Z 查看进程信息,包括SeLinux上下文,PID等

image.png

ps显示不全,ps -A 显示所有

ps -AZ

image.png

ps -AZ | grep "xxx" 根据grep查看某个具体的进程信息。

image.png

ls -al -Z

image.png

4.2 设置SELinux工作模式

SELinux有3种工作模式

Enforcing:强制模式。违反SELinux规则的行为将被阻止并记录到日志中。

Permissive:宽容模式。违反SELinux 规则的行为只会记录到日志中。一般为调试用。

Disabled:关闭SELinux。

查看当前工作模式:getenforce

修改工作模式:setenforce

setenforce 0(permissive) ,setenforce 1(enforcing)

注意:需在设备启动后迅速输入这个命令,刷完机后连上电脑就要一直输入adb shell,shell输入成功后,要马上setenforce 0,否则就会设置失败。可用getenforce查看设置结果。

4.3 查看log,问题定位

adb shell "cat /proc/kmsg | grep avc" > avc_log.txt 可以直接提出avc的log

cat /dev/kmsg | grep avc //查看kernel中的SELinux权限报错

dmesg | grep avc //查看kernel中的SELinux权限报错

logcat | grep -i -e avc -e selinux

dmesg -c |grep avc

dmesg -C,清空kernel log

编译过程中,偶尔会出现编译错误。类似这种

device/qcom/sepolicy/msm8952/system_app.te:3 'syntax error' at token 'allow' on line 33320

由于在编译过程中SELinux报的错误有时并不是实际问题出现的位置,因此导致有时SELinux语法错误很难定位。

事实上,在编译过程中,是通过如下命令对SELinux进行检查的:

/bin/bash -c "(out/host/linux-x86/bin/checkpolicy -M -c 30 -o out/target/product/msm8952/obj/ETC/sepolicy_intermediates/sepolicy.tmp out/target/product/msm8952/obj/ETC/sepolicy_intermediates/policy.conf ) && (out/host/linux-x86/bin/checkpolicy -M -c 30 -o out/target/product/msm8952/obj/ETC/sepolicy_intermediates/sepolicy.dontaudit out/target/product/msm8952/obj/ETC/sepolicy_intermediates/policy.conf.dontaudit ) && (out/host/linux-x86/bin/sepolicy-analyze out/target/product/msm8952/obj/ETC/sepolicy_intermediates/sepolicy.tmp permissive > out/target/product/msm8952/obj/ETC/sepolicy_intermediates/sepolicy.permissivedomains ) && (if [ \"eng\" = \"user\" -a -s out/target/product/msm8952/obj/ETC/sepolicy_intermediates/sepolicy.permissivedomains ]; then echo \"==========\" 1>&2; echo \"ERROR: permissive domains not allowed in user builds\" 1>&2; echo \"List of invalid domains:\" 1>&2; cat out/target/product/msm8952/obj/ETC/sepolicy_intermediates/sepolicy.permissivedomains 1>&2; exit 1; fi ) && (mv out/target/product/msm8952/obj/ETC/sepolicy_intermediates/sepolicy.tmp out/target/product/msm8952/obj/ETC/sepolicy_intermediates/sepolicy )"

从上述命令可以看出checkpolicy命令是对out/target/product/msm8952/obj/ETC/sepolicy_intermediates/policy.conf这个文件进行语法检查的,打开policy.conf可以看到所有的SELinux配置最终都汇总到policy.conf中,因此为了解决“syntax error"问题,我们只需要在policy.conf搜索编译过程中报的出错语句(如device/qcom/sepolicy/msm8952/system_app.te:3),并在policy.conf中检查其周围的语句即可定位是哪一个SELinux配置语句导致的syntax error。

4.4 快速验证
mmm system/sepolicy

image.png

push system/etc/selinux 和 vendor/etc/selinux 到手机里面, 并重启手机.

adb push  $(PRODUCT_OUT)/system/etc/selinux /system/etc/
adb push  $(PRODUCT_OUT)/vendor/etc/selinux /vendor/etc/
adb reboot

5.sys目录下的权限

sys下的权限由于Android P收紧的对sysfs 的权限,导致直接配置对sysfs的SElinux权限,会触发编译时的neverallow规则。

cts版本不能有任何neverallow,只能去掉添加的权限。单独配置type。

国内版本可适当注释掉原生相关neverallow进行规避。

我遇到过一个复现率很高的sys目录下节点type配置失败的情况。

具体现象是开机后,一定几率,设置type失败。

就像这种,虽然将节点都设置了sysfs_egbin这个type,但是开机后,sda的type却是sysfs。

Android P SElinux权限调试

drwxr-xr-x  4 root root u:object_r:sysfs:s0      0 1970-01-29 19:16 .
drwxr-xr-x 11 root root u:object_r:sysfs:s0      0 1970-01-29 19:16 ..
drwxr-xr-x  2 root root u:object_r:sysfs_egbin:s0 0 1970-01-29 19:16 features
drwxr-xr-x  2 root root u:object_r:sysfs:s0      0 2018-10-30 18:16 sda

但是,我即使添加了
restorecon --recursive /sys/class/xxx
还是无法解决这个问题。

在系统启动过程中,当执行到restorecon这句的时候,我需要访问的/sys/class/xxx节点,有一定几率还是不存在,没有创建完成,因此在后面解决办法是不使用/sys/class/xxx节点,使用/proc/driver/xxx节点去设置type。这个节点挂载时间更早一点。

参考链接:

官方文档:

https://source.android.google.cn/static/security/selinux/images/SELinux_Treble.pdf
https://source.android.google.cn/security/selinux/concepts
https://opensource.com/business/13/11/selinux-policy-guide
https://deepinout.com/seandroid/seandroid-policy-dac-and-mac.html

android 8.1 安全机制 — SEAndroid & SELinux
SELinux_Treble学习记录
Android Q system_app默认写persist.sys.系统属性SEliux权限来源
SELinux权限
android P 修改sysfs的 u:object_r:失效问题分析
SELinux syntax error问题定位
Android/SELinux 添加 AVC 权限
Android P SElinux权限调试
SEAndroid学习笔记
Android 9 SELinux
Linux DAC 权限管理详解

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,240评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,328评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,182评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,121评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,135评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,093评论 1 295
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,013评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,854评论 0 273
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,295评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,513评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,678评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,398评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,989评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,636评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,801评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,657评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,558评论 2 352

推荐阅读更多精彩内容