Android Automotive 安全架构:系统分区、SELinux策略、用户权限模型
好,咱们今天聊聊 Android Automotive 的安全架构。说实话,车载系统和手机上的 Android 虽然同源,但安全模型差别挺大的。我刚开始接触这个领域时,也踩过不少坑。今天我把核心的三个模块——系统分区、SELinux 策略、用户权限模型——掰开揉碎了讲清楚。
1. 系统分区:谁动了我的系统?
先说说分区。Android Automotive 的分区设计和手机基本一致,但更严格。为什么呢?因为车机一旦出厂,系统分区就不能被随意修改。你想想看,要是有人能随便改 /system 下的文件,那车机安全就形同虚设了。
核心分区包括:
- /system:只读分区,存放 Android 框架和系统应用。我见过有些厂商为了调试方便,把这个分区改成可写,结果被攻击者利用——嗯,这是大忌。
- /vendor:硬件相关代码和驱动。同样只读,但允许 OEM 定制。
- /product:厂商专属应用和服务。也是只读。
- /data:用户数据分区,可读写。但加密是必须的。
- /odm:原始设备制造商(ODM)的专属分区,很少用到。
关键点:/system、/vendor、/product 这三个分区在出厂后必须保持只读。任何修改都需要通过 OTA 更新,且更新包必须经过签名验证。
我在项目中遇到过一件事:某款车机为了快速集成第三方应用,把 /system 分区挂载为可写。结果呢?一个恶意应用通过提权漏洞直接替换了系统服务。后来我们花了整整两周才定位到问题。说白了,分区权限是安全的第一道防线,千万别图省事。
2. SELinux 策略:强制访问控制的艺术
接下来是 SELinux。很多开发者觉得 SELinux 很烦,动不动就「avc: denied」。但说实话,没有 SELinux,Android 的安全模型就是纸糊的。
SELinux 在 Android Automotive 中扮演的角色很简单:即使进程有 root 权限,也不能为所欲为。它基于「最小权限原则」——每个进程只能访问它明确被允许的资源。
咱们看一个实际的策略文件片段:
# 车载蓝牙服务的 SELinux 策略
type hal_bluetooth_default, domain;
type hal_bluetooth_default_exec, exec_type, file_type;
# 允许蓝牙服务访问蓝牙硬件
allow hal_bluetooth_default hal_bluetooth_hwdevice:chr_file rw_file_perms;
# 禁止蓝牙服务访问网络
neverallow hal_bluetooth_default { tcp_socket udp_socket }:socket create;
# 允许蓝牙服务读取系统属性
allow hal_bluetooth_default system_prop:file read;
你看,这个策略明确规定了蓝牙服务能做什么、不能做什么。它不能创建网络 socket,这意味着即使蓝牙服务被攻破,攻击者也无法通过网络外传数据。这就是 SELinux 的精髓。
我的习惯:在开发新功能时,我会先写一个宽松的策略(permissive mode),跑一遍所有用例,收集所有 avc 日志。然后根据日志收紧权限。这样既不会漏掉必要权限,也不会过度授权。
我曾经犯过一个错误:给某个系统服务授予了过于宽泛的权限,结果导致一个第三方应用通过该服务的漏洞读取了车辆位置信息。从那以后,我对每个 allow 规则都反复推敲——「这个权限真的需要吗?」
SELinux 策略文件通常放在这些位置:
system/sepolicy/:AOSP 通用策略device/[OEM]/[产品]/sepolicy/:厂商自定义策略vendor/[OEM]/[产品]/sepolicy/:vendor 分区策略
注意:千万不要在 permissive 模式下发布产品。permissive 模式只记录日志,不强制执行。我见过有团队为了赶进度,带着 permissive 模式就出货了——结果安全审计直接不通过。
3. 用户权限模型:谁可以做什么?
最后聊聊用户权限模型。Android Automotive 的用户模型和手机不太一样。手机通常只有一个用户,但车机可能有多个用户:驾驶员、乘客、访客、甚至儿童模式。
Android Automotive 定义了三种用户类型:
| 用户类型 | 权限范围 | 典型场景 |
|---|---|---|
| 系统用户(System) | 完全控制,可管理所有用户 | 车主、管理员 |
| 普通用户(Regular) | 可安装应用、修改个人设置 | 家庭成员、常乘客 |
| 访客用户(Guest) | 受限,无法安装应用,数据临时 | 代驾、临时乘客 |
权限模型的核心是 PermissionController。它负责管理应用权限的授予和撤销。在车机上,有些权限是「危险权限」,需要用户明确同意。比如:
android.permission.ACCESS_FINE_LOCATION:精确位置android.permission.CAMERA:摄像头android.permission.RECORD_AUDIO:麦克风
但车机有个特殊之处:有些权限是默认授予的。比如导航应用的位置权限、音乐应用的音频权限。为什么?因为车机不像手机,用户不会频繁地「允许/拒绝」权限弹窗。你想想看,开车时弹个权限请求框,多危险。
最佳实践:对于核心车载功能(导航、电话、媒体),建议在系统预装时直接授予必要权限。对于第三方应用,则严格按照运行时权限模型处理。
我建议在开发车载应用时,遵循以下权限策略:
- 最小化权限声明:只声明你真正需要的权限。别为了省事声明一堆没用的。
- 分组请求:把相关权限放在一起请求。比如导航功能同时需要位置和网络权限。
- 提供解释:在请求权限前,先告诉用户为什么需要这个权限。比如「为了提供实时路况,需要访问您的位置信息」。
- 处理拒绝:如果用户拒绝了权限,应用要能降级运行,而不是直接崩溃。
我记得有一次,一个第三方导航应用在权限被拒绝后直接闪退。用户投诉说「一打开导航就退出」。后来我们强制要求所有预装应用必须处理权限拒绝场景。说白了,用户体验和安全要兼顾。
总结一下
系统分区、SELinux 策略、用户权限模型,这三者构成了 Android Automotive 安全架构的基石。分区保证了系统完整性,SELinux 限制了进程行为,权限模型控制了用户和应用的操作范围。三者缺一不可。
我个人习惯在项目初期就把这三块规划好。别等到开发后期再补安全策略——那时候改起来成本太高了。嗯,今天就聊到这儿,下一章咱们讲讲车载应用的签名和验证机制。