Android安全策略SELinux

目录

一、基本概念

1、工作模式

1)、关闭模式

2)、宽容模式

3)、强制模式

2、进程和资源

3、安全属性

1)、进程SContext

2)、资源SContext

4、TE术语

5、allow语句

6、调试

7、基本原理

二、策略文件

1、sepolicy/vendor/service.te

2、sepolicy/system/private/service_contexts

3、sepolicy/vendor/shen.te

4、sepolicy/vendor/file_contexts

三、配置新进程的SEAndroid

1、配置进程shen的安全策略

1)、domain

2)、exec_type

3)、init_domain_domain

2、赋予二进制文件SContext

3、赋予binder通信功能

四、问题思路

1、如何定位Selinux权限问题?

2、违反neverallow规则解决思路

1)访问 default property 超过权限

2)为新服务添加标签并解决拒绝事件

3)新设备节点增加访问权限


SELinux原本是美国国安局联合一些公司设计的一个针对Linux的安全加强系统。

SELinux出现之前,Linux系统上的安全模型叫做DAC(自主访问控制),其原理是进程所拥有的权限与执行它的用户的权限相同(例如:以root用户启动Browser,那么Browser就有root用户的权限,在Linux系统上能干任何事情)。SELinux的出现结束了这种宽松的访问。

SELinux在DAC的基础之上,设计了新的安全模型叫做MAC(强制访问控制),其原理是任何进程想在SELinux系统中干任何事情,都必须先在安全策略配置文件中赋予权限,凡是没有在安全策略配置文件配置的权限,进程就没有该权限。Android4.4版本上正式推出的一套以SELinux为基础于核心的系统安全机制,且命名为SEAndroid,自此SELinux便被"移植"到了Android上了。

参考:Selinux小结

一、基本概念

1、工作模式

SELinux通常有如下三种模式:disable、permissive、enforcing。通常发布版都将使用强制模式Enforcing。

可以通过getenfoce来获取当前工作模式,还可以通过setenforce 0来设置当前模式为Permissive;也可以通过setenforce 1来设置当前模式为Enforcing。除此之外还可以进入fastboot模式设置:

#设置参数bootargs
$setenv bootargs  androidboot.selinux = permissive/enforcing
#保存参数
$saveenv
#重启系统
$reset

1)、关闭模式

如果SELinux 被关闭(开启Disable模式),就使用传统的Linux系统默认的自主访问控制(DAC)方式,不需要增强安全性的环境来说,该模式是很好用的(换句话禁止SELinux功能)

编辑配置文件/etc/selinux/config,把SELINUX=disabled,然后重启系统,SELinux 就被禁用了。

还可以通过修改源代码的方式来关闭SELINUX,再Android S修改如下代码

BuildServer108:~/works/v501_driver/android/system$ git diff
diff --git a/core/init/selinux.cpp b/core/init/selinux.cpp
index 1d0daed8..8e6e5c4d 100644
--- a/core/init/selinux.cpp
+++ b/core/init/selinux.cpp
@@ -114,10 +114,11 @@ EnforcingStatus StatusFromProperty() {
 }
 
 bool IsEnforcing() {
-    if (ALLOW_PERMISSIVE_SELINUX) {
-        return StatusFromProperty() == SELINUX_ENFORCING;
-    }
-    return true;
+    //if (ALLOW_PERMISSIVE_SELINUX) {
+    //    return StatusFromProperty() == SELINUX_ENFORCING;
+    //}
+    //return true;
+    return false;
 }

2)、宽容模式

在 Permissive 模式中,安全策略规则并没有被强制执行。当安全策略规则应该拒绝访问时,访问仍然被允许。然而,此时会向日志文件发送一条消息,表示该访问应该被拒绝(换句话使能SELinux功能,但是SELinux不会拒绝方法但会打印日志)

SELinux Permissive 模式主要用于以下几种情况:审核当前的 SELinux 策略规则;测试新应用程序,看看将 SELinux 策略规则应用到这些程序时会有什么效果;解决某一特定服务或应用程序在 SELinux 下不再正常工作的故障。

总结:仅记录但不强制执行 SELinux 安全政策。

