当前位置: 首页 > 工具软件 > SE Android > 使用案例 >

Android-SEAndroid权限

阮选
2023-12-01

前言

SEAndroid是在Android系统中基于SELinux推出的强制访问控制模型,来完善自主访问模型中只要取得root权限就可以为所欲为的情况。
SELinux是一种基于域-类型(domain-type)模型的强制访问控制(MAC)安全系统,其原则是任何进程想在SELinux系统中干任何事,都必须先在安全策略的配置文件中赋予权限。凡是没有在安全策略中配置的权限,进程就没有该项操作的权限。在SELinux出现之前,Linux的安全模型是DAC(DiscretionaryAccess Control),译为自主访问控制。其核心思想是进程理论上所拥有的权限与运行它的用户权限相同。比如,以root用户启动shell,那么shell就有root用户的权限,在Linux系统上能干任何事。这种管理显然比较松散。在SELinux中,如果需要访问资源,系统会先进行DAC检查,不通过则访问失败,然后再进行MAC权限检查。
Linux中有两种东西,一种死的(Inactive),一种活的(Active)。死的东西就是文件(Linux哲学,万物皆文件。注意,万不可狭义解释为File),而活的东西就是进程。此处的“死”和“活”是一种比喻,映射到软件层面的意思是:进程能发起动作,例如它能打开文件并操作它。而文件只能被进程操作。
为了方便调试,我们可以手动开启或关闭selinux:
使用setenforce 命令进行设置:
adb shell setenforce 0 //设置成permissive 模式
adb shell setenforce 1 //设置成enforce 模式
注意此方法重启后失效

一.SELinux知识点分析

1.1 SEAndroid app分类和其他

SELinux(或SEAndroid)将app划分为主要三种类型(根据user不同,也有其他的domain类型):
1.untrusted_app 第三方app,没有Android平台签名,没有system权限
2.platform_app 有android平台签名,没有system权限
3.system_app 有android平台签名和system权限
4.untrusted_app_25 第三方app,没有Android平台签名,没有system权限,其定义如下This file defines the rules for untrusted apps running with targetSdkVersion <= 25.
从上面划分,权限等级,理论上:untrusted_app < platform_app < system_app按照这个进行排序

1.2 app_contexts定义

system/sepolicy/seapp_contexts数据文件

isSystemServer=true domain=system_server
user=system seinfo=platform domain=system_app type=system_app_data_file
user=bluetooth seinfo=platform domain=bluetooth type=bluetooth_data_file
user=nfc seinfo=platform domain=nfc type=nfc_data_file
user=radio seinfo=platform domain=radio type=radio_data_file
user=shared_relro domain=shared_relro
user=shell seinfo=platform domain=shell type=shell_data_file
user=_isolated domain=isolated_app levelFrom=user
user=_app seinfo=platform domain=platform_app type=app_data_file levelFrom=user
user=_app domain=untrusted_app type=app_data_file levelFrom=user

从上面可以看出,domain和type由user和seinfo两个参数决定。
比如:
user=system seinfo=platform,domain才是system_app
user=_app,可以是untrusted_app或platform_app,如果seinfo=platform,则是platform_app。

1.3 user和seinfo判定方式

首先看user,user可以理解为UID,例如ps -Z结果如下:

u:r:system_app:s0              system    2414  1172  com.android.keychain
u:r:platform_app:s0            u0_a6     2439  1172  com.android.managedprovisioning
u:r:untrusted_app:s0           u0_a8     2460  1172  com.android.onetimeinitializer
u:r:system_app:s0              system    2480  1172  com.android.tv.settings
u:r:untrusted_app:s0           u0_a27    2504  1172  com.android.email
u:r:untrusted_app:s0           u0_a28    2523  1172  com.android.exchange
u:r:untrusted_app:s0           u0_a7     2567  1172  com.android.musicfx

第一列是SContext,第二列是UID,只要UID是system的基本都是system_app,反过来一样。
其他的U0_XXX要么属于platform_app或untrusted_app
seinfo由system/sepolicy/private/mac_permissions.xml决定,内容如下:

 <!-- Platform dev key in AOSP -->
    <signer signature="@PLATFORM" >
      <seinfo value="platform" />
    </signer>

 <!-- All other keys -->
    <default>
      <seinfo value="default" />
    </default>

即如果签名是platform,seinfo就是platform,其他的比如shared等,seinfo是default。
比如上面ps -Z的结果里面,OneTimeInitializer.apk是untrusted_app,ManagedProvisioning.apk是platform_app。
分别查看这两个app的Android.mk
packages\apps\OneTimeInitializer\Android.mk 没有定义LOCAL_CERTIFICATE,默认是shared
packages\apps\ManagedProvisioning\Android.mk 有定义LOCAL_CERTIFICATE := platform
因为ManagedProvisioning.apk有platform签名,所以seinfo是platform。

2.1 主体(subject)与客体(object)

