前言

做Android平台SDK开发,在Android 8.0版本之后面临不少系统权限问题,经过这几年的开发和适配以及平时的探索,我在系统权限和安全方面学习和掌握了不少这方面的知识。

本文基于Android 11.0, 主要介绍下SELinux和SEAndroid,本文在阅读参考了国内外不少大牛的资料基础上,加上平时的实战总结出来的,希望对大家有所帮助。

自编故事

很久以前,有个公司成立了,公司里有总经理张总一人,秘书小王一人,还有李赵等小兵若干,有一天总经理写了一封信,信中写了公司员工每个人的薪水等级,写完后,放在一个柜子里,

结果总经理为了方便,设置了柜子权限为老铁666,然后下班回家睡觉了

秘书小王有事进到张工办公司发现没人,本来想离开的,但是看到屋里有个柜子,上面钥匙挂在上面(可读写),小王就忍不住打开偷看了一下,看完之后,心生一计,偷偷改了自己的薪水等级,然后关上柜子走了

小李小赵有事请教来找张总,结果也发现了柜子,然后也偷偷改了数据(可读写),

等第二天张总上班后,再拿出来信的时候,倒吸一口凉气,大事不妙。。。。

心想,这种不小心就把文件的权限暴露给其他人的情况,太不安全了,必须要改革!

张总熬了几个通宵,掉了一把头发,终于新的机制2.0诞生了,

2.0模式是这样的,公司里面的每个人都有一个公司派发的身份证,每个文件,也有一个身份证,公司还雇用了一个保安大爷(董事长化身),实时监控每个人对于每个文件的行为。

首先张总写信的时候,还是保持以前的模式,每次都检查下其他人是否有可读写的权限,

然后小李在打开柜子想要读写信的时候,保安是会立即检查小李的身份证和信的身份证,然后在一台只能读的电脑上,搜索小李的权限,看看人有没有读写信的权限

如果没有的话,那么保安会立即传送到小李身边,揪住小李拖出去,然后利用公司大喇叭广播所有人,小李想读信,被我阻止了,大家下次别干了啊,

张总每天最开心的事,就是听保安喋喋不休的说谁谁谁没干成什么什么事。。。。

安全系统的重要性

对于安卓系统,比如一台手机,如果系统不安全,不稳定,那么很可能就会出现如下问题:

  • 系统经常崩溃,影响用户体验
  • 对于各种bug的第三方应用,影响系统使用
  • 对于恶意应用,会入侵入侵用户的私有数据,串改数据等
  • 系统被网络黑客入侵与控制

可以想象,对于生产厂家和用户来说,如上的情况是多么的糟糕,公司倒闭,各种被唾弃都能可能出现。。。

所以构建一个坚固的系统多么的重要

Linux标准安全机制介绍:

众所周知,Android底层是Linux内核,那么关于安全部分,肯定离不开Linux,首先简单介绍下Linux的权限机制。

我们平时登陆 Linux 系统时,虽然输入的是自己的用户名和密码,但其实 Linux 并不认识你的用户名称,它只认识用户名对应的 ID 号(也就是一串数字)。

Linux 系统中,每个用户的 ID 细分为 2 种,分别是用户 ID(User ID,简称 UID)和当前工作组 ID(Group ID,简称 GID),这与文件有拥有者和拥有群组两种属性相对应,另外还有一个用户所有组ID(Groups ID,简称GIDS)

Linux id命令用于显示用户的ID,以及所属群组的ID

1
2
pi@raspberrypi:~ $ id
uid=1000(pi) gid=1000(pi) groups=1000(pi),4(adm),20(dialout),24(cdrom),27(sudo),29(audio),44(video),46(plugdev),60(games),100(users),105(input),109(netdev),997(gpio),998(i2c),999(spi)

如上,可以看到我的树莓派当前uid是1000,当前工作组gid是1000,当前用户所属的所有组的gids是后面那一长串

更多id 命令用法,请用id --help

同样,linux进程也有uid,gid,gids,某个用户启动的进程,那么这个进程就会继承用户的uid,gid,gids

查看命令为ps -aux

