Android R(11)HIDL服务的sepolicy(五)

本文介绍了Android从4.4版本开始引入的强制访问控制(MAC)框架——SELinux,它与传统的自主访问控制(DAC)结合,提升了系统文件和程序的安全性。SELinux通过严格的策略规则限制进程访问,支持调试和产品两种模式。文章详细阐述了SELinux的基本概念,如DAC与MAC的区别、标签系统和域类型,并展示了如何在Android中添加自定义的sepolicy规则。此外,还提供了查看系统标签的工具和示例,帮助理解SELinux在实际操作中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

  在Android安全组件中,除了使用传统DAC(Discretionary Access Control)的方式来保护系统文件。但在版本4.4及以后还引入并开启了MAC(Mandatory Access Control)安全框架,使用DAC+MAC组合的方式来保护系统文件及可执行程序的安全。其中被Android所采用的MAC保护框架为SELinux(Security-Enhanced Linux)。

1.Security-Enhanced Linux in Android

  开启了MAC框架后,即使是Root用户或具备super权限的进程也会需要完全遵照sepolicy的规则来访问文件。SELinux可以为Android带来如下好处
  a).更好地保护和限制系统服务。
  b).控制对应用数据和系统日志的访问、降低恶意软件的影。
  c).保护用户免遭移动设备上的代码可能存在的缺陷的影响。

  SELinux设计时的控制原则为:任何没有被规则允许的操作都会被禁止。但是SELinux框架是支持两种控制模式的
  1.Permissive mode, 在不被允许的操作发生后,只是log方式提示,但不禁止。这种模式也只用于调试阶段。
  2.Enforcing mode, 在不被允许的操作发生后,除了log方式提示,并且禁止该操作。这种模式则是产品阶段。

2.SELinux 的基本概念

2.1 DAC和MAC的区别

  DAC方式,存在所有权的概念,即特定资源的所有者可以控制与该资源关联的访问权限。这种系统通常比较粗放,并且容易出现无意中提权的问题。MAC框架方式则会严格按照预先定义好的sepolicy来允许/拒绝操作。受DAC和MAC同时保护的系统中不会出现获取root的进程能为所欲为的场景。例如,软件通常情况下必须以Root用户帐号的身份运行,才能向原始块设备写入数据。但在基于DAC的传统系统中,如果Root用户遭到入侵,攻击者便可以利用该用户身份向每个原始块设备写入数据。但是在MAC系统中可以使用sepolicy为这些设备添加标签,即使被分配了 Root权限的进程也只可以向相关政策中指定的设备写入数据。这样一来,该进程便无法重写特定原始块设备之外的数据和系统设置。

2.2 Labels, rules, and domains

  SELinux依靠标签(Labels)来匹配操作和政策。标签用于决定允许的事项。套接字(socket)、文件(file)和进程(process)在SELinux中都有标签。SELinux在做决定时需参照以下两点:
  a)为对象(socket/file/process/etc…)分配正确的标签。
  b)定义对象的交互政策。

  在 SELinux 中,标签采用以下形式
user:role:type:mls_level,主要注意下type就行了。一个基本的规则如下

allow domains types:classes permissions;

其中:
  Domain: 一个进程或一组进程的标签。也称为域类型,因为它只是指进程的类型。
  Type: 一个对象(例如,文件、套接字)或一组对象的标签。
  Class: 要访问的对象(例如,文件、套接字)的类型。
  Permission: 要执行的操作(例如,读取、写入)。
下面则是一个具体的使用实例

allow appdomain app_data_file:file rw_file_perms;

这表示所有appdomain都可以读取和写入带有 app_data_file 标签的文件。一个 domain 通常对应一个进程,而且具有与其关联的标签。至此sepolicy的基本规则也说的差不多了,下面进入正题。

3.添加sepolicy规则到Android

  sepolicy的添加也需要使用到Android的编译系统,下面则是添加自定义sepolicy的写法

//test/flagstaffTest/BoardConfig.mk 
BOARD_VENDOR_SEPOLICY_DIRS += \
    test/flagstaffTest/sepolicy

  BOARD_VENDOR_SEPOLICY_DIRS关键字用于告知编译系统哪些目录下包含sepolicy,对于测试代码的sepolicy都放置于目录test/flagstaffTest/sepolicy下。其结构如下

flagstaff@flagstaff-pc:~/aosp_r.lns/test/flagstaffTest$ tree sepolicy/
sepolicy/
├── file_contexts
├── hal_customehardware_default.te
├── hwservice_contexts
└── hwservice.te

3.1.file_contexts

//file:file_contexts
type hal_customehardware_hwservice, hwservice_manager_type;

  定义标签hal_customehardware_hwservice,并且其继承自标签hwservice_manager_type,即针对hwservice_manager_type标签的规则也适用于hal_customehardware_hwservice。hwservice_manager_type则是android团队专门为HIDL服务预制的宏定义,其内部包含了HIDL服务必须的权限规则。

3.2.hal_customehardware_default.te