所有资源可以分为两类: 主体和客体
主体是活的,可以主动对其他资源进行某些操作的,在linux中指进程。
客体则是死的,被动的。除了主体之外的资源(file,socket,device等)。

2.2 标签(Labels)

所有subject和object都有自己的标签,比如进程,目录,文件,设备,网终端口,主机名等资源都有自己的标签。
通过编写规则来控制某个subject标签对某个object标签的访问,这就是所谓管理政策。

如下面 u:object_r:system_file:s0 表示 用户,角色,类型,安全级别 , 这些字符串都是标签
-rwxr-xr-x root shell u:object_r:system_file:s0 dexdump

2.3 安全上下文(Security Context)

对象都有一个安全上下文(Security Context),它是一串字符串,通示标签构建。
标准格式:user:role:type:mls_level,可通过ps -Z命令查看
比如u:object_r:system_file:s0

2.4 用户user与角色role

用于角色访问控制,user不是linux uid,是MAC专用的定义,一个user可以属于多个role,不同的role具有不同的权限, android只定义一个用户u和一个subject角色r,一个object角色object_r,即不使用角色访问控制功能,这里不作详述。

2.5 安全级别

主体(subject)和客体(object)都关联有一个安全级别,安全级别较高的主体可以读取安全级别较低的客体,而安全级别较低的主体可以写入安全级别较高的客体,通过这种规则,可以允许数据从安全级别较低的主体流向安全级别较高的主体,而限制数据从安全级别较高的主体流向安全级别较低的主体.Android只定义一种安全级别S0,即不使用安全级别。

2.6 类型type,域domain,类class

type: 标注资源类型。
domain:和type一样,但是只限于标注subject,即进程的类型。对进程来说,Type就是Domain。
class:客体(object)的类别,本质上是具有相同操作权限集合的资源类型 , 比如file,它有open,read,write等操作,就定义一个file的class,包含所有相关操作权限。

2.7 类型强制检测(TE)

策略格式:
rule subject_type target_type : class perm_set
rule:控制类型,比如allow neverallow.
subject_type:指domain
target_type:请求资源的类型
class perm_set: 对资源的操作

//init进程 创建/data/property and files
allow init property_data_file:dir create_dir_perms;
allow init property_data_file:file create_file_perms;

我们直接来看几个实例:

//SEAndroid中的安全策略文件policy.conf

#允许zygote域中的进程向init type的进程(Object Class为process)发送sigchld信号

allow zygote init:process sigchld;

2.8 Type Transitions类型切换

Domain Transitions
一个进程fork 另外一个进程并执行(exec) 一个执行档时,为了避免新进程权限和源进程一样大,需要进行domain 切换

Object Transitions
process创建文件时, 默认是沿用父目录的Security Context, 如果要设置成特定的Label, 就必须进行Object切换。

3 SEAndorid策略中的一些基本语法

讲解SEAndroid策略文件前,先了解一些基本语法,主要有下面三类
type
class
allow

type

type用于定义资源类型 即把资源类型和属性关联到一起
属性在后面有详细介绍
type type_id [alias alias_id,] [attribute_id]
将type_id(别名为alias)关联到attribute. 这样的话,方便用attribute来管理不同的type中包含相同的属性的部分。
例子:
type init, domain;
将init关联到domain,即将domain设置为init类型的属性
每一个资源对应一个type, 每一个type 对应有一个或几个Attribute.

class

用于定义资源类别的权限集合
class class_name [ inherits common_name ] { permission_name … }
inherits表示继承了common定义的权限,然后自己额外实现了permission_name的权限
例子:
class dir inherits file
{
add_name
remove_name
reparent
search
rmdir
open
audit_access
execmod
}
dir继承 file的操作权限集合并增加自己的操作

allow

allow:赋予某项权限。
allowaudit:audit含义就是记录某项操作。默认情况下是SELinux只记录那些权限检查失败的操作
dontaudit:对那些权限检查失败的操作不做记录。
neverallow:用来检查安全策略文件中是否有违反该项规则的allow语句。

例子:
allow init unlabeled:filesystem mount;
允许init类型对unlabeled类型的filesystem进行mount的操作

neverallow { appdomain -unconfineddomain } kmem_device:chr_file { read write };
绝对不允许app(除了有unconfineddomain属性的app)对kmem_device类型的字符设备进行读写的操作

type,attribute和allow等

现在再来看type的定义,和type相关的命令主要有三个,如下面的例子所示:

  • type命令的完整格式为:type type_id [alias alias_id,] [attribute_id]
    其中,方括号中的内容为可选。alias指定了type的别名,可以指定多个别名。
    #下面这个例子定义了一个名为shell的type,它和一个名为domain的属性(attribute)关联
    type shell, domain; #本例来自shell.te,注意,可以关联多个attribute

  • 属性由attribute关键字定义,如attributes文件中定义的SEAndroid使用的属性有:
    attribute domain
    attribute file_type
    可以在定义type的时候,直接将其和某个attribute关联,也可以单独通过

  • typeattribue将某个type和某个或多个attribute关联起来,如下面这个例子
    将前面定义的system类型和mlstrustedsubject属性关联了起来
    typeattribute system mlstrustedsubject

