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:麦克风

但车机有个特殊之处:有些权限是默认授予的。比如导航应用的位置权限、音乐应用的音频权限。为什么?因为车机不像手机,用户不会频繁地「允许/拒绝」权限弹窗。你想想看,开车时弹个权限请求框,多危险。

最佳实践:对于核心车载功能(导航、电话、媒体),建议在系统预装时直接授予必要权限。对于第三方应用,则严格按照运行时权限模型处理。

我建议在开发车载应用时,遵循以下权限策略:

  1. 最小化权限声明:只声明你真正需要的权限。别为了省事声明一堆没用的。
  2. 分组请求:把相关权限放在一起请求。比如导航功能同时需要位置和网络权限。
  3. 提供解释:在请求权限前,先告诉用户为什么需要这个权限。比如「为了提供实时路况,需要访问您的位置信息」。
  4. 处理拒绝:如果用户拒绝了权限,应用要能降级运行,而不是直接崩溃。

我记得有一次,一个第三方导航应用在权限被拒绝后直接闪退。用户投诉说「一打开导航就退出」。后来我们强制要求所有预装应用必须处理权限拒绝场景。说白了,用户体验和安全要兼顾。

总结一下

系统分区、SELinux 策略、用户权限模型,这三者构成了 Android Automotive 安全架构的基石。分区保证了系统完整性,SELinux 限制了进程行为,权限模型控制了用户和应用的操作范围。三者缺一不可。

我个人习惯在项目初期就把这三块规划好。别等到开发后期再补安全策略——那时候改起来成本太高了。嗯,今天就聊到这儿,下一章咱们讲讲车载应用的签名和验证机制。