3)、强制模式

Enforcing 模式, SELinux 被启动,并强制执行所有的安全策略规则(换句话使能SELinux,并强制按照SElinux的规则来进行权限访问)

总结:强制执行并记录安全政策。如果失败,则显示为 EPERM 错误。

2、进程和资源

有人比喻Linux中有两种东西:死的(Inactive)、活的(Active)。活的东西就是进程,而死的东西就是资源(普通文件、特殊文件、套接字等)。他们之间就是一种使用(操作)与被使用(被操纵)的关系:进程能发起动作(例如它能打开文件并操作它);而文件只能被进程操作

SElinux Policy语言将死的和活的东西都给打上"标签",通过"标签"将系统内的资源(包括进程)分成不同的角色(比如:用户、客体),进而对整个系统资(包括进程)进行合理安全的管控。

3、安全属性

在SELinux世界里,每种东西都会被赋予一个安全属性(官方说法叫Security Context,后文简称SContext),也可以理解为第一小节提到的标签。

Linux中的所有东西,包括活的进程、死的资源都有自己对应的SContext安全属性,因此可以把SContext分为进程SContext和资源SContext,无论哪种安全属性,他们的本质都是一个字符串,其格式如下:

user:role:type[:range]
#user表示用户:SEAndroid中仅定义了一个SELinux用户,用u表示
#role表示角色:可以暂时理解为在SELinux用户可以有多个不同的role,不同role所具有的权限也不一样
#type表示类型:不同的type所具有的权限也不一样,但跟role有本质的不同
#range表示安全级别:通常为s0,不用怎么关注

1)、进程SContext

HWBLN-H:/ $ ps -Z -A
LABEL                          USER           PID  PPID     VSZ    RSS WCHAN            ADDR S NAME
u:r:init:s0                    root             1     0   22180   1404 0                   0 S init
u:r:kernel:s0                  root             2     0       0      0 0                   0 S [kthreadd]
u:r:kernel:s0                  root             3     2       0      0 0                   0 S [ksoftirqd/0]
u:r:kernel:s0                  root             5     2       0      0 0                   0 S [kworker/0:0H]
u:r:logd:s0                    logd           405     1   20132   4168 0                   0 S logd
u:r:servicemanager:s0          system         406     1   11320    808 0                   0 S servicemanager
u:r:hwservicemanager:s0        system         407     1   14064   1532 0                   0 S hwservicemanager
u:r:vndservicemanager:s0       system         408     1   10116    280 0                   0 S vndservicemanager
u:r:hal_health_default:s0      system         473     1   12964    720 0                   0 S [email protected]
u:r:hal_memtrack_default:s0    system         474     1   12988    772 0                   0 S [email protected]
u:r:hal_thermal_default:s0     system         475     1   13100    520 0                   0 S [email protected]
u:r:hal_usb_default:s0         root           476     1   13044    556 0                   0 S [email protected]
u:r:displayeffect:s0           system         477     1   13128    516 0                   0 S [email protected]
u:r:hal_audio_default:s0       audioserver    478     1   50088   2356 0                   0 S [email protected]
u:r:mediacommservice:s0        system         479     1   13140    532 0                   0 S [email protected]
u:r:hi110x_daemon:s0           system         480     1   16352    808 0                   0 S [email protected]
u:r:untrusted_app:s0:c512,c768 u0_a118      21453   684 4176436 310404 0                   0 S com.tencent.mm
u:r:untrusted_app:s0:c512,c768 u0_a118      21473   684 3089252  57528 0                   0 S com.tencent.mm:push
u:r:untrusted_app:s0:c512,c768 u0_a118      21721   684 7797824  87584 0                   0 S com.tencent.mm:appbrand0
u:r:untrusted_app:s0:c512,c768 u0_a118      21737   684 7432960  42216 0                   0 S com.tencent.mm:appbrand1

输入命令ps -Z -A能够查询当前所有进程的安全属性,最右边列表示进程名称,最左边列表示该进程对应的安全属性。大多数的进程的SContext的user值为u表示SEAndroid用户;role值为r表示进程;range值为s0。