使用attribute有什么好处呢?一般而言,系统会定义数十或数百个Type,每个Type都需要通过allow语句来设置相应的权限,这样我们的安全策略文件编起来就会非常麻烦。有了attribute之后呢,我们可以将这些Type与某个attribute关联起来,然后用一个allow语句,直接将source_type设置为这个attribute就可以了:

#定义两个type,分别是A_t和B_t,它们都管理到attribute_test
type A_t attribute_test;
type B_t attribute_test;

#写一个allow语句,直接针对attribute_test
allow attribute_test C_t:file {read write};

#上面这个allow语句在编译后的安全策略文件中会被如下两条语句替代:
allow A_t C_t:file {read write};
allow B_t C_t:file {read write};

Domain/Type Transition和宏

SEAndroid中,init进程的SContext为u:r:init:s0,而init创建的子进程显然不会也不可能拥有和init进程一样的SContext(否则根据TE,这些子进程也就在MAC层面上有了和init一样的权限)。那么这些子进程的SContext是怎么被打上和其父进程不一样的SContext呢?
ELinux中,上述问题被称为Domain Transtition,即某个进程的Domain切换到一个更合适的Domain中去。Domain Transition也是需要我们在安全策略文件中来配置的,而且有相关的关键词,来看例子。

#先要使用type_transition语句告诉SELinux
#type_transition的完整格式为:
#type_transition source_type target_type : class default_type;

#对Domain Transition而言有如下例子:
type_transition init_t apache_exec_t : process apache_t;

上面这个例子的解释如下,请读者务必仔细:

  • 当init_t Domain中的进程执行type为apache_exec_t类型的可执行文件(fork并execv)时,其class(此处是process)所属Domain(对process而言,肯定是指Domain)需要切换到apache_t域。
    要做DT,肯定需要先fork一个子进程,然后通过execv打开一个新的可执行文件,从而进入变成那个可执行文件对应的活物!所以,在type_transition语句中,target_type往往是那个可执行文件(死物)的type。default_type则表示execv执行后,这个活物默认的Domain。另外,对DT来说,class一定会是process。
    请注意,DT属于Labeling一部分,但这个事情还没完。因为打标签也需要相关权限。所以,上述type_transition不过是开了一个头而已,要真正实施成功这个DT,还需要下面至少三个allow语句配合:
#首先,你得让init_t域中的进程能够执行type为apache_exec_t的文件
allow init_t apache_exec_t : file execute;

#然后,你还得告诉SELiux,允许init_t做DT切换以进入apache_t域
allow init_t apache_t : process transition;

#最后,你还得告诉SELinux,切换入口(对应为entrypoint权限)为执行apache_exec_t类型的文件
allow apache_t apache_exec_t : file entrypoint;

为什么会需要上述多达三个权限呢?这是因为在Kernel中,从fork到execv一共设置了三处Security检查点,所以需要三个权限。
提示:读者不必纠结这个了,按照规范做就完了。不过…,这导致我们写TE文件时候会比较麻烦啊!
确实比较麻烦,不过SELinux支持宏,这样我们可以定义一个宏语句把上述4个步骤全部包含进来。在SEAndroid中,系统定义的宏全在te_macros文件中,其中和DT相关的宏定义如下:

#定义domain_trans宏。$1,$2等等代表宏的第一个,第二个....参数

define(`domain_trans', `

# SEAndroid在上述三个最小权限上,还添加了自己的一些权限

allow $1 $2:file { getattr open read execute };

allow $1 $3:process transition;

allow $3 $2:file { entrypoint read execute };

allow $3 $1:process sigchld;

dontaudit $1 $3:process noatsecure;

allow $1 $3:process { siginh rlimitinh };

')
#定义domain_auto_trans宏,这个宏才是我们在te中直接使用的

#以例子7而言,该宏的用法是:

#domain_auto_trans(init_t, apache_exec_t, apache_t)

define(`domain_auto_trans', `

# 先allow相关权限

domain_trans($1,$2,$3)

# 然后设置type_transition

type_transition $1 $2:process $3;
')

除了DT外,还有针对Type的Transition。举个例子,假设目录A的SContext为u:r:dir_a,那么默认情况下在该目录下创建的文件都具有u:r:dir_a这个SContext。所以我们也要针对死得东西进行打标签。

# 定义file_type_auto_trans(domain, dir_type, file_type)宏

#该宏的含义是:当domain域中的进程在某个Type为dir_type的目录中创建文件时,该文件的SContext应该是file_type

在SEAndroid的app.te中,有如下TT设置:

./app.te:86:file_type_auto_trans(appdomain, download_file, download_file)

 类似资料: