节点如何被android系统授权?

1 阅读4分钟

一、 经典谜题:权限是从哪里掉下来的? 假设我们有一个系统级 App,它的 AndroidManifest.xml 中配置了系统级的共享用户身份:

XML 并且在编译时,使用了 platform 证书进行了签名。此时通过一系列底层的映射,奇迹发生了:应用可以如丝般顺滑地直接读写 /dev/ttyUSB0 和 /dev/ttyS1。

这背后的完整证据链条是怎样的?

二、 破案证据链:四重安全防线是如何闭环的? Android 处理一个进程是否有权访问某个底层硬件节点,需要经过以下四个步骤:

  1. 进程身份:为什么是 system_app? 很多开发者以为,用了 platform 证书签名,App 运行时的 SELinux 域就一定是 platform_app。其实不然!

条件 1:APK 签名 = platform 证书(常叫平台应用)。

条件 2:声明了 android:sharedUserId="android.uid.system"。

结果:由于这两个条件同时成立,Android 运行时会直接分配 Linux UID 1000 (system) 给该应用进程。而在 SEAndroid 的安全映射规则中,UID 1000 对应的应用进程域是 system_app(普通的系统签名应用如果不加这个 system UID,才属于 platform_app)。

  1. 硬件被打上了什么“标签”? 在芯片厂(以 MTK 为例)的供应商私有安全上下文配置文件 file_contexts 中,早已静态地为常见的串口物理节点打好了身份标签:

代码段 /dev/ttyS.* u:object_r:ttyS_device:s0 /dev/ttyUSB0 u:object_r:tty_device:s0 当设备插入或初始化时,/dev/ttyUSB0 被赋予了 tty_device 标签。

/dev/ttyS1 被赋予了 ttyS_device 标签。

3. SELinux:谁在暗中放行? 既然进程是 system_app,硬件标签是 tty_device 和 ttyS_device,那么接下来就要看安全策略文件(.te)了。

打开 MTK 默认的原生策略文件 system_app.te,你会赫然发现厂商早就为你写好了通行证:

代码段 allow system_app ttyS_device:chr_file { getattr open read write ioctl }; allow system_app tty_device:chr_file { getattr open read write ioctl }; 第一条规则:允许 system_app(你的应用)对 ttyS_device(即 /dev/ttyS1)做获取属性、打开、读取、写入、控制(ioctl)的整套操作。

第二条规则:同理,直接放行了对 tty_device(即 /dev/ttyUSB0)的访问权限。

这就是为什么你一行 Policy 没写,串口却直接能用的底层真相!

三、 刨根问底:什么是 ueventd 权限? 在理清了上面的 SELinux 链条后,很多工程师会问:既然有了 SELinux 规则,那为什么我们经常还在 ueventd.rc 里看到类似下面的配置?这有什么用?

代码段 /dev/ttyUSB* 0666 system system

  1. 传统 Linux 权限与 SELinux 的双重门 在 Android 中,访问一个硬件节点就像进入一个高安全性机密房间,必须通过两道安检门:

第一道门:传统 Linux 权限(由 ueventd 负责管理)

第二道门:SELinux 强制访问控制(由 .te 规则负责管理)

只有两道门都对你放行,你才能真正读写这个设备。任何一道门卡住,都会报 Permission denied。

  1. ueventd 的核心职责 ueventd 是 Android 的一个核心守护进程。当内核检测到有新的硬件(如插上 USB 串口线)加入系统时,内核会发出一个硬件事件,ueventd 收到后就会在 /dev/ 目录下创建对应的设备节点。

在创建节点时,ueventd 会去读取各种 ueventd.rc 配置文件,来决定这个硬件节点的传统 Linux 权限、所属用户(Owner)和所属用户组(Group)。

如果没有配置 ueventd.rc:系统默认会给节点极度严格的权限(例如 0600,且属于 root 用户)。这意味着除了 root 进程,连 UID 1000 (system) 的应用走过去,在第一道门就会被传统 Linux 权限直接拦死!

配置了 /dev/ttyUSB* 0666 system system:意思就是告诉 ueventd,凡是生成这类串口节点,传统 Linux 权限直接拉满到 0666(所有人可读写),且所有者归 system 账户。

总结大白话: ueventd 权限 决定了传统 Linux 层面谁是这个文件的老爸,普通人能不能读写它(第一道物理门)。

SELinux 权限 是在此之上,由内核进行的高级政治审查(第二道策略门)。

在你的项目中,因为 ueventd 已经放开了传统门槛,而 MTK 的 system_app.te 又在第二道门对你的系统 UID 应用大开绿灯,双剑合璧,这才成就了免配置直接读写串口的巧合!

本文完。