值得注意的是它们的type不一样,init进程的type值为init,进程logd的type值为logd,除此之外还有些进程的type是相同的,例如腾讯的几个进程的type都是untrusted_app。进程SContext的type字段代表该进程所属的Domain(域名),个人理解domain就跟tcp协议栈里面的域名一样,它对应于一类进程,后文将要讲解的安全策略就会应用于该类的所有进程,即相同type的进程具有相同的访问权限。

2)、资源SContext

#查看根目录的安全属性
1|HWBLN-H:/ $ ls -l -Z
drwxrwx---   7 system cache  u:object_r:cache_file:s0        4096 2020-04-30 14:34 cache
drwxrwx--x  57 system system u:object_r:system_data_file:s0  4096 2020-07-27 09:00 data
lrwxrwxrwx   1 root   root   u:object_r:rootfs:s0              23 1970-01-01 08:00 default.prop -> system/etc/prop.default
drwxr-xr-x  22 root   root   u:object_r:device:s0            3920 2020-07-27 09:00 dev
lrwxrwxrwx   1 root   root   u:object_r:rootfs:s0              11 1970-01-01 08:00 etc -> /system/etc
lrwxrwxrwx   1 root   root   u:object_r:rootfs:s0               8 2020-07-27 09:00 log -> /splash2
drwxr-xr-x  10 root   system u:object_r:tmpfs:s0              240 2020-07-27 09:02 mnt
drwxr-xr-x   8 root   root   u:object_r:system_file:s0       4096 1970-01-01 08:00 odm
drwxr-xr-x   2 root   root   u:object_r:rootfs:s0              40 1970-01-01 08:00 oem
drwxr-xr-x   2 root   root   u:object_r:rootfs:s0              80 1970-01-01 08:00 res
drwx------   2 root   root   u:object_r:rootfs:s0              40 2020-01-14 11:08 root
drwxr-x---   2 root   root   u:object_r:rootfs:s0             420 1970-01-01 08:00 sbin
drwxr-xr-x   5 root   root   u:object_r:storage_file:s0       140 2020-07-27 09:02 storage
dr-xr-xr-x  14 root   root   u:object_r:sysfs:s0                0 2020-07-27 09:00 sys
drwxr-xr-x  22 root   root   u:object_r:system_file:s0       4096 1970-01-01 08:00 system
drwxr-xr-x   9 root   root   u:object_r:vendor_file:s0       4096 1970-01-01 08:00 vendor

在Android系统根目录执行ls -Z命令,能够查看根目录文件的SContext。大多数资源的SContext的user值为u代表SEAndroid用户;role值为object_r代表文件;range值为s0。

值得注意的他们的type不一样,目录cache的type值为cache_file;目录root和res和etc的type值为rootfs;目录system的type值为system_file;跟进程SContext一样,有些资源的type相同,代表他们是同一类,后文结束的allow语句配置的安全策略都将应用同type的资源。

#/system/bin目录下的安全属性
1|HWBLN-H:/ $ ls /system/bin/ -Z -l
-rwxr-xr-x 1 root shell  u:object_r:system_file:s0         207 2020-01-14 11:39 am
lrwxr-xr-x 1 root shell  u:object_r:zygote_exec:s0          13 2020-01-14 11:39 app_process -> app_process64
-rwxr-xr-x 1 root shell  u:object_r:zygote_exec:s0       24988 2020-01-14 11:39 app_process32
-rwxr-xr-x 1 root shell  u:object_r:zygote_exec:s0       23960 2020-01-14 11:39 app_process64
-rwxr-xr-x 1 root shell  u:object_r:system_file:s0         194 2020-01-14 11:39 locksettings
lrwxr-xr-x 1 root shell  u:object_r:system_file:s0           6 2020-01-14 11:39 log -> toybox
-rwxr-xr-x 1 root shell  u:object_r:logcat_exec:s0        6840 2020-01-14 11:39 logcat
-rwxr-xr-x 1 root shell  u:object_r:shell_exec:s0       298864 2020-01-14 11:39 sh