1
2
3
4
5
6
7
pi@raspberrypi:~ $ ps -aux
USER PID %CPU %MEM VSZ RSS TTY STAT START TIME COMMAND
root 2 0.0 0.0 0 0 ? S 09:43 0:00 [kthreadd]
root 510 0.2 0.4 32796 17400 ? S 09:43 0:05 /usr/bin/vncserver-x11-core -service
pi 617 0.0 0.0 9932 3096 ? Ss 09:43 0:00 /usr/bin/vncserver -depth 16 -geometry 1024x768 :1
pi 782 0.0 0.0 9788 2556 pts/0 R+ 10:24 0:00 ps -aux
pi 1638 0.0 0.0 8516 3776 pts/0 Ss 09:43 0:00 bash

如上截取部分输出,可以看到我用当前用户pi执行ps -aux这个执行,那么其进程的uid(USER那一列为pi

最后介绍linux文件系统,只有uid gid 以及相对应的rwx权限

查看命令为ls -l 可以看到文件型态、权限、拥有者、文件大小以及时间等内容

1
2
3
4
5
6
7
8
9
10
pi@raspberrypi:~/Downloads $ touch abc
pi@raspberrypi:~/Downloads $ ls -l
total 0
-rw-r--r-- 1 pi pi 0 Jul 18 10:32 abc
pi@raspberrypi:~/Downloads $ sudo touch bbb
pi@raspberrypi:~/Downloads $ ls -l
total 0
-rw-r--r-- 1 pi pi 0 Jul 18 10:32 abc
-rw-r--r-- 1 root root 0 Jul 18 10:32 bbb
pi@raspberrypi:~/Downloads $

如上,我在当前目录下使用当前用户pi创建了一个文件,那么从结果来看-rw-r--r-- 1 pi pi 0 Jul 18 10:32 abc我们就知道了这个文件的uid为pi ,gid为pi,其rwx权限为-rw-r--r--,其中第一个横杠-代表是一个文件,其余的9位,以3位为一组,分别代表当前用户对着文件的所有权,当前用户组对这个文件的所有权,以及其他用户组对这个文件的所有权,

当我切换到root用户去创建一个文件夹的时候,那么可以看到其uid gid也变成了root

总结一下:

  • 系统上的每个进程(运行中的程序)都作为一个特定的用户来运行
  • 每个文件都归一个特定的用户所有
  • 对资源(文件和目录等)的访问受用户所限制
  • 正在运行的进程所关联的用户可以决定该进程可访问的资源(文件/目录等)

DAC介绍

全称:Discretionary access control (DAC) 自主式权限控制

概念:如果一个用户拥有一个文件,那么用户可以允许自由的控制文件的读写和执行权限,那么就叫DAC

上一节介绍的Linux标准安全机制就是属于DAC,那么这个机制有什么特点(缺点)吗

  1. 资源所有权掌握在特定用户的手里,导致资源可能被乱用
  2. 用户的区分度比较低,系统上只有两个特权等级:普通user和超级用户root
  3. 读权限可以转移,导致信息可以任意流动,比如用户A允许文件被B用户读,那么B读到文件后,可以转手传递给C

可以看到这种DAC模式无论是用户和资源都难以控制,因此大家都想疯狂拿到root权限,然后就可以为所欲为

Android沙箱介绍

Application Sandbox,官网地址:应用沙盒

简单来说主要是

  • 基于Linux保护应用资源
  • 每个app分配唯一的UID/GID,在各自的的进程中运行
  • 互相不能访问(默认)

既然Android是基于Linux的,那么进程和资源也有uid/gid/gids,下面就介绍一下

  • 每个app安装之后都会被分配一个uidaid,源码路径/system/core/include/private/android_filesystem_config.h

  • id查看uid/gid,命令没变,cat /proc/xxx/status查看进程信息,包括uid、gid、gids

  • ps -l查看进程uid/gid 比如 u0_a36那么意思就是10000 add 36 为10036, 其中#define AID_APP 10000 /* first app user */

  • 资源或者说文件的uid/gid定义路径:/system/core/include/private/android_filesystem_config.h

  • 最后说下Android 服务service,其一般会伴随着一个xxx.rc文件,并在其中声明其uid/gid,例如下面中声明user和group,对应的就是uid和gid

    1
    2
    3
    4
    5
    6
    service surfaceflinger /system/bin/surfaceflinger
    class core
    user system
    group graphics drmrpc readproc
    onrestart restart zygote
    writepid /sys/fs/cgroup/stune/foreground/tasks
  • 另外设备节点如/dev/binder 的uid和gid一般定义在各个ueventd.rc文件中 一般放在/system/etc/ueventd.rc

那么Android中的权限Permission除了上面介绍的rwx,对于APK开发,还包括清单文件中需要配置的权限,路径:/frameworks/base/core/res/AndroidManifest.xml

无论是通过Android API,Java API,NDK C API,还是执行shell命令,那么要么在api调用过程中,如framework,要么是在底层,通过uid/gid等进行权限管理和控制。道理是相通的。

SELinux介绍

全称Security-Enhanced Linux (SELinux) ,安全增强型Linux,是增强安全的一个机制,那么就探究下到底相比DAC模式,如何增强的?

首先说下背景知识,简单了解下:

  • 是集成在kernel 2.6.x中一个安全架构
  • 是Linux Security Modules (LSM)的一部分
  • 是美国国家安全局和linux社区开发的一个项目
  • 是MAC (Mandatory Access Control)在Linux内核级的一个实现

其实最重要的就是它是MAC的一个linux实现,那么MAC是什么,跟DAC什么关系呢?

MAC介绍

  • MAC被预置到内核级的系统中,对于linux,是预置在kernel里面的
  • MAC限制主体(英文叫subject,比如用户或进程)对客体(英文名叫object,比如文件等资源)的访问操作的能力
  • MAC机制会给所有主体和客体分配一个安全标签(Security label),包括用户user,进程process,访问的资源等
  • MAC机制会定义一个清晰明确的的访问规则,限制每个用户或者进程只允许访问它已经定义好的资源,所以即使是Root权限也能被限制
  • 是非DAC的,不能被资源的所有者修改

如上可以看出,我们想要了解SELinux以及相关的概念,那么会出现很多名词,当然这些名词其实只是在不同场景下的不同叫法而已,大家习惯就好,我也是经常用,所以有时候会说出好几个名词,但是其实都是表达一个意思。

SELinux 引入**标签(label)**这个东西来进行权限的操作和规则的制定,在SELinux世界里,任何一个对象都有标签,比如进程,文件,目录等等,全都有标签,就像每个人身份证上的名字一样,与生俱来,而且每个对象的标签都是唯一的。SELinux 在做决定时,就会根据这些标签以及系统根据标签来制定的规则进行权检查。

SELinux架构流程

selinux-arc

我这边画了一个图,大致说下流程,首先主体(Subject比如user或Process)想要访问(Access) 一个客体(Object,比如一个文件file吧),那么首先需要经过DAC判断,如果DAC判断失败了(比如rwx权限不足等),那么直接就会拒绝

如果DAC验证通过,那么就会进入MAC的判断,其中MAC,我又把具体内容扩展了一下,见图中虚线方框内,

进入MAC时,首先会通过AVC(访问向量缓存),看名字cache缓存,那么缓存什么呢?缓存的是Security Server(相当于数据库) 对于主体访问客体的策略是否命中,如果命中了,那么为了提高判断效率,直接会把这个策略放到AVC里缓存,下次判断时,直接缓存里查找,速度更快。

最后通过AVC检查后,才能得到访问客体的权限,拿到相应的资源。我这里省略了图中的MLS,这个在后续会单独介绍。

如上可以知道,DAC和MAC是互为补充的,先要经过DAC后才能进行MAC,所以SELinux也叫增强安全型

SEAndroid介绍

了解过SELinux之后,那么SEAndroid就比较好理解了,其实:

SELinux + Android = SEAndroid

也就是说安卓平台对于SELinux的一个实现,或者应用于安卓上,就叫SEAndroid

官网地址:https://source.android.google.cn/security/selinux

简单说下历史演变过程:

  • Android 4.3(宽容模式)
  • Android 4.4(部分强制模式)
  • Android 5.0 及更高版本中,已全面强制执行 SELinux
  • Android 6.0 高度限制对 /proc 的访问
  • Android 8.0 更新了 SELinux 以便与 Treble 配合使用

这里解释下宽容模式(Permissive)和强制模式(Enforcing),SELinux 按照默认拒绝的原则运行:任何未经明确允许的行为都会被拒绝。SELinux 可按两种全局模式运行:

  • 宽容模式:权限拒绝事件会被记录下来,但不会被强制执行。
  • 强制模式:权限拒绝事件会被记录下来强制执行。

Android CDD

提到安卓,不得不提CDD兼容性文档,谷歌认证必备的,

CDD中对于SELinux部分也是有强制要求的,具体链接如下:https://source.android.google.cn/compatibility/11/android-11-cdd#9_7_security_features

这里我直接粘贴过来翻译过的内容

1
2
3
4
5
6
7
如果设备要使用 Linux 内核,则:
•[C-1-1] 必须实现 SELinux。
•[C-1-2] 必须将 SELinux 设置为全局强制模式。
•[C-1-3] 必须将所有域配置为强制模式。不允许使用宽容模式域,包括特定于设备/供应商的域。
•[C-1-4] 对于 AOSP SELinux 域以及特定于设备/供应商的域,不得修改、省略或替换上游 Android 开源项目 (AOSP) 中提供的 system/sepolicy 文件夹中存在的 neverallow 规则,并且政策必须在所有 neverallow 规则都存在的情况下编译。
•[C-1-5] 必须在每个应用的 SELinux 沙盒中运行面向 API 28 级或更高级别的第三方应用,并对每个应用的私有数据目录设定应用级 SELinux 限制。
•应保留上游 Android 开源项目的 system/sepolicy 文件夹中提供的默认 SELinux 政策,并且应仅针对自己的设备特定配置向该政策进一步添加内容。

可以看出,谷歌对于安卓系统的要求还是挺严格的,当然国内厂家如果不需要满足CDD的话, 很多都是为了拿到更多权限而直接宽容模式运行的,但是这样的话,系统安全就得不到保证,所以说安全和权限总是鱼和熊掌不可兼得

SEAndroid 标签Label

selinux-label

下面介绍重要概念标签label,我这里又画了一个图,便于理解这个概念,首先label是给所有对象贴的,包括进程和资源

首先标签label又叫Security Context安全上下文,然后进程的标签,我们也叫scontext(source context)源上下文,而资源的标签也叫tontext(target context)目标上下文名字如意思,比较好理解。

然后它长什么样子呢,就是user:role:domain或者type:mls_level 也就是三个冒号分隔成四个部分

其中user叫用户,在SEAndroid中只定义了一个用户叫u,

然后role角色,在SEAndroid中也定义了两个角色叫r和object_r

什么区别的,r是给进程用的,而object_r是给访问的对象或者叫资源用的,因为object就是对象的意思

然后domain或者type什么区别呢?如果进程的标签,那么就是domain域,如果是资源,那就是type

最后是mls_level在SEAndroid里面只定义了一个级别s0

其实从标签的样子,大家可以知道,四部分中主要变化的是第三部分(domain/type),所以安卓中主要以这个部分定义相关规则

SEAndroid 的标签大致分为五类:

  • 首先是Service服务相关的标签。
  • 其次,对于基于 Binder 的服务,允许向 Service Manager 注册的标签。
  • 第三,系统属性Property的标签。
  • 第四,设备节点相关的标签。
  • 第五,文件相关的标签
  • 最后,app应用相关的标签。

这里先说下SEAndroid中文件相关的标签

  • file_contexts 为文件分配标签,为/system /sys /dev /data 等文件分配标签
  • genfs_contexts 用于为不支持扩展属性的文件系统(例如,proc 或 vfat)分配标签
  • property_contexts 用于为 Android 系统属性分配标签。在启动期间,init 进程会读取此配置。
  • service_contexts 用于为 Android Binder 服务分配标签,以便控制哪些进程可以为相应服务添加(注册)和查找(查询)Binder 引用。在启动期间,servicemanager 进程会读取此配置。
  • seapp_contexts 用于为应用进程和 /data/data 目录分配标签。在每次应用启动时,zygote 进程都会读取此配置;在启动期间,installd 会读取此配置。
  • mac_permissions.xml 用于根据应用签名和应用软件包名称(后者可选)为应用分配 seinfo 标记。随后,分配的 seinfo 标记可在 seapp_contexts 文件中用作密钥,以便为带有该 seinfo 标记的所有应用分配特定标签。在启动期间,system_server 会读取此配置。

最后说下如下的信息含义

1
W com.aa.bb: type=1400 audit(0.0:199): avc: denied { call } for  scontext=u:r:system_app:s0 tcontext=u:object_r:update_engine:s0 tclass=binder permissive=0 app=com.aa.bb

我们平时一般会通过logcat查看相关打印信息,这里介绍两个命令来抓取selinux的拒绝事件打印:logcat |grep avc 或者dmess |grep avc 就会过滤出一大堆类似如上的信息,我们要从这些信息中提取出有用的关键信息,并修改系统的规则来满足我们产品的要求。

下面我会介绍SELinux的规则,并解释如上的信息含义

SEAndroid 规则1 Rule/Policy

每个对象都有标签了,那么如何利用这些标签来干事情呢,重要的规则或者叫策略登场了

基于安卓源码,介绍下SDK中源码相关的内容:

system/sepolicy 是android 关于selinux核心策略配置的所有内容,我们不应该去修改这个路径下任何文件

/device/manufacturer/device-name/sepolicy 这个路径会包含芯片厂家所有平台相关的配置,我们主要修改这里 BOARD_VENDOR_SEPOLICY_DIRS += vendor/oem/sepolicy 我一般会把自定义的规则放在自定义的目录里面,便于跟芯片厂家的分区开

*.te策略配置文件的后缀,其中的语言从global_macros, te_macros attributes 这些配置文件中读取和使用

Android 8.0 之后

  • system/sepolicy/public 平台共有策略的全部定义
  • system/sepolicy/private 平台私有规则,不会向vendor部分暴露。
  • system/sepolicy/vendor 厂商规则,可引用public的规则,不能引用private的规则
  • device/manufacturer/device-name/sepolicy 厂商自定义的规则,包括如上的vendor部分

总之大家没事可以多去上面说的几个目录下点击文件看看内容,其中厂家一般都只修改device里面定义的规则,否则可能会引起谷歌认证失败的情况。大家还是遵守规则比较好

SEAndroid 规则2

image-20210722214227470

下面介绍下*.te中常用的语法规则,目的是让大家能看到,会写

上面图中以adbd.te为例,介绍具体的内容

首先说下domain域定义的规则,如下面两行

1
2
3
type adbd, domain; //解释下type就是定义的意思,定义adbd 为domain,看到domain,意思就是adbd是给进程或者用户贴的标签类型
type adbd_exec, exec_type, file_type; //这行意思是定义一个adbd_exec这个类型,然后属于exec_type和file_type,意思就是adbd这个文件的标签为adbd_exec,那么它是可执行文件(exec_type),也是文件类型(file_type)
//图中标注为红色的,都可以通过箭头找到原始定义的源码路径,大家可以自己查看

域定义完了之后,紧接着就是定义规则了

1
allow domains types:classes permissions; //这行是语法规则,意思就是允许(allow) 某个域(domains) 对于某个资源(types):资源类型(classes) 拥有资源类型相关的权限(permissions)

举个例子

1
2
allow bootanim system_file:dir r_dir_perms;
允许 域类型为bootanim的进程 对于资源为system_file的目录dir 有读r权限

另外介绍下有4种情况:

  • allow - 允许主体对客体执行许可的操作。
  • neverallow - 表示不允许主体对客体执行制定的操作。
  • auditallow - 表示允许操作并记录访问决策信息。
  • dontaudit - 表示不记录违反规则的决策信息,切违反规则不影响运行。

SEAndroid 规格3

说下SDK编译这些规则最终的产出物策略生成位置

  • boot.img(针对非 A/B 设备)或 system.img/vendor.img(针对 A/B 设备)。

  • (/system /vendor /product)/etc/selinux 所有分区中的策略配置文件位置,包括如下内容
  • (plat vendor product)_sepolicy.cil: 所有策略转成cil (CIL(common Intermediate Language))
  • *_file_contexts: 文件的security contexts 其中* 代表plat|vendor|product

  • *_property_contexts: 属性的security contexts

  • *_seapp_contexts: App 的security contexts

  • *_mac_permissions.xml

SEAndroid 命令

平时开发中,我这里总结了常用的命令来查看或者设置SELinux相关的内容

Command Action
setenforce 0/1 或 getenforce 临时关闭或打开安全策略 ,或者获取当前策略 Permissive/Enforcing
Ls -Z 显示文件的Security Context
ps -Z 显示进程的Security Context
id (user) 显示进程/用户的Security Context
chcon 修改文件的Security Context
restorecon 恢复文件的默认Security Context
dmesg |grep avc 或 logcat |grep avc 查看所有denied的信息

如下是一些实际操作的效果

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
console:/sdcard # ps -AZ
LABEL USER PID PPID VSZ RSS WCHAN ADDR S NAME
u:r:init:s0 root 1 0 46160 6772 SyS_epoll_wait 0 S init
u:r:kernel:s0 root 2 0 0 0 kthreadd 0 S [kthreadd]
u:r:netd:s0 root 306 281 17776 2632 pipe_wait 0 S iptables-restore
u:r:audioserver:s0 audioserver 332 1 58772 17608 binder_ioctl_write_read 0 S audioserver
u:r:su:s0 root 5414 5149 10864 2932 0 0 R ps
console:/sdcard # id system
uid=1000(system) gid=1000(system) groups=1000(system) context=u:r:su:s0
console:/ $ id
uid=2000(shell) gid=2000(shell) groups=2000(shell),1007(log),3009(readproc) context=u:r:shell:s0
console:/ $ id log
uid=1007(log) gid=1007(log) groups=1007(log) context=u:r:shell:s0
console:/sys/fs # ls -Zl
total 0
drwxrwxrwt 2 root root u:object_r:fs_bpf:s0 0 2021-07-20 23:28 bpf
dr-xr-xr-x 2 root root u:object_r:sysfs:s0 0 2021-07-20 23:51 cgroup
drwxr-xr-x 10 root root u:object_r:sysfs:s0 0 2021-07-20 23:51 ext4
drwxr-xr-x 3 root root u:object_r:sysfs_fs_f2fs:s0 0 2021-07-20 23:28 f2fs
drwxr-xr-x 3 root root u:object_r:sysfs:s0 0 2021-07-20 23:28 fuse
drwxr-xr-x 3 root root u:object_r:sysfs:s0 0 2021-07-20 23:51 incremental-fs
dr-xr-x--- 2 system log u:object_r:pstorefs:s0 0 2021-07-20 23:28 pstore
drwxr-xr-x 8 root root u:object_r:selinuxfs:s0 0 1970-01-01 08:00 selinux

这里说一下,系统开机后,selinux会把文件系统挂在到/sys/fs/selinux这个节点下面,里面有所有android所定义的对象以及相应的权限控制,部分列举如下

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
console:/sys/fs/selinux/class # ls -l
total 0
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 binder
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 blk_file
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 bluetooth_socket
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 capability
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 capability2
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 chr_file
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 dir
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 fd
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 fifo_file
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 file
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 filesystem
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 hwservice_manage
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 ipc
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 keystore_key
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 lnk_file
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 packet_socket
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 process
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 process2
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 property_service
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 service_manager
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 sock_file
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 socket
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 system
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 tcp_socket
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 udp_socket
dr-xr-xr-x 3 root root 0 2021-07-20 23:28 unix_stream_socket
console:/sys/fs/selinux/class/binder/perms # ls -lZ
total 0
-r--r--r-- 1 root root u:object_r:selinuxfs:s0 0 2021-07-20 23:28 call
-r--r--r-- 1 root root u:object_r:selinuxfs:s0 0 2021-07-20 23:28 impersonate
-r--r--r-- 1 root root u:object_r:selinuxfs:s0 0 2021-07-20 23:28 set_context_mgr
-r--r--r-- 1 root root u:object_r:selinuxfs:s0 0 2021-07-20 23:28 transfer
console:/sys/fs/selinux/class/binder/perms #

如上可以看到binder所有的权限,可以与其它进程进行binder ipc通信(call),能够向这些进程传递Binder对象(transfer),以及将自己设置为Binder上下文管理器(set_context_mgr)

具体可以查看每个class里面 perms文件夹内的内容。

SEAndroid 实战1 Service

seandroid-service

对于在 Android 6.x (Marshmallow) 之后添加的 Service,如果缺少相关文件或编写不正确,则 开机时service是无法正常启动和运行的。

图中定义了一个mytest_service的服务,声明了一个mytest.rc文件,这样放入system/etc/init/mytest.rc里面,那么开机后是无法启动的,原因就是缺少安全策略

那么如何定义安全策略呢?

seandroid-service-ok

1
2
3
4
//一共需要如下这些文件
mytest_service
mytest.rc
file_context

想开机运行服务,需要将相关内容添加到与服务相关的安全标签中(图中file_contexts 和mytest.te)即可

但是这种开机起来的服务是不能注册到binder里面的,也就是不能作为binder服务

那么如何作为binder服务并开机注册呢?请看下图

seandroid-service-binder

1
2
3
4
5
6
7
//一共需要如下这些文件
mytest_service
mytest.rc

file_context
service_context.te
service.te

SEAndroid 实战2 Property

Google在Android O以后,为了降低vendor和system之间的耦合度,对property的作用区域也做了明确的区分,分为vendor的property和system里的property.

一般我们自定义property的时候,OEM厂家都应该以vendor.开头,或者persist,ro这种的,而不能是xx.yy.zz,否则谷歌认证会报错

property

1
2
3
4
//一共需要如下这些文件
mytest.te //主要是声明权限控制的
property_contexts //主要是定义你的某个prop的完整标签上下文
property.te //定义一个新标签类型type

这样,你的property,开机后就会能读取或者写入等操作,

也可以使用getprop -Z 来看你定义的prop的标签内容

SEAndroid 实战3 Device设备节点

项目中有可能需要自定义了一个设备节点,比如/dev/test_dev ,然后要求访问特定设备节点,

那么在SEAndroid中也需要设置相关文件

同时如果你发现系统内某个设备节点无法访问,权限不足,那么你也有能需要重新修改下这个设备节点的SELinux标签,满足权限要求

下面介绍下

device

比如一个服务mytest_service想要打开一个设备节点,如上图,那么一般会设计到如下设置

device-context

1
2
3
4
涉及到设备相关的文件
device.te //主要是定义一个设备节点的type
file_contexts //给具体的设备节点路径定义一个完整的标签,标签中加入你新定义的type
mytest.te //最后在你的服务的域中,定义相关的权限即可

当然,如果系统内已经定义好了相关设备节点的标签,那么你直接修改为你自定义的,然后权限自然就有了哦

查看设备节点的标签命令ls -Z 因为设备节点属于资源,不是进程

SEAndroid 实战4 Binder/HIDL

在Android 8.0以后,system和vendor进行了隔离,那么就引入了HIDL来进行通信,其实也是binder通信,

这里总结下Android中的三种binder,以及涉及到的SELinux文件,大家具体可以查看自己家平台里面相关的内容

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
//System binder service相关
file_contexts
service.te
service_context
servicemanager.te

//HIDL binder service相关
file_contexts
hwservice.te
hwservice_context
hwservicemanager.te

//vendor中的binder service相关
file_contexts
vndservice
vndservice_contexts
vndservicemanager.te

MLS介绍

当大家查看进程标签时ps -AZ,一般会发现如下的标签中有个c512,c768,这种的

1
u:r:platform_app:s0:c512,c768  u0_a58     747    287 1140388 136964 SyS_epoll_wait      0 S com.android.systemui

SEAndroid里,只定义了s0一个敏感度sensitive,但是定义了0~1023个category。在敏感度只有一个值的情况下,其实MLS已经变成了MCS(Multi-category Security),多组安全。MCS用于隔离,阻断不同组之间的信息流动。颗粒度更细

相关源码定义:

system/sepolicy/private/mls 主要策略控制位置

mls-level

如上 小写l代表level,小写t 代表type,

l1表示subject的MLS level,l2表示object的MLS level

t1表示subject的type,t2表示object的type

上图的mlsconstrain规则,定义了只有在满足下面四个条件其中之一的情况下,才能对系统的任何目录和文件拥有写、追加、重命名等权限:

(1)dir/file的类型为app_data_file(t2 == app_data_file,t2表示object的类型)

(2)主体和客体的MLS相等(l1 eq l2,l1表示subject的MLS level,l2表示object的MLS level)

(3)主体拥有mlstrustedsubject属性(t1 == mlstrustedsubject )

(4)客体拥有mlstrustedobject属性(t2 == mlstrustedsubject )mlstrustedsubject和mlstrustedobject分别是subject和object的属性,相应的类型关联到这两种属性后,可以绕过MLS的限制。

system/sepolicy/private/mls_decl 使用了宏生成sensitive和category

1
system/sepolicy/private/mls_macros

/system/sepolicy/private/seapp_contexts 文件中的levelFrom字段决定应用和目录/文件的level

external/selinux/libselinux/src/android/android_platform.c 文件中,通过对levelFrom的值的判断,赋予应用、应用的数据对应level。

mls-levelfrom

levelcode

Code & Doc

主要代码和文档汇总

谷歌在线文档:https://source.android.google.cn/security/selinux

源码路径 :/system/sepolicy

其他在线文档,排名不分先后

https://jung-max.github.io/2019/09/16/Android-SEAndroid%EC%A0%81%EC%9A%A9/

https://milestone-of-se.nesuke.com/en/sv-advanced/selinux/selinux-summary/

https://blog.csdn.net/innost/article/details/19299937/

https://blog.csdn.net/luoshengyang/article/details/35392905

http://androidxref.com/

https://www.jianshu.com/p/3f6006e74821

感谢!