通过前面的文章内容,我们对 SELinux 目录和 te 文件有一个初步的了解,这里我们继续研究Sepolicy 的语法规范。
一、Sepolicy语言介绍
Linux 中有两种东西,一种死的(Inactive),一种活的(Active)。活的东西就是进程,而死的东西就是文件(Linux 哲学,万物皆文件。注意,万不可狭义解释为 File,普通文件、特殊文件、套接字等都属于文件范畴)。他们之间就是一种使用(操作)与被使用(被操纵)的关系,进程能发起动作(例如它能打开文件并操作它),而文件只能被进程操作。
SElinux Policy 语言将死的和活的东西都给打上"标签",通过"标签"将系统内的资源(包括进程)分成不同的角色(比如:用户、客体),进而对整个系统资(包括进程)进行合理安全的管控。
1、属性(attribute)
所有常⻅的 Attribute 定义在 /system/sepolicy/public 下⾯,vendor 定义的 attribute 通常 在 /device/qcom/sepolicy/vendor/common 中。声明格式如下:
attribute 属性名;
示例配置
源码位置:/system/sepolicy/public/attributes
# 用于进程的类型
attribute domain;
# 用于进程入口点的类型
attribute exec_type;
# 所有可以存在于标记文件系统(labeled filesystem)上的文件类型
# 不要用于伪文件类型(pseudo file types)
# 如果更改此属性定义,需要更新 tools/checkfc.c 中的 CHECK_FC_ASSERT_ATTRS 定义
attribute file_type;
这里分别定义了名为 domain(进程类型)、exec_type(进程入口点的类型)和file_type(文件类型)的属性组。
在实际项目中,可以通过添加⾃定义属性 vendor_xxx_type ,来针对本项⽬统⼀设置某些权 限,如当常规⽅法⽆法解决 neverallow 问题时,可以将类型与该属性相关联,以规避 neverallow 规则。
2、类型(type)
在 SELinux 中,每种东西都会被赋予一个安全属性,官方说法叫 Security Context,⽬前 type 是 Security Context 中最重要的栏⽬。即可以说,每⼀个 ⽂件对应⼀个 type,⽽每⼀个 type 都对应有⼀个或⼏个 Attribute 。type 的定义,分散在各个 te ⽂件中。
Android 依靠 SELinux 的类型强制执⾏ (TE) 组件来实施其政策。这表⽰所有对象(例如⽂件、进程或套接字)都具有相关联的类型。例如,默认情况下,应⽤的类型为 untrusted_app,它是 File Class 类型。对于进程⽽⾔,其类型也称为域(domain)。类型定义格式如下:
type 类型名 [alias 别名集] [属性集];
type:关键字,用于声明一个新的类型。
类型名:新定义的类型的名称。
alias 别名集:可选部分,用于指定该类型的别名集合。
属性集:可选部分,用于指定该类型的属性集合。
示例配置
这里以 adbd.te 为例,adbd 的安全标签(seclabel)在 init.rc 文件中进行了指定,位于根文件系统(rootfs)中,adbd 没有独特的文件类型。
源码位置:/system/sepolicy/public/adbd.te
# adbd seclabel is specified in init.rc since
# it lives in the rootfs and has no unique file type.
type adbd, domain;
type adbd_exec, exec_type, file_type;
这里定义一个新的安全域(domain)叫做 adbd。这意味着 adbd 进程会被 SELinux 视为一个独立的安全域。 同时还定义了一个新的类型 adbd_exec 并且指定了它同时属于 exec_type(可执行文件) 和 file_type(普通文件)类型。
该配置确保了 adbd 进程及其相关文件具有正确的 SELinux 标签,从而能够在系统中正确地执行其功能,同时也遵循了 SELinux 的安全策略。下面进行详细解析。
type adbd, domain;
定义了一个名为 adbd 的类型,指定 adbd 类型的属性是一个域(domain)。属性是在 attribute 文件中定义的一个类型,类似于一个分组。
type adbd_exec, exec_type, file_type;
这里指定了 adbd_exec 可执行文件和普通文件的属性,说明 adbd_exec 是一个文件类型,而不是进程。其实 domain 是一种特殊的属性,表示一个进程域(domain),只有进程才会赋予 domain 域属性。
属性值
对于一个属性是同时可以被多个类型指定的,这样配置权限时就可以针对⼀组属性来设置权限,⽽不必精确的去针对每个类型设置权限,如:
# adbd.te
type adbd_exec, exec_type, file_type;
#logdumpd.te
type logdumpd_exec, exec_type, vendor_file_type, file_type;
这里的 adbd_exec 和 logdumpd_exec 均包含 file_type 属性。
别名
上面 adbd.te 中的 type 属性并不包含 alias 别名集。下面看一个含有别名的类型。
type my_app, app_domain alias untrusted_app, exec_type;
my_app:定义了一个名为 my_app 的类型。
app_domain:指定 my_app 类型是一个域(app_domain)。
alias untrusted_app:指定 my_app 类型的别名为 untrusted_app。
exec_type:指定 my_app 类型是一个可执行文件类型。
3、关联属性
除了上面在定义类型的时候关联属性,也可以⽤ typeattribute 来设置类型的属性。
typeattribute [类型名] [属性名];
示例配置
# 定义类型
type adbd;
type adbd_exec;
# 使用 typeattribute 设置属性
typeattribute adbd domain;
typeattribute adbd_exec exec_type, file_type;
上述两种⽅法都是将 adbd 添加⾄ domain 属性集合中,即 adbd 属于 domain ,对 domain 配置的权限也会同步给 adbd,同样对 domain 的限制也会限制 adbd。
4、访问向量(Access Vector)
SELinux 的访问控制规则采用以下格式:
allow source target:class permissions;
- allow:访问规则名称,表示允许某种类型的访问。
- source:规则主体的类型(或属性)。表示“谁”正在请求访问权限,通常是进程的类型。
- target:对象的类型(或属性)。表示“对哪些内容”提出了访问权限请求,通常是文件、目录或其他对象的类型。
- class:类(权限集)。表示要访问的对象的类型,例如文件(file)、目录(dir)、套接字(sock)等。
- permissions:权限。表示要执行的操作(或一组操作),例如读取(read)、写入(write)、执行(execute)等。
策略规则的⽬的是⽤来描述主体(源)对客体(⽬标)的访问规则。 具体例子如下:
allow sample_app app_data_file:file { read write };
这个例子是说,允许 sample_app 这个进程去访问 app_data_file(它是一个 file 类型,也就是文件),允许的操作是 read 和 write。
而其实这里的 sample_app 并不是一个真正的具体的进程名,而是在系统编译阶段就定义好的一个标签(Label),一些真正的进程被映射到 sample_app 这个标签上,那么在执行上面规则的时候,其实生效的、有权限访问 app_data_file 的是所有映射了sample_app 标签的那些进程。同样的,app_data_file 也不是一个具体的文件名。它也是一个提前声明了的标签,一些真正的文件被映射到这个标签上,sample_app 有权访问的是所映射的这些文件。
从这里看出来,有别于传统 DAC 的 Owner、Group、Permissions 的控制方式,所谓的“基于标签系统”的 SELinux,就是这种通过声明标签的方式来表述访问规则的。
标签只是一种概念性的东西,具体体现在策略文件里,则是抽象成了 Type、Attribute、Class、Permissions 这些具体关键字。
示例配置
假设我们需要定义一些访问规则,具体如下:
# 允许 adbd 进程读取和执行 adbd_exec 文件
allow adbd adbd_exec:file { read execute };
# 允许 adbd 进程写入 log_file 文件
allow adbd log_file:file write;
# 允许 adbd 进程读取 config_file 文件
allow adbd config_file:file read;
- source:adbd(adbd 进程)
- target:adbd_exec(adbd 的可执行文件)
- class:file(文件类型)
- permissions:{ read execute }(读取和执行权限)
拒绝访问
当 SELinux 拒绝访问权限的时候,将会打印如下日志:
avc:denied { map } for path="/data/local/data/mute.png" dev="mmcblk0p37" ino=5338 scontext=u:r:bootvideo:s0 tcontext=u:object_r:system_data_file:s0 tclass=file permissive=0
像这类日志都是以关键字 avc 开头,需要注意其中几个很重要的字段:
- denied { 权限 }:找到 denied 字段,后面通常跟随大括号,里面的内部就表示被拒绝的操作,即什么操作权限被拒绝,例如读写查等权限
- scontext:主体上下文。找到 scontext 字段,后面跟随的为主体安全上下文 SContext,即代表主体进程。
- tcontext:客体上下文。找到 tcontext 字段,后面跟随的为客体安全上下文 SContext,即代表被访问单个资源或一系列资源的上下文。
- tclass:客体类别。找到 tclass 字段,后面为客体类别。
通过上面几个关键字,我们就可以为其配置专门的 AV 规则,安装 allow 语句的规则可以在对应主体进程的te文件下添加 allow 语句:
allow bootvideo system_data_file:file { map }
修改后的 SELinux 策略文件后需要使用 make 命令来编译策略文件,如果是项目整编,直接刷机运行即可。而如果通过运行 make selinux 或者 make -C system/sepolicy 对 SELinux 策略文件进行单编,就需要在编译完成后,将编译后的二进制策略文件复制到 /system/etc/selinux 目录下,然后再重启系统。
5、访问规则名
SELinux 中通常有四种访问规则名称。
- allow:允许主体对客体执⾏许可的操作。
- neverallow:不允许主体对客体执⾏制定的操作。
- auditallow:记录允许操作的访问决策信息。
- dontaudit:表⽰不记录违反规则的决策信息,且违反规则不影响运⾏。
示例配置
# 允许 adbd 进程读取并执行 adbd_exec 文件
allow adbd adbd_exec:file { read execute };
# 不允许 adbd 进程修改 system 目录
neverallow adbd system:dir write;
# 记录 adbd 进程对 log_file 文件的写入操作
auditallow adbd log_file:file write;
# 不记录 adbd 进程尝试读取 secure_file 文件的操作
dontaudit adbd secure_file:file read;
这里的 auditallow 的前提是 adbd 进程已经有对 log_file 文件的写入权限,才能在写入操作时进行记录。同样 dontaudit 的主要作用是忽略某些特定的访问尝试,即使这些尝试违反了现有的 SELinux 策略规则,也不会记录这些尝试。所以 dontaudit 的前提是 adbd 进程没有对 secure_file 文件的读取权限,这样在 adbd 进程尝试读取 secure_file 文件时,不记录读取记录。
标签:Sepolicy,adbd,exec,SELinux,app,file,类型,Android,type From: https://blog.csdn.net/c19344881x/article/details/142383756