#/vendor/lib目录下的安全属性
1|HWBLN-H:/ $ ls /vendor/lib/ -l -Z
total 53600
-rw-r--r-- 1 root root  u:object_r:vendor_file:s0            113284 2020-01-14 11:03 [email protected]
-rw-r--r-- 1 root root  u:object_r:vendor_file:s0            159148 2020-01-14 11:03 [email protected]
-rw-r--r-- 1 root root  u:object_r:vendor_file:s0             71608 2020-01-14 10:58 displayeffect.hi6250.so
drwxr-xr-x 2 root shell u:object_r:same_process_hal_file:s0    4096 2020-01-14 10:50 egl
drwxr-xr-x 2 root shell u:object_r:vendor_hal_file:s0          4096 2020-01-14 11:03 hw
drwxr-xr-x 2 root shell u:object_r:vendor_file:s0              4096 2020-01-14 11:03 hwcam
-rw-r--r-- 1 root root  u:object_r:vendor_file:s0             53792 2020-01-14 10:58 libAntiTheftCA.so
-rw-r--r-- 1 root root  u:object_r:vendor_file:s0             62704 2020-01-14 10:50 libBestShot.so
-rw-r--r-- 1 root root  u:object_r:vendor_file:s0             16048 2020-01-14 10:58 libBootloaderOeminfo.so

如上文件/system/bin/log的type值为system_file,文件/system/bin/logcat的type值为logcat_exec,文件/system/bin/sh的type值为shell_exec。个人理解type后戳为file表示单纯的文件,后戳为exec代表它能够被执行,但是他们可不是天生就是这样的,具体详情后文将介绍。

4、TE术语

SEAndroid世界将所有事物都打上了标签(每个事物都有自己的SContext),那么SEAndroid就能根据这些SContext来进行统一管理。SEAndroid就是通过一系列的te文件来管理所有进程和资源的权限,每个te文件里面都有无数条te语句,每条te语句对应一条安全策略。

  • 主体:主体和客体只是一个逻辑上的概念,就跟主谓宾语句:小红在吃米饭,其中主语是小红(活的),宾语是米饭(死的)。同理在Linux世界中,活的东西只有进程,死的东西是资源。即资源是被使用的东西,进程是使用者,这里的主体就是指使用者。SEAndroid中的主体就是指的进程,当然可能是单一的进程,也可以是一组具有相同权限的进程,但是它们都对应一个type。
  • 客体:同上客体就是这个被使用者。SEAndroid中的客体就是指的资源(包括普通文件/特殊文件/套接字),当然可能是单一的资源,也可以是一组相同类型的资源,但是他们都对应一个type。
  • 客体类别:客体与客体类别的概念就类似于Java语言中的object和class,其中class表示一个类,object表示一个实例对象。同样客体和客体类别也是这样的关系,例如小红在吃米饭,小红在吃鱼肉,米饭和鱼肉都是具体的事物(客体),但是他们却是不一样的类别(客体类别)。SEAndroid中已经为资源定义了一些客体类别,我们也可以自定义。例如/etc/password是一个普通文件,/atv/socket_0是一个套接字。
  • 访问许可:这个比较好理解,代表对客体的访问权限,例如读写权限,查询发送等权限。这个也是可以自定义的。
  • AV规则:既然已经有了主体和客体,那么就有对应访问规则,又叫AV规则。属于SElinux策略语言的控制部分,即te文件中每一条AV规则语句都需要能够描述清楚:主体 对 客体 是否具有 访问许可。其实就是te文件里面的allow、neverallow、dontaudit、auditallow等语句。
#一条完整的te安全控制语句格式应该为: AV规则 主体 客体:客体类别 许可
#示例1:
allow netd proc:file write
#allow为AV规则,表示允许
#netd为主体,一般为进程SContext的type
#proc为客体,一般为资源SContext的type
#file为客体类别,表示proc是一个文件
#write为许可,表示写权限
#综上可以解读为:允许域名为netd的所有进程具有对资源文件proc的write权限
#示例2:
allow zygote init:process sigchld;
#allow为AV规则,表示允许
#zygote为主体
#init为客体,一般为资源SContext的type
#process为客体类别,表示init是一个进程
#sigchld为许可,表示发送信号
#综上可以解读为:允许zygote进程向init进程发送信号

