1 背景
基于Android10,在进行sd卡读取权限配置时候,发现只配置AndroidManifest.xml不能解决权限问题,经过多方查找发现当前版本的Android还需要配置SELinux,废话不多说,请看下面的分析。
2 Android的权限问题
AndroidManifest.xml是Android应用的入口文件,它描述了package中暴露的组件(activities,services,等等),他们各自的实现类,各种能被处理的数据和启动位置。除了能声明程序中的Activities,ContentProviders,Services和Intent Receivers,还能指定permissions和instrumentation(安全控制和测试)。
比如需要加入SD卡的读取权限,则需要添加:
1. <uses-permission android:name="android.permission.INTERNET"/>
2. <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
3. <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
注意:6.0后的版本即使添加了权限还是会报错,但是权限声明是必须要加的
在Android10中除了要注意在AndroidManifest.xml中添加权限,还需要关注SELinux的问题。SELinux是Google从android 5.0开始,强制引入的一套非常严格的权限管理机制,主要用于增强系统的安全性。
SELinux出现之前,Linux上的安全模型叫DAC,全称是Discretionary Access Control,翻译为自主访问控制。DAC的核心思想:进程理论上所拥有的权限与执行它的用户的权限相同。比如,以root用户启动Browser,那么Browser就有root用户的权限,在Linux系统上能干任何事情。
显然,DAC太过宽松了,应用获得的权限过多容易造成安全问题。SELinux在DAC之外,设计了一个新的安全模型,叫MAC(Mandatory Access Control),翻译为强制访问控制。MAC的核心思想:即任何进程想在SELinux系统中干任何事情,都必须先在安全策略配置文件中赋予权限。凡是没有出现在安全策略配置文件中的权限,进程就没有该权限。
SELinux中,每个进程都有一个安全属性Security Context。Security Context是一个字符串,主要由三部分组成。例如SEAndroid中,进程的SContext可通过ps -Z命令查看,如下所示:
1. ps -Z
2. LABEL USER PID PPID VSZ RSS WCHAN ADDR S NAME
3. u:r:su:s0 root 6671 6664 33492 2492 sigsuspend 0 S sh
4. u:r:su:s0 root 6673 6671 35972 3216 0 0 R ps
以第一个进程sh的SContext为例,其值为u:r:init:s0,其中:
- u为user的意思。SEAndroid中定义了一个SELinux用户,值为u。
- r为role的意思。role是角色之意,它是SELinux中一种比较高层次,更方便的权限管理思路,即Role Based Access Control(基于角色的访问控制,简称为RBAC)。简单点说,一个u可以属于多个role,不同的role具有不同的权限。RBAC我们到最后再讨论。
- init,代表该进程所属的Domain为su。MAC的基础管理思路其实不是针对上面的RBAC,而是所谓的Type Enforcement Accesc Control(简称TEAC,一般用TE表示)。对进程来说,Type就是Domain。比如sh这个Domain有什么权限,都需要通过[例1]中allow语句来说明。
- S0,SELinux为了满足军用和教育行业而设计的Multi-Level Security(MLS)机制有关。简单点说,MLS将系统的进程和文件进行了分级,不同级别的资源需要对应级别的进程才能访问
例1:
device/*/common/sepolicy/system_app.te
allow system_app proc:file write
根据SELinux语句,表示为:允许(allow)system_app域(domain)中的进程写(write)类型为proc的文件。如果没有在system_app中使用上例中的权限配置allow语句,则system_app就无法往/proc目录下得任何文件中写数据。
这条语句的语法为:
- allow:TE的allow语句,表示授权。除了allow之外,还有allowaudit、dontaudit、neverallow等。
- system_app:source type。也叫subject,domain。
- proc:target type。它代表其后的file所对应的Type。
- file:代表Object Class。它代表能够给subject操作的一类东西。例如File、Dir、socket等。在Android系统中,有一个其他Linux系统没有的Object Class,那就是Binder。
- write:在该类Object Class中所定义的操作。
3 问题分析与解决
当对SD卡进行读写操作时候,即使已经配置了AndroidManifest.xml,使其能够对外置SD卡进行读写,但是在应用中读写SD卡时候仍然报错:
W System.err: java.io.FileNotFoundException: /sys/block/mmcblk1/device/ssr: open failed: EACCES (Permission denied)
原因为:
在AndroidManifest.xml中配置了权限之后,仍然需要配置SELinux的相关权限。因为SELinux有3种操作模式,分别是Disabled、Permissive、Enforcing,在Android中可以通过输入adb命令getenforce来获取当前系统的SELinux状态。Disabled表示SELinux是被禁止的,Permissive只发出警告但不拒绝访问,而Enforcing在发出警告的同时会拒绝访问。
解决办法为:
为了澄清是否因为SELinux导致的问题,可先执行:
setenforce 0(临时禁用掉SELinux)
getenforce(得到结果为Permissive)
如果问题消失了,基本可以确认是SELinux造成的权限问题,需要通过正规的方式来解决权限问题。
遇到权限问题,在kernel的log中一定会打印avc denied提示缺少什么权限,可以通过命令过滤出所有的avc denied,再根据这些log各个击破:
cat /proc/kmsg | grep avc
<5>[67.544398] c4 audit: type=1400 audit(1584583763.943:407): avc:denied { read } for pid=3578 comm="HwBinder:357 8_2" name="u:object_r:default_prop:s0" dev="tmpfs" ino=15134 scontext=u:r: system_app:s0 tcontext=u:object_r: sysfs:s0 tclass=file permissive=0
可以看到有avc denied,且最后有permissive=0,表示不允许。
该问题的解决原则是:缺什么权限补什么权限。
上例中的hal_camera_default权限配置文件一般在:
android根源码目录/device/厂商/硬件型号/common/sepolicy/hal_camera_default.tee
log分析:
缺少什么权限:{read}权限,
谁缺少权限:scontext=u:r: system_app:s0
对哪个文件缺少权限:tcontext=u:object_r: sysfs:s0
什么类型的文件:tclass=file
完整的意思:system_app进程对sysfs类型的file缺少read权限。所以只需要在system_app.tee中添加如下配置语句:
allow system_app sysfs:file { read };
但是添加了上述配置之后编译会报错,通常错误形式为:
libsepol.report_failure: neverallow on line 31 of system/sepolicy/private/domain.te (or line 26746 of policy.conf) violated by allow system_app sysfs:file { read write create setattr open };
libsepol.report_failure: neverallow on line 507 of system/sepolicy/public/app.te (or line 8383 of policy.conf) violated by allow system_app sysfs:file { write };
libsepol.check_assertions: 2 neverallow failures occurred
Error while expanding policy
该错误意思是:在system_app.tee中的配置违反了在system/sepolicy/private/domain.te和system/sepolicy/public/app.te中neverallows规则。
- 修改system/sepolicy/private/domain.te中的内容,增加-system_app
# /sys
neverallow {
coredomain
-init
-ueventd
-vold
-system_app //排除system_app
} sysfs:file no_rw_file_perms;
- 修改system/sepolicy/public/app.te中的内容,注销限制
# Write to various pseudo file systems.
#neverallow { appdomain -bluetooth -nfc }//注销app对sysfs的操作限制
# sysfs:dir_file_class_set write;
neverallow appdomain
proc:dir_file_class_set write;
到此还有最后一步工作需要完成,否在编译会报错:
FAILED: out/target/product/ums512_20c10/obj/ETC/sepolicy_freeze_test_intermediates/sepolicy_freeze_test
/bin/bash -c "(diff -rq -x bug_map system/sepolicy/prebuilts/api/29.0/public system/sepolicy/public ) && (diff -rq -x bug_map system/sepolicy/prebuilts/api/29.0/private system/sepolicy/private ) && (touch out/target/product/ums512_20c10/obj/ETC/sepolicy_freeze_test_intermediates/sepolicy_freeze_test )"
Files system/sepolicy/prebuilts/api/29.0/public/app.te and system/sepolicy/public/app.te differ
[ 0% 97/84946] target C: libsensor_imx586 <= vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/So
vendor/sprd/modules/libcamera/sensor/sensor_drv/classic/Sony/imx586/sensor_imx586_mipi_raw.c:62:31: warning: unused variable 'sns_drv_cxt' [-Wunused-variable]
struct sensor_ic_drv_cxt *sns_drv_cxt = (struct sensor_ic_drv_cxt *)handle;
该错误是因为system/sepolicy/prebuilts/api/29.0/private和system/sepolicy/private文件内容不一致,system/sepolicy/prebuilts/api/29.0/private和system/sepolicy/private文件内容不一致导致的。
通过
diff –Naur system/sepolicy/prebuilts/api/29.0/private system/sepolicy/private
diff –Naur system/sepolicy/prebuilts/api/29.0/private system/sepolicy/private
来查看文件的不同,同步为一致即可。
自此该问题可以得到解决。