鸿蒙系统权限内核级高级校验机制:UID/GID权限模型/SELinux策略/能力CAP机制/权限校验调用链源码级解析
·



一、前置思考
1.1 权限是系统安全的"守门员"
一个恶意应用能读到另一个应用的数据吗?能偷偷拍照吗?能修改系统设置吗?——全看权限校验机制:
权限校验的本质: 每次敏感操作前,问一句"你有资格吗?"
谁(主体: 应用进程)→ 做什么(操作: 读文件/拍照)
→ 对什么(客体: 目标资源)→ 依据什么(权限模型)
1.2 权限校验失效的灾难
❌ UID 可伪造 → 恶意应用冒充系统进程 → 任意读写
❌ SELinux 策略漏洞 → 应用越权访问系统数据
❌ CAP 滥用 → 普通应用获得管理员能力
❌ 校验链断裂 → 有一个环节没查 → 全盘失守
1.3 鸿蒙/OpenHarmony 权限体系
三层权限模型:
① UID/GID 权限模型: 进程身份(你是谁)
② SELinux MAC 强制访问控制: 安全策略(你能做什么)
③ CAP 能力机制: 特权能力(你有哪把钥匙)
校验调用链:
应用请求 → 权限管理服务 → UID 校验 → SELinux 策略 → CAP 检查 → 放行/拒绝
二、核心原理
2.1 UID/GID 权限模型
UID (User ID): 进程身份标识
普通应用: 10000 + 应用索引(如 10023)
系统进程: 0~999(root=0, system=1000)
GID (Group ID): 进程所属组
补充组: 提供共享权限(如 inet 组可联网)
隔离机制:
每个应用进程用独立 UID 运行
→ 文件系统按 UID 判权限
→ 进程间不能随意互相访问(沙箱基础)
2.2 SELinux 强制访问控制(MAC)
SELinux: 内核级安全策略(比 DAC 更强)
DAC (自主访问): 文件属主自己决定谁能访问
→ 缺点是: root 用户无所不能(拦不住恶意 root)
MAC (强制访问): 系统策略统一决定
→ 即使 root 也要过策略
→ 恶意进程无法绕过
SELinux 判定:
主体(进程) × 客体(文件/资源) × 操作(读/写/执行)
→ 查安全策略表 → allow/deny
2.3 CAP 能力机制
传统 Linux: 只有"root/非 root"二元
→ root 能做一切(太危险)
CAP 机制: 将 root 权限拆成 40+ 种能力
CAP_NET_ADMIN: 网络管理
CAP_SYS_TIME: 修改系统时间
CAP_KILL: 杀死任意进程
CAP_SYS_BOOT: 重启系统
...
原则: 最小特权 — 进程只需要哪几个能力就给哪几个
普通应用: 无能力
系统服务: 按需授予特定 CAP
三、源码/API 深度解析
3.1 权限校验调用链(应用层 → 内核)
import { abilityAccessCtrl } from '@kit.AbilityKit';
import { common } from '@kit.AbilityKit';
// 应用层权限申请 → 系统校验链
async function requestAndVerify(): Promise<void> {
const context = getContext(this) as common.UIAbilityContext;
const atManager = abilityAccessCtrl.createAtManager();
// 1. 申请权限(弹出系统授权框)
const result = await atManager.requestPermissionsFromUser(
context, ['ohos.permission.CAMERA']
);
// result: { authResults: [0=授予, -1=拒绝] }
// 2. 校验权限(每次使用前检查)
const grantStatus = await atManager.checkAccessToken(
atManager.getTokenID(), 'ohos.permission.CAMERA'
);
// grantStatus === 0 (PERMISSION_GRANTED)
if (grantStatus !== 0) {
// 无权限 → 降级处理
showPermissionDenied();
return;
}
// 3. 执行敏感操作
startCamera();
}
3.2 内核权限校验(UID/GID)
// 文件访问权限校验(内核)
// 每次 open/read/write 都会调用
static int inode_permission(struct inode *inode, int mask)
{
// 1. 获取当前进程凭据(UID/GID)
const struct cred *cred = current_cred();
kuid_t uid = cred->fsuid; // 进程 UID
kgid_t gid = cred->fsgid; // 进程 GID
// 2. 权限位检查 (rwx)
// 属主权限: inode->i_mode & S_IRUSR...
// 属组权限: inode->i_mode & S_IRGRP...
// 其他权限: inode->i_mode & S_IROTH...
if (uid_eq(inode->i_uid, uid)) {
// 属主 → 查属主权限位
mode = inode->i_mode & 0700;
} else if (in_group_p(gid)) {
// 属组 → 查属组权限位
mode = inode->i_mode & 0070;
} else {
// 其他人 → 查其他权限位
mode = inode->i_mode & 0007;
}
// 3. 权限不足 → EACCES
if (!(mode & mask)) { return -EACCES; }
return 0;
}
3.3 SELinux 策略(安全策略)
# SELinux 策略文件示例 (te: Type Enforcement)
# 定义类型
type sensor_app, domain;
type sensor_data, file_type;
# 允许 sensor_app 读取 sensor_data
allow sensor_app sensor_data:file { read getattr open };
# 允许访问 Binder
allow sensor_app binder_device:binder { transfer };
# 禁止项 (默认 deny): 未声明的访问全部拒绝
# 这就是 MAC 与 DAC 的区别:
# DAC: 没拒绝 = 允许
# MAC: 没允许 = 拒绝
// SELinux 内核校验核心
static int selinux_file_permission(struct file *file, int mask)
{
// 1. 获取主体安全上下文 (进程的 SID)
u32 sid = current_sid();
// 2. 获取客体安全上下文 (文件的 SID)
u32 tsid = file->f_path.dentry->d_inode->i_sid;
// 3. 查策略数据库 (AVC 缓存)
u32 av = avc_has_perm(sid, tsid,
SECCLASS_FILE, // 客体类: 文件
file_mask_to_av(mask), // 操作: 读/写
NULL);
// 4. 未允许 → 拒绝 (EACCES)
if (av) { return -EACCES; }
return 0;
}
3.4 CAP 能力校验
// 能力检查(内核核心函数)
// 每次特权操作调用
int capable(int cap)
{
// 1. 获取当前进程的有效能力集
const struct cred *cred = current_cred();
kernel_cap_t cap_effective = cred->cap_effective;
// 2. 检查是否拥有该能力
if (!cap_raised(cap_effective, cap)) {
return 0; // 无能力 → 拒绝
}
return 1; // 有能力 → 允许
}
// 实例: 修改系统时间需要 CAP_SYS_TIME
if (!capable(CAP_SYS_TIME)) {
return -EPERM; // Operation not permitted
}
四、企业级实战落地
4.1 权限安全清单
| 层 | 检查点 | 说明 |
|---|---|---|
| 应用 | 权限最小化 | 用到的才申请 |
| 应用 | 使用前校验 | checkAccessToken |
| 系统 | UID 隔离 | 独立 UID 沙箱 |
| 系统 | SELinux 策略 | 未声明即拒绝 |
| 系统 | CAP 最小化 | 按需授予能力 |
4.2 完整示例:权限校验链演示
@Entry
@ComponentV2
struct KernelPermissionDemo {
@Local logs: string[] = [];
@Local state: string = '未校验';
private runPermissionChain(): void {
this.logs = [];
this.state = '校验中';
this.log('🔐 权限校验调用链');
this.log('请求: 应用访问相机');
this.log('① UID 校验: 进程 UID=10023 (应用沙箱)');
this.log(' → 身份有效 ✅');
this.log('② SELinux 策略: 查 AVC 缓存');
this.log(' → allow app camera_app:camera { open }');
this.log(' → 策略允许 ✅');
this.log('③ CAP 检查: 应用无需特权能力');
this.log(' → 普通能力集即可 ✅');
this.log('④ 授权框: 用户确认 → Token 记录');
this.log(' → 校验通过,相机打开 ✅');
this.state = '校验通过 (相机已授权)';
}
private runDeniedChain(): void {
this.logs = [];
this.state = '拒绝演示';
this.log('🔒 权限不足场景');
this.log('恶意应用尝试读取其他应用数据:');
this.log('① UID 校验: UID=10099 ≠ 目标 UID=10023');
this.log(' → 文件属主不匹配 ❌');
this.log('② SELinux 策略: 未声明该访问');
this.log(' → MAC: 未允许 = 拒绝 ❌');
this.log('③ 结论: 双重拒绝,无法越权');
this.log('→ 返回 EACCES / EPERM');
}
build() {
Column({ space: 12 }) {
Text('🔐 内核权限校验机制').fontSize(20).fontWeight(FontWeight.Bold)
Text('状态: ' + this.state).fontSize(13).fontColor('#4FC3F7')
Row({ space: 8 }) {
Button('放行链路').layoutWeight(1).height(40).fontSize(12)
.onClick(() => this.runPermissionChain())
Button('拒绝链路').layoutWeight(1).height(40).fontSize(12)
.onClick(() => this.runDeniedChain())
}
.width('100%')
Scroll() {
Column() {
ForEach(this.logs, (l: string) => {
Text(l).fontSize(11).lineHeight(18).fontColor('rgba(255,255,255,0.8)').width('100%')
}, (l: string, i: number) => l + i)
}.width('100%')
}
.layoutWeight(1).width('100%').scrollBar(BarState.Off)
}
.width('100%').height('100%').padding(16)
.backgroundColor('#0D1B2A')
}
}
4.3 权限模型对比
| 模型 | 控制方式 | 强度 | 特点 |
|---|---|---|---|
| UID/GID | 身份判定 | 中 | 基础隔离 |
| SELinux MAC | 策略判定 | 高 | 未允许即拒绝 |
| CAP | 能力判定 | 高 | 最小特权 |
| 组合使用 | 多层校验 | 极高 | 层层设防 |
五、问题排查与性能优化
| 问题 | 原因 | 解决 |
|---|---|---|
| 应用无法访问 | SELinux 策略缺失 | 补充 allow 策略 |
| 越权成功 | CAP 授予过多 | 能力最小化 |
| 校验变慢 | 策略表大 | AVC 缓存命中 |
| 权限被恶意利用 | 校验链缺失 | 全链路校验 |
| root 逃逸 | 单层 DAC | SELinux 兜底 |
| 服务权限过大 | 共用 root | 拆分 UID + CAP |
5.1 权限安全优化
1. 最小特权: 应用只申请用到的权限,服务只给需要的 CAP
2. SELinux 补全: 新功能上线前审查策略(未声明即拒绝)
3. 校验前置: 敏感操作前主动 checkAccessToken(别依赖系统拦截)
4. 分层设防: UID 隔离 + MAC 策略 + CAP 能力,缺一不可
5. 审计留痕: 权限授予/拒绝都记录(安全审计)
六、高阶总结与最佳实践
- 身份先行:UID/GID 是权限的基础,独立 UID = 沙箱隔离的基石。
- MAC 兜底:SELinux"未允许即拒绝",即使 root 也无法绕过——这是最后防线。
- 能力最小化:CAP 拆分了 root 权限,按需授予是安全最佳实践。
- 全链路校验:应用层申请 + 系统层策略 + 内核层校验,每层都要查。
- 审计闭环:权限行为留痕,违规可追溯。
一句话记住:权限校验三层防线——UID 管身份(你是谁)、SELinux 管行为(你能做什么,未允许即拒绝)、CAP 管特权(你有哪把钥匙)——应用按需申请、系统策略兜底、内核层层校验。
更多推荐




所有评论(0)