//file:hal_customehardware_default.te
type hal_customehardware_default, domain;
type hal_customehardware_default_exec,exec_type,vendor_file_type,file_type;
init_daemon_domain(hal_customehardware_default);
allow hal_customehardware_default hwservicemanager:binder { call transfer };
//允许标签为hal_customehardware_default的进程访问标签为hwservicemanager_prop的属性。
get_prop(hal_customehardware_default, hwservicemanager_prop)
/*
    Ability for domain to add a service to hwservice_manager
    and find it. It also creates a neverallow preventing
    others from adding it.
*/
add_hwservice(hal_customehardware_default, hal_customehardware_hwservice);

  1.定义标签hal_customehardware_default ,并且继承自 domain。domain则代表可执行程序。
  2.定义标签hal_customehardware_default_exec,并且继承自exec_type,vendor_file_type,file_type。该标签作用于文件。
  3.init_daemon_domain 则是宏定义,使用m4语言书写,展开如下

//file:system/sepolicy/public/te_macros
define(`domain_trans', `
allow $1 $2:file { getattr open read execute map };
allow $1 $3:process transition;
allow $3 $2:file { entrypoint open read execute getattr map };
ifelse($1, `init', `', `allow $3 $1:process sigchld;')
dontaudit $1 $3:process noatsecure;
allow $1 $3:process { siginh rlimitinh };
')
define(`domain_auto_trans', `
domain_trans($1,$2,$3)
type_transition $1 $2:process $3;
')
define(`init_daemon_domain', `
domain_auto_trans(init, $1_exec, $1)
')

  所以init_daemon_domain(hal_customehardware_default)展开如下

init_daemon_domain(hal_customehardware_default)
    allow init hal_customehardware_default_exec:file { getattr open read execute map };
    allow init hal_customehardware_default:process transition;
    allow hal_customehardware_default hal_customehardware_default_exec:file { entrypoint open read execute getattr map };
    allow hal_customehardware_default init:process sigchld;
    dontaudit init hal_customehardware_default:process noatsecure;
    allow init hal_customehardware_default:process { siginh rlimitinh };
    type_transition init hal_customehardware_default_exec:process hal_customehardware_default;

  展开后宏的意图就很明朗了,主要还是为HIDL服务添加必须的规则,提炼公共部分,减少代码量。

3.3.hwservice_contexts

//file:hwservice_contexts
flagstaff.hardware.custom_hardware::ICustomHardware   u:object_r:hal_customehardware_hwservice:s0

  为HIDL接口添加sepolicy,在android中任何资源都是被管控的,管控的越细腻,系统的安全度也就越高。

3.4.hwservice.te

//file:hwservice.te
/vendor/bin/hw/flagstaff.hardware.custom_hardware@1.0-service         u:object_r:hal_customehardware_default_exec:s0

  为可执行程序flagstaff.hardware.custom_hardware@1.0-service的标签为u:object_r:hal_customehardware_default_exec:s0。
 经过上述配置后,flagstaff.hardware.custom_hardware@1.0-service运行时标签为hal_customehardware_default。

4.规则查看工具

4.1 查看文件的标签

ls -Z

4.2 查看执行程序的标签

ps -Z

  另外如果有问题,欢迎留言或者email(836190520@qq.com)我,技术升级在于交流~~

<think>我们正在解决Android 9中使用HIDL时出现的'Cannot find entry'错误。 根据引用[1]中的信息,类似错误可能是由于VNDK库列表不一致导致的。在Android构建系统中,VNDK(Vendor Native Development Kit)库是供应商实现HAL所依赖的核心库。如果HAL模块被错误地添加到VNDK列表中,但未在相应的current.txt或版本特定的txt文件(如30.txt)中列出,就会导致编译错误。 但是,用户遇到的是运行时错误('Cannot find entry'),而不是编译错误。因此,我们需要从运行时加载HIDL服务的角度来考虑。 常见原因: 1. HAL服务未正确注册:HIDL服务需要在设备启动时注册到hwservicemanager中。如果服务没有注册,客户端尝试获取服务时就会报告“Cannot find entry”。 2. SELinux策略限制:SELinux可能阻止了服务进程的启动或注册。 3. 服务二进制文件缺失或权限问题:HAL服务可执行文件可能不在系统分区中,或者没有执行权限。 4. 服务未启动:可能是init.rc脚本中服务定义有误,导致服务未启动。 解决方案步骤: 步骤1:检查服务是否注册 在设备上执行: ```shell adb shell hidl-ls ``` 或者对于特定接口(假设接口为android.hardware.foo@1.0::IFoo): ```shell adb shell hidl-ls android.hardware.foo@1.0::IFoo ``` 如果列表中不存在,则服务未注册。 步骤2:检查服务进程是否运行 使用ps命令查看服务进程是否在运行。例如,如果服务进程名为vendor.foo_service,则: ```shell adb shell ps -A | grep foo_service ``` 步骤3:检查init.rc文件 确保在设备的vendor/etc/init/目录下有对应的init.rc文件(例如vendor.foo_service.rc),并且其中定义了服务启动命令和接口注册。 示例init.rc文件内容: ``` service vendor.foo_service /vendor/bin/hw/foo_service class hal user system group system ``` 步骤4:检查SELinux策略 查看日志中是否有avc拒绝信息: ```shell adb logcat | grep avc ``` 如果有,需要添加相应的SELinux规则。 步骤5:检查manifest.xml文件 确保在vendor/manifest.xml(或类似的位置)中声明了HIDL服务。例如: ```xml <hal format="hidl"> <name>android.hardware.foo</name> <transport>hwbinder</transport> <version>1.0</version> <interface> <name>IFoo</name> <instance>default</instance> </interface> </hal> ``` 步骤6:检查HIDL_FETCH_*函数 在服务实现中,必须实现HIDL_FETCH_*函数(例如HIDL_FETCH_IFoo)并返回接口的实例。确保该函数被正确实现且没有返回nullptr。 步骤7:检查服务可执行文件 确保服务可执行文件被正确推送到设备的/vendor/bin/hw/目录下,并具有执行权限(权限应为755)。 如果以上步骤都检查无误,问题应该可以解决。 引用[2]和[3]提到了HAL实现文件的位置,这提醒我们在开发HIDL服务时,代码应放在正确的目录下(如vendor/.../interfaces/...)。同时,引用[4]提到了系统启动的早期阶段,如果服务需要在引导早期启动,应确保它被放置在正确的启动类中(如`class hal`)。 根据经验,最常见的错误是init.rc文件配置错误或SELinux权限问题。 如果问题仍然存在,请提供更详细的错误日志,以便进一步分析。 生成相关问题: 1. 如何调试HIDL服务无法注册的问题? 2. 在Android HIDL开发中,如何正确配置init.rc文件? 3. 如何为HIDL服务添加SELinux策略? 4. Android HIDL服务的启动过程是怎样的?</think>### Android 9 HIDL "Cannot find entry" 错误解决方案 该错误通常发生在 HIDL 服务未正确注册或客户端无法定位服务实现时,以下是系统级排查方案: #### 1. **检查 HIDL 服务注册状态** - 在设备上执行命令验证服务是否注册: ```shell adb shell hidl-ls -r # 列出所有已注册的 HIDL 服务 ``` 若目标服务(如 `android.hardware.foo@1.0::IFoo`)未列出,说明服务未正确注册。 #### 2. **验证 manifest 声明** - 确保在 `manifest.xml` 中声明了 HIDL 接口: ```xml <!-- 示例:vendor/manifest.xml --> <hal format="hidl"> <name>android.hardware.foo</name> <transport>hwbinder</transport> <version>1.0</version> <interface> <name>IFoo</name> <instance>default</instance> </interface> </hal> ``` 文件路径参考:`vendor/<vendor>/<device>/manifest.xml`[^3] #### 3. **检查 init.rc 服务启动** - 确认服务在 `init.rc` 中正确启动: ```rc # 示例:vendor/etc/init/hw/foo_service.rc service vendor.foo_service /vendor/bin/hw/foo_service class hal user system group system ``` - 重启服务并检查日志: ```shell adb shell stop vendor.foo_service adb shell start vendor.foo_service adb logcat | grep foo_service ``` #### 4. **验证 SELinux 策略** - 检查 avc 拒绝日志: ```shell adb shell dmesg | grep avc ``` - 添加缺失策略(示例): ```te # 文件:device/<vendor>/sepolicy/vendor/foo_service.te allow foo_service hwservicemanager_prop:file read; allow foo_service hwservice_manager:service_manager add; ``` #### 5. **检查 VNDK 兼容性** - 确认 `current.txt` 包含所需库(Android 9 对应 `28.txt`): ```txt # 文件:build/make/target/product/vndk/28.txt libhidlbase.so libhidltransport.so ``` 若缺失关键库,需在 `device.mk` 添加: ```makefile PRODUCT_PACKAGES += libhidlbase libhidltransport ``` 此错误通常由 VNDK 库列表不一致引起[^1]。 #### 6. **验证 HIDL_FETCH_ 实现** - 在服务实现中确保导出符号: ```cpp // 文件:vendor/xxx/hardware/foo/1.0/service.cpp extern "C" IFoo* HIDL_FETCH_IFoo(const char* /* name */) { return new FooImplementation(); // 必须返回有效实例 } ``` - 检查映射文件: ```map # 文件:vendor/xxx/hardware/foo/1.0/Android.bp symbols_file: "foo.hidl.28.map.txt" ``` #### 7. **清除构建缓存** - 删除中间文件后重新编译: ```shell make clean make -j24 ``` > **关键日志定位**:搜索 `hwservicemanager` 相关日志: > ```shell > adb logcat | grep -E 'hwservicemanager|HIDL' > ``` --- ### 相关问题 1. 如何调试 HIDL 服务的 SELinux 权限问题? 2. Android 9 的 VNDK 机制与旧版本有何区别? 3. HIDL 服务注册失败时如何分析 `hwservicemanager` 日志? 4. 如何为自定义 HIDL 接口编写正确的 `manifest.xml` 声明? [^1]: VNDK 库列表不一致导致的编译错误 [^2]: HAL 实现文件路径参考 [^3]: HIDL 接口定义文件位置 [^4]: 系统服务启动阶段说明
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值