Skip to content

HAL Domain Template

追踪 Android 17 HAL 域模板从 attribute 声明、init 启动到 HwBinder/ServiceManager 注册、客户端查找和权限失败。

基于android-17.0.0_r1
AndroidSELinuxHALHwBinder源码阅读

HAL Domain Template ​

本文面向已经读过 Init Domain、System Server Domain、Public Private Policy 和 Binder 基础文章的读者。本文不把 hal_xxx_default 当成一条可以复制的模板命令,而是沿 Android 17 的真实宏、type、service type 和启动规则,解释一个 HAL server 如何被标记、启动、注册,以及 client 为什么必须同时拥有 attribute、service_manager/hwservice_manager 和 Binder 权限。

文章使用 audio HAL 作为主例,因为它同时展示 server、client、HwBinder、稳定 AIDL service、设备节点和跨进程 fd;再用 KeyMint HAL 对照只注册 service_manager 的情况。读完后,读者应能从一个 hal_foo_default.te 反查其 owner、入口 executable、服务消费者、权限边和失败位置。

1. HAL对象 ​

1.1 三种身份 ​

HAL 策略中至少有三种不同对象:

对象示例owner消费者
进程 domainhal_audio_defaultinit 启动的 HAL 进程kernel/服务代码
HAL attributehal_audio, hal_audio_server, hal_audio_clientpolicy 宏allow/neverallow
服务 typehal_audio_hwservice, hal_audio_servicehwservicemanager/servicemanagerclient find、server add

hal_audio attribute 不是进程 context,hal_audio_service 也不是 executable file type。一个可运行的 server 通常同时需要 domain、*_exec 文件 type、server attribute 和 service registration 规则。

1.2 真实主例 ​

源码文件:system/sepolicy/vendor/hal_audio_default.te

text
type hal_audio_default, domain;
hal_server_domain(hal_audio_default, hal_audio)
type hal_audio_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_audio_default)
hal_client_domain(hal_audio_default, hal_allocator)
hal_client_domain(hal_audio_default, hal_bluetooth)

这 7 行并没有直接写 allow。它们把职责分发给不同宏:hal_server_domain 绑定 server attribute,init_daemon_domain 负责 init 到 HAL 的启动 transition,hal_client_domain 绑定另一个 HAL 的 client attribute。真正的设备节点、服务注册和 Binder 规则在 private/hal_audio.te 等文件中。

2. Attribute宏 ​

2.1 hal_attribute ​

源码文件:system/sepolicy/public/te_macros

