最近项目上遇到Android selinux权限配置的问题,Android O之前的版本与Android O及之后的版本有较大的差异。Android O引入了Treble机制,为了防止system.img和vendor.img 中的数据、服务、应用等相互依赖、调用和 引用,谷歌大幅度的更新了selinux权限管理,在Android O及以后的版本中,sepolicy进行了分离,与system相关的sepolicy(对应文件路径:/system/sepolicy)打包到system.img,与vendor相关的sepolicy(对应文件路径:/device/mediatek/sepolicy/basic)打包到vendor.img,在终端上生成策略文件路径分别为/system/etc/sepolicy、/vendor/etc/sepolicy。
selinux的原理等网上已经有文章写的非常好(https://blog.youkuaiyun.com/innost/article/details/19299937),本篇文章主要介绍两种系统下的selinux配置方法
1、基于Android O之前的版本的selinux配置
在selinux配置前要先熟悉整体方案在Android系统中的架构,项目的整体框架大致如下:底层的kernel中有设备驱动程序,建立/dev/node的设备节点,hal层封装具体协议,服务程序service跑在系统system server的进程背景下,通过jni对设备节点进行访问,在service中做相关的安全检查,检查通过的apk与service间通过binder机制进行通信及调用,最终操作设备节点
配置思路:定义主体和客体的安全上下文,定义主体对客体的访问权限,通俗一点即为新增的device定义具体的标签,然后给相应的process开启相应的权限。
具体步骤:将设备节点打上标签,将service定义为system_server type,配置system_server对设备节点的操作权限,将service打上标签,将service加到system server进程中,具体修改如下:
1) init.project.rc
chown system system /dev/node
chmod 0666 /dev/node
2) device.te
type xxx_device,dev_type;
3) file_contexts
/dev/node u:object_r:xxx_device:s0
4) system_server.te
allow system_server xxx_device:chr_file rw_file_perms;
5) service.te
type yyy_server_service, app_api_service,system_server_service,system_manager_type;
6) service_contexts
zzz u:object_r:yyy_server_service:s0
7) frameworks/base/core/java/android/content/Context.java
public static final String YYY_SERVICE = "zzz";
services/java/com/android/server/SystemServer.java
ServiceManager.addService(Context.YYY_SERVICE, yyyService);
2、基于Android O及之后版本的selinux配置
项目的整体框架为:底层的kernel中有设备驱动程序,建立/dev/node的设备节点,中间件封装具体的协议,HIDL提供独立的进程背景,上层应用程序可以通过C和Java与HIDL服务进行进程间通信。与Android O之前的版本相比,服务不再运行在system server进程背景下,有独立的进程背景。
配置思路:配置HIDL可执行程序对设备节点的访问权限,配置HIDL的server和client,调用者可通过成为HIDL的一个client的方式获取对server的访问权限
几个重要角色:设备节点、HIDL可执行程序(生成的HIDL可执行文件)、HIDL server进程(HIDL可执行程序运行时进程)、HIDL service(注册到系统中的HIDL服务,APK通过获取到HIDL service与之通信)、HILD client(最终调用HIDL的应用程序)
配置步骤:将设备节点打上标签,配置HIDL可执行程序对设备节点的访问权限,配置HIDL的server进程允许使用IBinder IPC通信,配置server进程有权限将HIDL service添加到hwservice_manager并找到这个service,配置server和client的绑定关系,这样就可以通过client与server进行通信,具体修改如下:
1) attributes
attribute hal_issue;
attribute hal_issue_client;
attribute hal_issue_server;
2) file_contexts
/dev/node u:object_r:xxx_device:s0 //给设备节点打上标签
/(vendor|system/vendor)/bin/hw/vendor\.yyy\.device@1\.0-service u:object_r:hal_issue_mtk_exec:s0 //给HIDL的可执行程序打上标签
3) hwservice_contexts
vendor.yyy.device::IDevice u:object_r:hal_issue_hwservice:s0 //给HIDL的服务打上标签
4) hwservice.te
type hal_issue_hwservice, hwservice_manager_type;
5) hal_issue.te
binder_call(hal_issue_client, hal_issue_server) //设置允许hal_issue_client进程 binder IPC to hal_issue_server进程
binder_call(hal_issue_server, hal_issue_client) //设置允许进程hal_issue_server binder IPC to hal_issue_client进程
allow hal_issue_client hal_issue_hwservice:hwservice_manager find; //允许hal_issue_client对hal_issue_hwservice有find权限
6) hal_issue_default.te
type hal_issue_mtk, domain;
type hal_issue_mtk_exec, exec_type, file_type, vendor_file_type; //设置HIDL的可执行程序的属性
init_daemon_domain(hal_issue_mtk) // //通过执行hal_zyitong_qti_exec可执行程序设置从init到hal_zyitong_qti守护进程域的转换:如果没有设置,当hal_zyitong_qti 从init进程fork出来执行后,hal_zyitong_qti会被设置成和init进程拥有一模一样的安全上下文,其拥有和init进程一样的权限
;如果设置之后,则当其从init进程fork出来之后,将被设置成hal_zyitong_service.te为hal_zyitong_qti进程配置的安全上下文,其拥有同init进程不一样的权限.
hwbinder_use(hal_issue_mtk) //允许hal_issue_qti进程使用HwBinder IPC
hal_server_domain(hal_issue_mtk, hal_issue) //设置hal_issue_server的实现为hal_issue_mtk进程
add_hwservice(hal_issue_mtk, hal_issue_hwservice) //使hal_issue_mtk有能力将hal_issue_hwservice添加到hwservice_manager并找到这个service
allow hal_issue_mtk xxx_device:chr_file { ioctl read write getattr lock append map open }; //配置hal_issue_mtk对xxx_device的操作权限
hal_client_domain(platform_app, hal_issue) //设置platform_app为hal_issue_client的一个client,从而可以与hal_issue_server通信
8) seapp_contexts
user=_app seinfo=platform name=com.xxx domain=platform_app type=app_data_file levelFrom=user // 设置通过平台签名的apk的进程domain为platform_app
9) init.project.rc
chown system system /dev/node
chmod 0666 /dev/node
以下摘抄自 system/sepolicy/public/te_macros
#####################################
# init_daemon_domain(domain)
# Set up a transition from init to the daemon domain
# upon executing its binary.
define(`init_daemon_domain', `
domain_auto_trans(init, $1_exec, $1)
tmpfs_domain($1)
')
#####################################
# hwbinder_use(domain)
# Allow domain to use HwBinder IPC.
define(`hwbinder_use', `
# Call the hwservicemanager and transfer references to it.
allow $1 hwservicemanager:binder { call transfer };
# Allow hwservicemanager to send out callbacks
allow hwservicemanager $1:binder { call transfer };
# hwservicemanager performs getpidcon on clients.
allow hwservicemanager $1:dir search;
allow hwservicemanager $1:file { read open };
allow hwservicemanager $1:process getattr;
# rw access to /dev/hwbinder and /dev/ashmem is presently granted to
# all domains in domain.te.
')
###########################################
# add_hwservice(domain, service)
# Ability for domain to add a service to hwservice_manager
# and find it. It also creates a neverallow preventing
# others from adding it.
define(`add_hwservice', `
allow $1 $2:hwservice_manager { add find };
allow $1 hidl_base_hwservice:hwservice_manager add;
neverallow { domain -$1 } $2:hwservice_manager add;
')
#####################################
# hal_server_domain(domain, hal_type)
# Allow a base set of permissions required for a domain to offer a
# HAL implementation of the specified type over HwBinder.
#
# For example, default implementation of Foo HAL:
# type hal_foo_default, domain;
# hal_server_domain(hal_foo_default, hal_foo)
#
define(`hal_server_domain', `
typeattribute $1 halserverdomain;
typeattribute $1 $2_server;
typeattribute $1 $2;
')
#####################################
# hal_client_domain(domain, hal_type)
# Allow a base set of permissions required for a domain to be a
# client of a HAL of the specified type.
#
# For example, make some_domain a client of Foo HAL:
# hal_client_domain(some_domain, hal_foo)
#
define(`hal_client_domain', `
typeattribute $1 halclientdomain;
typeattribute $1 $2_client;
#####################################
# binder_call(clientdomain, serverdomain)
# Allow clientdomain to perform binder IPC to serverdomain.
define(`binder_call', `
# Call the server domain and optionally transfer references to it.
allow $1 $2:binder { call transfer };
# Allow the serverdomain to transfer references to the client on the reply.
allow $2 $1:binder transfer;
# Receive and use open files from the server.
allow $1 $2:fd use;
')
#####################################
# app_domain(domain)
# Allow a base set of permissions required for all apps.
define(`app_domain', `
typeattribute $1 appdomain;
# Label ashmem objects with our own unique type.
tmpfs_domain($1)
# Map with PROT_EXEC.
allow $1 $1_tmpfs:file execute;
neverallow { $1 -shell } { domain -$1 }:file no_rw_file_perms;
neverallow { appdomain -shell -$1 } $1:file no_rw_file_perms;
')
注意:在Android P版本中,系统严格限制了untrusted_app对于HIDL服务的访问权限,通过app_domain(application)定义的application,在通过hal_client_domain(application, hal_issue)成为hal_issue_client的client时与系统的never_allow冲突,解决方法是将需要访问HIDL服务的APK使用Android系统签名,同时设置platform_app对HIDL的访问权限