SELinux与Binder
SELinux Binder 检查不是一个统一的“允许 Binder”位。事务、Binder 引用转移、fd 转移和 context manager 分别进入不同 LSM hook 与 class/permission;下图给出四条路径。
本文面向已读过 Binder调用者身份、checkCallingPermission 和 Stable AIDL 的读者。Binder SELinux 控制不是 Java permission 的另一份缓存,而是在驱动事务、Binder 引用转移、fd 转移和 context manager 设置等内核路径调用 LSM hook。本文沿一次 transaction 的 credential→SID→AVC 判定追踪真实源码。
1. 策略宏
源码文件:system/sepolicy/public/te_macros
define(`binder_call', `
allow $1 $2:binder { call transfer };
allow $2 $1:binder transfer;
allow $1 $2:fd use;
')binder_call(client, server) 不只是允许 call:它还允许 Binder 引用双向 transfer,以及客户端使用服务传来的 fd。宏展开后的 source/target domain 是 SELinux 策略 owner;Binder 驱动只负责把当前 cred 和目标 cred 交给 hook。
2. 事务检查
源码文件:kernel/common/drivers/android/binder.c、kernel/common/security/selinux/hooks.c
驱动在解析目标 node、确认目标 proc 后调用 security_binder_transaction(proc->cred, target_proc->cred)。SELinux hook 先比较当前 task SID 与 from cred SID;不同则要求 BINDER__IMPERSONATE,随后以 fromsid→tosid 检查 BINDER__CALL。
return avc_has_perm(fromsid, tosid, SECCLASS_BINDER,
BINDER__CALL, NULL);因此 clearCallingIdentity 改变的是用户态线程状态,不会改变本次驱动 transaction 使用的 Linux cred/SID;SELinux 不会被 Java token 欺骗。
3. 引用转移
源码文件:kernel/common/drivers/android/binder.c
传递一个 Binder 对象时,驱动分别在 node→ref、ref→node、ref→ref 路径调用 security_binder_transfer_binder(from->cred, target->cred)。即使 source domain 有 call 权限,没有 transfer 权限也不能把 Binder 引用塞进目标 Parcel。
对应策略来自 binder_call 的 { call transfer } 和 reply 方向的 transfer;排查“方法能调用但回调 Binder 传不过去”时应看 transfer AVC,而不是 call AVC。
4. 文件转移
BINDER_TYPE_FD 走 security_binder_transfer_file。SELinux 同时检查目标 domain 对文件 SID 的 FD__USE,并处理 file receive 规则;因此传递 Ashmem/memfd、ParcelFileDescriptor 时,必须同时满足 Binder transfer 和目标对该 fd/file 的使用权限。
5. Context manager
源码文件:kernel/common/drivers/android/binder.c、kernel/common/security/selinux/hooks.c
设置 Binder context manager 前调用 security_binder_set_context_mgr(proc->cred),SELinux 以当前 SID→manager SID 检查 BINDER__SET_CONTEXT_MGR。这条权限独立于普通 binder_call,所以允许某 domain 调服务不代表它能成为 servicemanager。
6. Security context
若目标 Binder node 设置 FLAT_BINDER_FLAG_TXN_SECURITY_CTX,驱动在 transaction buffer 中追加发送方 security context:security_cred_getsecid 获取 secid,security_secid_to_secctx 转为字符串,并通过 BR_TRANSACTION_SEC_CTX 交给 Native。该 context 是诊断/服务读取的入站元数据,不能替代驱动在发送时已经完成的 AVC 判定。
7. 失败返回
任一 Binder LSM hook 返回非零,驱动把 transaction 设为 BR_FAILED_REPLY、参数 -EPERM,并记录失败事务。Native/Java 看到的可能是 PERMISSION_DENIED、FAILED_TRANSACTION 或远端异常;要定位 SELinux 拒绝,必须结合 kernel audit/AVC 日志中的 source、target、class 和 permission。
8. 调用与Java权限
checkCallingPermission 检查的是 framework permission controller;SELinux Binder hook 检查的是 domain 对 domain 的 binder class 权限。一个可以通过 Java permission 的调用仍可能被 SELinux 拒绝;反之 SELinux 允许 IPC 也不代表 Java permission 已授予。两层必须分别审计。
9. 实例策略
真实策略如 binder_call(hal_vehicle_default, stats_service_server)、binder_call(system_server, appdomain) 为具体 source/target domain 建立边。不能把 binder_service 当作万能授权;其注释已标为 deprecated,推荐授予精确权限集合。
10. 调试路径
先确定 transaction 的 source/target domain 和对象类型;普通调用查 call,传 Binder 查 transfer,传 fd 查 fd use/file receive,设置 context manager 查 set_context_mgr,需要读取发送 SID 才检查 node 的 txn security context。再对照 AVC 日志与策略宏展开,避免只修改 Java manifest 或 service permission。
11. 阅读检查
给定三种失败:调用服务被拒、回调 Binder 传参被拒、Ashmem fd 传递被拒,分别指出驱动调用的 LSM hook、SELinux class/permission 和应查看的策略宏。再解释为什么 clearCallingIdentity 不会绕过 Binder SELinux 检查。
