假设我们已经写了一个AIDL HAL驱动模块,AIDL接口包名为android.hardware.aidltest,ITest, 输出的instance为default,AIDL实现模块为服务进程,编译在vendor分区,服务程序名称为android.hardware.aidltest.service,那么在/vendor/bin/hw目录会生成android.hardware.aidltest.service的可执行程序,我们配置成init进程在启动后加载。
在这种情况下,如果不配置selinux策略,init进程无法拉起进程,服务也无法注册进server_manager,客户端程序也无法调用。这受到selinux严格限制,每一步都需要有对应的策略以及上下文。
一、在BoardConfig.mk中配置selinux目录,比如:
BOARD_VENDOR_SEPOLICY_DIRS += vendor/soc/sphone/sepolicy
二、在vendor/soc/sphone/sepolicy 中创建file_contexts, service_contexts,hal_aidltest_default.te三个文件
在上一篇中已经说明file_contexts是linux selinux内核支持的,而service_contexts则是android扩展的,hal_aidltest_default.te则是策略文件,是selinux规定的语法。
#file_contexts内容如下,声明了vendor或者system/vendor目录。
/(vendor|system/vendor)/bin/hw/android\.hardware\.aidltest\.service u:object_r:hal_aidltest_default_exec:s0
#两个都是vendor分区,只不过system分区会将vendor分区连接到自身的vendor文件夹,本质就是同一个分区
#声明/vendor/bin/hw/android.hardware.aidltest.service这个可执行程序的上下文为u:object_r:hal_aidltest_default_exec:s0
#只是打了一个标签,其中标签类型是hal_aidltest_default_exec,这是通用写法
#service_contexts文件内容如下
android.hardware.aidltest.ITest/default u:object_r:hal_aidltest_service:s0
#声明了aidl服务android.hardware.aidltest.ITest/default
#它的标签是u:object_r:hal_aidltest_service:s0,所以类型为hal_aidltest_service
#hal_aidltest_default.te 文件内容如下,后面有对每一行的解释
hal_attribute(aidltest);
type hal_aidltest_default, domain, mlstrustedsubject;
hal_server_domain(hal_aidltest_default, hal_aidltest);
type hal_aidltest_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_aidltest_default);
binder_call(hal_aidltest_client, hal_aidltest_default)
type hal_aidltest_service, service_manager_type;
add_service(hal_aidltest_default, hal_aidltest_service)
allow hal_aidltest_client hal_aidltest_service:service_manager find;
hal_client_domain(system_server, hal_aidltest)
allow hal_aidltest_default servicemanager:binder { call transfer };
allow { platform_app shell } hal_aidltest:binder {call};
语句 | 等价于 | 说明 |
---|---|---|
hal_attribute(aidltest); | attribute hal_aidltest; attribute hal_aidltest_client; attribute hal_aidltest_server; neverallow { hal_aidltest_server -halserverdomain } domain:process fork; | expandattribute 属性名 true 可以忽略,它是一种编译优化,决定编译时是否展开,hal_attribute这个宏其实就是定义了三个属性,这三个属性名称依据的是传入的参数名, neverallow指定了不允许任何hal_aidltest_server类型进程执行fork,除了halserverdomain类型 |
type hal_aidltest_default, domain, mlstrustedsubject; | 声明类型hal_aidltest_default ,并赋予domain,mlstrustedsubject属性 | |
hal_server_domain(hal_aidltest_default, hal_aidltest); | typeattribute hal_aidltest_default halserverdomain; typeattribute hal_aidltest_default hal_aidltest_server; typeattribute hal_aidltest_default hal_aidltest; | 将类型hal_aidltest_default赋予halserverdomain,hal_aidltest_server,hal_aidltest三个属性 |
type hal_aidltest_default_exec, exec_type, vendor_file_type, file_type; | 声明hal_aidltest_default_exec类别,并赋予exec_type,vendor_file_type,file_type属性 | |
init_daemon_domain(hal_aidltest_default); | domain_auto_trans(init, hal_aidltest_default_exec, hal_aidltest_default) 同时等价于 type_transition init hal_aidltest_default_exec:process hal_aidltest_default; | init进程执行hal_aidltest_default_exec程序时,进程的安全上下文从hal_aidltest_default_exec转换为hal_aidltest_default安全上下文 |
binder_call(hal_aidltest_client, hal_aidltest_default) | allow hal_aidltest_client hal_aidltest_default_exec:binder{call transfer} allow hal_aidltest_default hal_aidltest_client:binder transfer; allow hal_aidltest_client hal_aidltest_default:fd use; | 允许具备hal_aidltest_client属性的所有类型进程对hal_aidltest_default类别的binder对象执行 call transfer 允许hal_aidltest_default(服务)类别进程对所有具备hal_aidltest_client属性的binder对象执行transfer 允许具备hal_aidltest_client属性的所有类型进程 使用hal_aidltest_default类型的fd |
type hal_aidltest_service, service_manager_type; | 声明hal_aidltest_service类型,并赋予service_manager_type属性 | |
add_service(hal_aidltest_default, hal_aidltest_service) | allow hal_aidltest_default hal_aidltest_service:service_manager { add find }; neverallow { domain -hal_aidltest_default }hal_aidltest_service:service_manager add; | 允许hal_aidltest_default类型进程对hal_aidltest_service类型的service_manager对象进程add和find操作 不允许除了hal_aidltest_default类型的进程对hal_aidltest_service类型的service_manager对象进行add操作 |
allow hal_aidltest_client hal_aidltest_service:service_manager find; | 允许具备hal_aidltest_client属性的所有进程对hal_aidltest_service类型的service_manager对象执行find操作 | |
hal_client_domain(system_server, hal_aidltest) | typeattribute system_server halclientdomain; typeattribute system_server hal_aidltest_client; not_full_treble(` typeattribute system_server hal_aidltest; allow hal_aidltest system_file:dir r_dir_perms; allow hal_aidltest vendor_file:dir r_dir_perms; allow hal_aidltest vendor_file:file { read open getattr execute map }; | 将system_server类型赋予halclientdomain和hal_aidltest_client属性 将system_server 赋予hal_aidltest属性 允许具备hal_aidltest属性的所有类型(进程)对system_file类型的目录对象,执行读操作 允许具备hal_aidltest属性的所有类型(进程)对vendor_file类型的目录对象,执行读操作允许具备hal_aidltest属性的所有类型(进程)对vendor_file类型的文件对象,执行read open gettattr excute map操作 |
allow hal_aidltest_default servicemanager:binder { call transfer }; | 允许hal_aidltest_default类型进程对servicemanager类型的binder对象执行call transfer操作 | |
allow { platform_app shell } hal_aidltest:binder {call}; | 允许平台app进程和shell进程对具备hal_aidltest属性的所有binder对象执行call |
最终selinux策略会经过编译系统编译进/vendor/etc/selinux目录中,然后打包成镜像程序就能正确运行了,在写selinux规则的时候会有点绕,不过总体而言就是定义类型,声明类型有哪些属性,然后写允许的规则,要写出这份策略文件需要对android selinux定义的原生属性类型对象比较熟悉,这个事情非常考验耐心。