5、allow语句

上节初步介绍了访问规则,在实际开发过程中,通常用的最多的还是allow语句,该语句格式如下:

allow  主体type  客体type  客体类别:  {权限}

当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 }

6、调试

我们配置了allow语句之后,可能还没生效,这个时候就可能需要调试了,查看一下我们的allow语句是否被编译到镜像里面的cil文件中。

例如System的一些配置编译之后会放到如下目录

除了上述方式去进行allow语句的手动配置,我们还可以使用audio2allow工具来自动帮我们生成allow语句,具体用法点击我。

7、基本原理(摘抄)

这里附上我学习资料中的一张图,感觉还是比较形象的,如下图:

Android安全策略SELinux_第1张图片(1) Subject: 一个必须在场的主体,以引起一个物体采取行动(例如,读取文件时,信
息仅在涉及主题时流动)
(2) Object: 一个对象管理器,它知道特定资源(例如文件)所需的操作并可以强制执行
这些操作(即,如果策略允许,则允许它写入文件)
(3) Security Server: 一个安全服务器,它根据安全策略规则做出有关主体权限以对对象
执行请求的操作的决策
(4) Security Policy: 使用 SELinux 策略语言描述规则的安全策略
(5) AVC: 通过缓存安全服务器决策来提高系统性能的访问向量缓存 (AVC)

当一个 subject(如: 一个应用)试图访问一个 object(如:一个文件),Kernel 中的策略执行服务器将检查 AVC (Access Vector Cache), 在 AVC 中,subject 和 object 的权限被缓存(cached)。如果基于 AVC 中的数据不能做出决定,则请求安全服务器,安全服务器在一个矩阵中查找“应用+文件”的安全环境。然后根据查询结果允许或拒绝访问。

二、策略文件

这里不深入讲解SEAndroid相关的所有文件,也不讲解一些基本type和属性的一些定义,只需要明白android默认的策略配置都基本上写好了,这些策略配置基本上不需要我们去更改。但是厂商定制策略文件的sepolicy目录下。这里介绍该目录下几个比较重要的文件。

1、sepolicy/vendor/service.te

service.te文件主要定义了一些service(init.rc服务对应的进程)的type。即定义了init.rc中的service对应进程的SContext的type字段。这些type通常会继承于service_manager_type。如下:

type    hitv_service,    service_manager_type;
type    bootvideo_service,    service_manager_type;
type    quickplay_service,    service_manager_type;
type    shen_service,    service_manager_type;

2、sepolicy/system/private/service_contexts

前文定义了一些type,但是这些type并没有得到使用,service_contexts文件就是用来配置Service(四大组件之一)系统服务的安全属性SContext,其中使用service.te里面定义的type(进程的type也叫域名Domain)。如下:

TVService    u:object_r:tvservice_service:s0
hitvservice  u:object_r:tvservice_service:s0
hirmservice  u:object_r:tvservice_service:s0
bootvideo    u:object_r:bootvideo_service:s0
quickplay    u:object_r:quickplay_service:s0
shen         u:object_r:shen_service:s0

3、sepolicy/vendor/shen.te

前文已经为init.rc将启动的进程做了安全属性的配置,那么可以在为每个进程做具体的安全策略,通常每个自定义进程就会对应一个te文件,编译系统打包过程中会自动将sepolicy目录下的配置拼接到原生SEAndroid中。这里拿自定义进程shen来举例,那么就需要创建一个shen.te文件来配置具体安全策略。如下:

type shen,coredomain,domain; 
#定义shen,继承于coredomain和domain,将代表某一组进程的域名
type shen_exec,exec_type,file_type;
#定义shen_exec,继承于exec_type和file_type,将代表某一资源,继承了执行权限
init_domain_domain(shen)

#具体安全策略
allow 语句
neverallow 语句

4、sepolicy/vendor/file_contexts

前文配置了进程SContext,那么这里还需要配置资源SContext,如下:

#Devices
/dev/sockect/vold0        u:object_r:vold_sockect:s0
/dev/sockect/vold1        u:object_r:vold_sockect:s0