text
define(`hal_attribute', `
attribute hal_$1;
expandattribute hal_$1 true;
attribute hal_$1_client;
expandattribute hal_$1_client true;
attribute hal_$1_server;
expandattribute hal_$1_server false;
neverallow { hal_$1_server -halserverdomain } domain:process fork;
build_test_only(`
  neverallow { hal_$1_server -hal_$1 } domain:process fork;
  neverallow { hal_$1_client -halclientdomain } domain:process fork;
')
')

源码文件:system/sepolicy/public/attributes

text
hal_attribute(audio);
hal_attribute(allocator);
hal_attribute(keymint);
hal_attribute(wifi_supplicant);

对 audio 展开后,policy 获得 hal_audio、hal_audio_client、hal_audio_server 三个 attribute。server attribute 默认不展开,便于策略对 server 集合做更精确控制;client attribute 为性能而展开。neverallow 防止一个被标成特定 HAL server 的 domain 在没有 halserverdomain 身份时 fork 任意 domain。

2.2 server与client ​

源码文件:system/sepolicy/public/te_macros

text
define(`hal_server_domain', `
typeattribute $1 halserverdomain;
typeattribute $1 $2_server;
typeattribute $1 $2;
')

define(`hal_client_domain', `
typeattribute $1 halclientdomain;
typeattribute $1 $2_client;
allow $1 $2:memfd_file { read write getattr map };
allow $2 $1:memfd_file { read write getattr map };
not_full_treble(`
  typeattribute $1 $2;
  allow $2 system_file:dir r_dir_perms;
  allow $2 vendor_file:dir r_dir_perms;
  allow $2 vendor_file:file { read open getattr execute map };
')
')

hal_server_domain(D, hal_audio) 把 D 加入 halserverdomain、hal_audio_server 和 hal_audio;hal_client_domain(D, hal_audio) 只加入 halclientdomain 与 hal_audio_client,并增加 HAL 间共享 memfd 的双向访问。在 non-full-Treble 条件下,client 还会获得 passthrough HAL 的文件查找权限;full-Treble 不展开这段,因此不能把 passthrough 行为外推到所有设备。

2.3 双重角色 ​

源码文件:system/sepolicy/vendor/mediacodec.te

text
hal_server_domain(mediacodec, hal_codec2)
hal_server_domain(mediacodec, hal_omx)
hal_client_domain(mediacodec, hal_allocator)
hal_client_domain(mediacodec, hal_graphics_allocator)

mediacodec 同时是两个 HAL 的 server 和两个 HAL 的 client。attribute 是按接口角色聚合,不是按进程数量聚合;一个 domain 可以拥有多个角色,但每个角色仍需对应的 service/device/Binder 规则。

3. 启动与注册 ​

3.1 init transition ​

源码文件:system/sepolicy/vendor/hal_audio_default.te、system/sepolicy/private/te_macros

text
type hal_audio_default_exec, exec_type, vendor_file_type, file_type;
init_daemon_domain(hal_audio_default)

init_daemon_domain 展开 domain_auto_trans(init, hal_audio_default_exec, hal_audio_default) 和 tmpfs 规则。file_contexts 必须把 /vendor/bin/hw/... 标成 hal_audio_default_exec;否则 init 计算到的 process context 可能仍是 init 或进入错误 domain。

源码文件:system/core/init/service.cpp

cpp
std::string scon;
if (!seclabel_.empty()) {
    scon = seclabel_;
} else {
    auto result = ComputeContextFromExecutable(args_[0]);
    if (!result.ok()) {
        return result.error();
    }
    scon = *result;
}

init 在 fork 前决定 service context;rc 显式 seclabel 优先于基于 executable 的 security_compute_create。HAL service 的最终 domain 因此取决于 rc、file_contexts、transition 和 entrypoint 四者,而不只是 .te 中的一条宏调用。

3.2 server注册 ​

源码文件:system/sepolicy/private/hal_audio.te

text
binder_call(hal_audio_client, hal_audio_server)
binder_call(hal_audio_server, hal_audio_client)
hal_attribute_hwservice(hal_audio, hal_audio_hwservice)
hal_attribute_service(hal_audio, hal_audio_service)
binder_call(hal_audio_server, servicemanager)
vndbinder_use(hal_audio)

源码文件:system/sepolicy/public/te_macros

text
define(`hal_attribute_hwservice', `
allow $1_client $2:hwservice_manager find;
add_hwservice($1_server, $2)
build_test_only(`
  neverallow { domain -$1_client -$1_server } $2:hwservice_manager find;
')
')

define(`hal_attribute_service', `
allow $1_client $2:service_manager find;
add_service($1_server, $2)
build_test_only(`
  neverallow { domain -$1_client -$1_server -atrace -shell -system_app -traceur_app } $2:service_manager find;
')
')

hal_attribute_hwservice 为 client 增加 hwservice_manager find,并让 server 通过 add_hwservice 注册;hal_attribute_service 对稳定 AIDL/service_manager 做同样配对。两者都不代替 server 与 client 的 Binder call 规则,所以 audio policy 还显式写了两个方向的 binder_call。

3.3 service type ​

源码文件:system/sepolicy/public/hwservice.te、system/sepolicy/public/service.te

text
type hal_audio_hwservice, hwservice_manager_type, protected_hwservice;
type hal_audio_service, protected_service, hal_service_type, service_manager_type;
type hal_keymint_service, protected_service, hal_service_type, service_manager_type;

protected_hwservice/protected_service 是服务类型的安全属性,限制未授权 client 的查找。hal_audio_hwservice 与 hal_audio_service 是否存在、由谁 add、谁 find,分别由宏展开和具体 allow 共同决定。

4. HAL资源 ​

4.1 音频设备 ​

源码文件:system/sepolicy/private/hal_audio.te

text
allow hal_audio_server audio_device:dir r_dir_perms;
allow hal_audio_server audio_device:chr_file rw_file_perms;
allow hal_audio_server self:global_capability_class_set sys_nice;
neverallow hal_audio_server { file_type fs_type }:file execute_no_trans;
neverallow { halserverdomain -hal_audio_server -hal_omx_server } audio_device:chr_file *;

HAL server 可以读写 audio_device,但所有 HAL server 中只有 audio server 与 omx server 被允许直接访问该设备;其他 HAL server 即使属于 halserverdomain 也被 neverallow 排除。execute_no_trans 禁止 audio server 在未发生 domain transition 时执行任意 file/fs type。

4.2 共享内存 ​

源码文件:system/sepolicy/private/hal_audio.te、system/sepolicy/public/te_macros

text
allow hal_audio_server appdomain:fd use;
allow hal_audio_server system_server_tmpfs:file { getattr map read };
allow hal_audio_server system_server:memfd_file { getattr map read };
allow hal_audio_server self:global_capability_class_set sys_nice;

音频 HAL 通过 fd 使用 app 共享内存,通过 system_server tmpfs/memfd 读取 system_server 传来的缓冲区。hal_client_domain 生成的 memfd 规则是接口级基础,具体 fd 传递仍可能在 HAL 专用 policy 中补充。

4.3 client查找 ​

源码文件:system/sepolicy/private/system_server.te、system/sepolicy/private/hal_audio.te

text
hal_client_domain(system_server, hal_audio)
allow hal_audio_client hal_audio_service:service_manager find;
allow system_server hal_audio_service:service_manager find;

system_server 作为 hal_audio client 通过 attribute 获得 HAL 共享 memfd 等基础关系,具体 service_manager find 仍可由 HAL policy 或 system_server policy 显式提供。若只有 server add 没有 client find,服务已注册但客户端仍会在查找阶段失败。

5. 安全约束 ​

5.1 fork边界 ​

源码文件:system/sepolicy/public/te_macros、system/sepolicy/private/hal_audio.te

text
neverallow { hal_audio_server -halserverdomain } domain:process fork;
neverallow hal_audio_server { file_type fs_type }:file execute_no_trans;
neverallow { halserverdomain -hal_audio_server -hal_omx_server } audio_device:chr_file *;

第一条来自 hal_attribute(audio) 的 server 约束,后两条是 audio 专用限制。它们分别保护 domain 角色、执行入口和硬件设备独占性。neverallow 在 policy 编译时验证,不能通过运行时 permissive 绕过。

5.2 受保护服务 ​

源码文件:system/sepolicy/public/service.te、system/sepolicy/public/hwservice.te

text
type hal_audio_service, protected_service, hal_service_type, service_manager_type;
type hal_audio_hwservice, hwservice_manager_type, protected_hwservice;

protected type 让服务 manager 的访问默认更严格;真正的 find/add 仍由 hal_attribute_service/hal_attribute_hwservice 和具体 policy 组合。不要只看 service type 的名字判断调用者权限。

6. 失败路径 ​

6.1 启动失败 ​

现象代码边界典型原因
init 报 no domain transitionComputeContextFromExecutableexecutable label 错或缺 transition
child 在 setexeccon 终止Service::SetProcessAttributesAndCapsrc seclabel 无效或未授权
HAL 进程 exec 后退出HAL 自身初始化设备节点、property 或 capability denial
service 已启动但 client 找不到hwservice/service_manager缺少 client find 或注册 type 不一致
Binder call 被拒绝Binder class缺少 client/server binder_call 或 fd use

6.2 lazy/重启 ​

HAL 是否 lazy、何时退出和是否重启由 init rc、servicemanager/hwservicemanager 和 HAL 实现共同决定。SELinux 只提供 add/find/call 等访问边;不能从 hal_server_domain 推导 lazy 生命周期。排查服务重启时要把 init service 状态、manager 注册记录和 AVC 分开记录。

7. 测试与诊断 ​

7.1 policy查询 ​

sh
# Locate one HAL's server/client and service edges.
rg -n 'hal_audio_(server|client)|hal_attribute_(hwservice|service).*hal_audio' \
  system/sepolicy/public system/sepolicy/private system/sepolicy/vendor

# Inspect final policy relationships separately by class.
sesearch -A -s hal_audio_default -c binder
sesearch -A -s system_server -c hwservice_manager -t hal_audio_hwservice
sesearch -A -s system_server -c service_manager -t hal_audio_service

# Check runtime labels and service registration consumers.
adb shell 'ps -AZ | grep -E "hal_audio|audioserver"'
adb shell 'lshal 2>/dev/null | grep -i audio || true'

第一条确认宏和 type 的来源,第二、三条分别查询 Binder、HwServiceManager 和 ServiceManager class,第四条确认运行中的 domain 与注册结果。sesearch 只能证明策略中存在规则,不能证明 HAL 当前成功启动或硬件可用。

7.2 设备标签 ​

源码文件:system/sepolicy/vendor/hal_audio_default.te、system/sepolicy/private/file_contexts

sh
# Verify that the executable path resolves to the HAL exec type.
adb shell 'ls -Z /vendor/bin/hw | grep -i audio'

# Compare the process label after init transition.
adb shell 'ps -AZ | grep hal_audio'

# Read AVC fields for the failed target class/permission.
adb shell 'dmesg | grep "avc: denied" | grep -E "hal_audio|audio_device"'

输入是 executable 路径、运行进程和 AVC 日志;断言分别是 file type、process scontext 和 tcontext/tclass/permission。它不能替代 VINTF、HAL API 版本或硬件功能测试。

7.3 反向证据 ​

Android 17 的 HAL policy 组合主要由 policy 编译、neverallow、CTS/VTS 和具体 HAL 测试反向验证。以 audio 为例,策略允许 audio_device 访问并禁止其他 halserverdomain 访问;这证明“设备独占边界”,不证明每个音频设备节点在所有产品配置中都存在。KeyMint、camera、wifi 等 HAL 还拥有各自服务 type 和附加资源规则,不能由 audio 的宏展开直接外推。

8. 源码导航 ​

  1. system/sepolicy/public/te_macros:hal_attribute、hal_server_domain、hal_client_domain、hal_attribute_service 和 hal_attribute_hwservice。
  2. system/sepolicy/public/attributes:所有 HAL attribute 的声明入口。
  3. system/sepolicy/vendor/hal_audio_default.te:具体 HAL server domain 的最小模板。
  4. system/sepolicy/private/hal_audio.te:audio server/client Binder、HwBinder、设备节点和 neverallow。
  5. system/sepolicy/public/service.te、hwservice.te:受保护 service/hwservice type。
  6. system/core/init/service.cpp:executable context 计算和 child exec。
  7. frameworks/base/core/jni/com_android_internal_os_Zygote.cpp:system_server/app specialization 的对照实现。
  8. external/selinux/libselinux/src/android:security_compute_create、service label 和 seapp context 的 native 消费者。

用 hal_audio_default 做练习:先从 .te 的 7 行宏调用展开 attribute,再沿 hal_audio.te 找 add/find/call/device 四类边,最后用 ls -Z、ps -AZ、sesearch 和 AVC 日志验证。若删除 hal_audio_client 的 find、删除 server 的 entrypoint 或把 audio_device allow 扩大到 halserverdomain,应能分别预测查找失败、进程 exec 失败和 neverallow 编译失败。