#System files
/system/bin/bootvideo     u:object_r:bootvideo_exec:s0
/system/bin/quickplay     u:object_r:quickplay_exec:s0
/system/bin/shen          u:object_r:shen_exec:s0

如上配置文件/system/bin/shen的type为shen_exec,前文继承于exec_type,表示该资源为一个可执行文件。

三、配置新进程的SEAndroid

service shen /system/bin/shen
    user root
    class core

现如今就可以在init.rc中配置如上代码,让init进程fock创建一个进程shen,并执行了/system/bin/shen里面的代码。其中新进程名叫shen,执行的资源文件是/system/bin/shen,但是仅仅这样,系统开机启动后并没有启动进程shen,原来是因为init进程在启动rc文件中的service之前初始化了selinux相关的东西,因此selinux校验不过,进程shen无法被启动,因此需要作如下步骤配置:

1、配置进程shen的安全策略

创建sepolicy/vendor/shen.te文件:

type shen,coredomain,domain; 
#定义shen,继承于coredomain和domain,将代表某一组进程的域名
type shen_exec,exec_type,file_type;
#定义shen_exec,继承于exec_type和file_type,将代表某一资源,继承了执行权限
init_domain_domain(shen)
binder_use(shen)
binder_service(shen)
binder_call(shen,system_server)
hwbinder_use(shen)
set_prop(shen,exported_system_prop)
set_prop(shen,exported2_system_prop)

allow shen mediaserver_service:service_manager { find };
allow shen mediaserver:binder { call};
allow shen surfaceflinger_service:service_manager { find };
allow shen surfaceflinger:binder { call };
allow shen surfaceflinger:fd { call };
allow shen system_file:dir { read open };
allow shen system_prop:property_service { set };
allow shen storage_file:link_file {read open };
allow shen system_data_file:file {read open map };

上面的策略文件,先定义了两个type,还记得type是什么吗?没错,是Linux任何东西(包括进程和资源)都具有的SContext安全属性中的type。上面的shen.te文件前两句就定义了两个type:shen和shen_exec,其中shen继承于domain,shen_exec继承于file_type。

1)、domain

深入原生sepolicy代码中的定义就会知道,domain专门用来修饰进程SContext的type,表示一个域(一组进程),我们的进程叫shen,因此用字符串shen来表示这组进程,在后面的allow语句中都是allow shen xxxx来实现安全策略。

2)、exec_type

file_type是用来修饰资源SContext的type,这里定义了一个shen_exec,并继承于exec_type/file_type,其中exec_type表示可执行文件,因此只要有某资源安全属性的type字段就表示它能够被执行。在后文中我们会把shen_exec赋予/system/bin/shen文件。

3)、init_domain_domain

init_domain_domain(shen)是一个宏,声明当一个domain为init的进程创建一个子进程执行一个type为study_exec的文件时,将该子进程的domain设置为shen,而不是继承父进程(它的父进程就是init进程)的domain。

2、赋予二进制文件SContext

rc文件中指定进程shen执行/system/bin/shen这个二进制文件,但到目前为止,这个文件就是一个普普通通的文件,shen进程读取该文件的代码时候将会被selinux权限校验的时候拒绝,因此我们还需要对该文件赋予可被执行的type。

sepolicy/vendor/file_contexts专门用来配置所有资源的SContext,因此我们只需要在该文件中进行如下配置即可:

#sepolicy/vendor/file_contexts
/system/bin/shen          u:object_r:shen_exec:s0

3、赋予binder通信功能

经过上面两个步骤init可以成功启动进程shen,但是此时的shen并不能在系统生态中使用binder进程间通信功能。

sepolicy/vendor/service.te中定义继承于service_manager_type的type,如下:

type    shen_service,    service_manager_type;

将拥有service_manager_type的type赋予给进程shen,如下:

shen         u:object_r:shen_service:s0

四、问题思路

1、如何定位Selinux权限问题?

  • 当遇到问题时,想判断是不是 selinux 权限导致时,在 userdebug 或 eng 版本,通过adb shell setenforce 0 命令,让 selinux 处于宽容模式,再看问题是否还存在。如果问题不存在,可以确认是 selinux 权限不足导致。(注意,特殊情况下可能还需要验证重启过程,上面命令重启失效,这个时候可以考虑修改init的代码来设置关闭模式)
  • 抓取 log,过滤“avc“,可以看到缺少的权限信息,类似如下错误:avc:denied{permission}for pid=257 scontext=u:r:scontext:s0 tcontext=u:object_r:tcontext:s0 tclass=tclass=0 
  •  根据报错,可以得知 scontext 缺少对 tcontext 的 tclass 的 permission 权限,可以在对应的scontext.te 文件中补上对应allown语句:allow scontext tcontext:tclass {permission};
  • 然后用 make selinux_policy 编译,然后 push 相关分区下的 etc/selinux。直到没有 avc 报错为止

2、违反neverallow规则解决思路(摘抄)

遇到neverallow规则问题,千万别急着去注释/剔除里面原有的规则(原生的尽量别动它!)。增加allow规则是常见的解决办法,但是随着 android 版本的升级,系统对 selinux 的管控越来越严,增加了大量的 neverallow。一般情况下,向默认标签授予权限的做法是错误的。其中许多权限都是 neverallow 规则所不允许的。按照上面方法去添加 selinux 可能会违反了 neverallow规则,编译时候会报 neverallow 相关的错误。

1)访问 default property 超过权限

这是比较常见的 neverallow 错误,比如在 systemserver 进程中去对新加的属性设置属性,运行时就会报 default propert 的错误。
遇到这种类型的错误,首先需要给新增的属性添加标签。在 property.te 中定义 property
type demo_prop, property_type;
在 Android 12 中,由于新的 neverallow,如果对 file 进行操作将会编译不过
neverallow domain {
 property_type
 -system_property_type
 -product_property_type
 -vendor_property_type
}:file no_rw_file_perms;
新的 property type 需要指出具体是什么 property type,比如用于 vendor 就改成如下
type demo_prop, property_type, vendor_property_type;
但是如果这个属性还需要在 coredomain 中使用,比如 shell,那么上面写法还是会报一样的 neverallow,需要额外添加 vendor_restricted_property_type 或者是 vendor_restricted_prop(demo_prop)
在 proerty_contexts 中匹配所需要访问的 property
prop u:object_r:demo_prop:s0
然后再根据提示添加政策,比如例子是在systemserver中操作,所以在system_server.te中添加如下政策:
allow system_server demo_prop:property_service set;

2)为新服务添加标签并解决拒绝事件

比如新添加了一个 java 服务,那么需要在 service.te 中新增对应 type: type new_service, service_manager_type; 然后在 service_contexts 中匹配servicename u:object_r: new_service:s0
最后添加根据报错添加相关政策
native 的服务一般是通过 rc 文件定义的可执行程序拉起并注册进 ServiceManager 的,所以要对可执行程序做如下权限配置:
创建一个新域 newdomain.te
type newdomain, domain;
type newdomain _exec, exec_type, file_type;
init_daemon_domain(newdomain)
在 file_contexts 添加对应标签
Service 地址 u:object_r:newdomain _exec:s0
最后添加相关的政策

payjoy移植过程中遇到过这个问题,同时注意一定要在项目文件中进行配置(不要去配Google那边的了)。部分配置如下:

./service_context.te
# Start of PayJoy changes
payjoy_access_service                     u:object_r:payjoy_access_service:s0
# End of PayJoy changes
./service.te
# Start of PayJoy changes
type payjoy_access_service,     system_server_service, service_manager_type;
# End of PayJoy changes

不要少了任何一步,否则都有可能不成功。

3)新设备节点增加访问权限

bsp 创建了一个新的设备节点,即使权限是 777,android 层也是没有访问权限的。
同样首先在 device.te 中添加定义
type new_device, dev_type;
然后在 file_context 中添加对应标签
device 路径 u:object_r:md_block_device:s0
最后添加相关的政策

总结:对于neverallow 需要缩小权限,明确具体需要对什么添加权限。然后根据需要的类型添加对应的 type 和 context 标签, 最后添加对应的政策。

你可能感兴趣的:(SEAndroid,android,selinux)