KernelSU 高级特性与安全
本章探讨 KernelSU 的高级特性、安全设计与潜在风险,对应当前重构后的代码。基础实现请先参阅 内核层实现。
1. App Profile 高级特性
App Profile 允许为每个应用定制独特的 root 环境,是 KernelSU 最强大的特性。结构定义见 用户空间实现 §2.3(uapi/app_profile.h,v4),提权应用见 内核层实现 §3.3(escape_with_root_profile)。
1.1 可定制项
| 维度 | 字段 | 说明 |
|---|---|---|
| 身份 | uid / gid |
提权后的目标 UID/GID(可不为 0,如以 shell=2000 运行受限 root) |
| 附加组 | groups[≤32] |
硬件/资源访问(graphics=1003、audio=1005、inet=3003 等) |
| 能力 | capabilities.effective |
精确裁剪 capabilities,默认 CAP_FULL_SET |
| SELinux | selinux_domain |
目标 domain,默认 u:r:ksu:s0(不再是 u:r:su:s0) |
| 命名空间 | namespaces |
INHERITED(0) / GLOBAL(1) / INDIVIDUAL(2)(见 Android 安全机制与绕过 §6.2) |
| 标志 | flags |
目前仅 FLAG_KSU_NO_NEW_PRIVS |
最小权限示例(只给网络相关能力 + inet 组):
allow_su = true
uid = 0, gid = 0
groups = [0, 3003] // root + inet
capabilities.effective = CAP_NET_ADMIN | CAP_NET_RAW
selinux_domain = "u:r:ksu:s0"
namespaces = GLOBAL // 能看到模块挂载
1.2 NO_NEW_PRIVS 标志
FLAG_KSU_NO_NEW_PRIVS(flags 首位):提权完成后,escape_with_root_profile 会 set_thread_flag(TIF_KSU_DISABLE_ESCAPE_WITH_ROOT)(线程标志 bit 63),禁止该线程再次提权。这是给"拿一次 root 后就应降权固化"的场景用的防护。userspace 也可通过 IOCTL DISABLE_ESCAPE_TO_ROOT(ksud su --ksu-no-new-privs)主动设置。
1.3 模板系统
rp_config 含 template_name:多个应用可引用同一模板统一配置。注意:模板本身(以及 App Profile 的 sepolicy 文本 rules)存储在 ksud 一侧(/data/adb/ksu/profile/templates/、/profile/selinux/),由 ksud profile list-templates/get-template/set-template 管理;而 profile 结构体(uid/caps/domain 等)经 JNI IOCTL 写入内核。这就是 用户空间实现 §5.4 提到的"双通路"。
1.4 Non-Root Profile 与全局默认
不授 root 的应用用 nrp_config,目前只有 umount_modules(是否对其卸载模块)。默认 umount_modules=true(默认对非 root 应用隐藏模块)。
特殊条目 uid=9999 / key="$" 承载"全局默认非 root profile":写它即修改 default_non_root_profile.umount_modules(Manager 的"默认卸载模块"开关)。该条目在 prune 时被保留。
2. Feature 系统(运行时可开关)
policy/feature.c 提供 feature 框架,userspace 经 IOCTL GET/SET_FEATURE 运行时开关五个特性。其中 su_compat 见 libsu 与 su 兼容层,此处详解其余四个。
2.1 kernel_umount(feature/kernel_umount.c,默认开)
内核态在每次 zygote→app/isolated 进程的 setresuid 后,于该进程的 mount namespace 中卸载模块挂载,实现"未授权应用看不到模块"。完整逻辑(前置 zygote 校验、mount_list、override_creds(ksu_cred))见 Android 安全机制与绕过 §6.3。待卸载路径由 IOCTL ADD_TRY_UMOUNT 维护(通常由 metamodule 在挂载后登记)。
2.2 selinux_hide(feature/selinux_hide.c,默认关)
针对"检测 SELinux 是否被 KernelSU 篡改"的应用,对应用进程(uid≥10000)伪造 SELinux 视图。开启时做三件事(基于 backup_sepolicy——注入 ksu 规则之前的策略副本):
- hook selinuxfs 的
write_op表:把write_op[SEL_CONTEXT]/[SEL_ACCESS]换成自定义实现,对 app 用backup_sepolicy而非当前内核策略来做 context↔sid 转换和 av 决策——使/sys/fs/selinux/context、/sys/fs/selinux/access的校验结果与"未打补丁"一致; - hook LSM
selinux_setprocattr(KernelSU 唯一用到的 LSM hook):app 写/proc/self/attr/current时用 backup_sepolicy 校验; - hook
sel_handle_status_ops.open:对 app 返回伪造的 SELinux status 页(fake_status,late-load 且 permissive 时把 enforcing 显示为 1),骗过 mmap/sys/fs/selinux/status的检测。
6.6+ 内核里 KernelSU 自带了一份 SELinux 内部函数(
string_to_context_struct、security_compute_av_user_with_policy等)的复制实现,因为这些未导出,需要自己基于 backup_sepolicy 计算。boot_completed 后若未启用则drop_backup_if_unused释放副本省内存。
2.3 adb_root(feature/adb_root.c,默认关)
让 adb shell 默认获得 root。当检测到 init 派生进程 execve 目标以 /adbd 结尾时(ksu_adb_root_handle_execve):
- 校验
/data/adb/ksu/lib/libadbroot.so存在; setup_ld_preload:在用户栈上构造并把LD_PRELOAD=/data/adb/ksu/lib/libadbroot.so、LD_LIBRARY_PATH=/data/adb/ksu/lib追加进 adbd 的 envp;escape_to_root_for_adb_root()给 adbd 提权。
libadbroot.so 由 Manager 的 adbroot.cc 编译,经 ksud install --libadbroot <path> 安装。
2.4 sulog(feature/sulog.c + sulog/,默认关)
su 操作审计日志。捕获三类事件(uapi/sulog.h):
| 事件 | 触发 |
|---|---|
ROOT_EXECVE (1) |
root 进程 execve(记录 filename + argv) |
SUCOMPAT (2) |
su 兼容路径触发(escape 前捕获,escape 后 emit) |
IOCTL_GRANT_ROOT (3) |
经 IOCTL 授权 root |
机制:内核把事件扁平化成定长 payload 推入 infra/event_queue(环形队列,上限 256 条、单条 2048 字节,满则记丢弃计数);userspace 经 IOCTL GET_SULOG_FD(only_root)拿到匿名只读 fd [ksu_sulog](单消费者)poll/read 消费。ksud 的 sulogd 守护进程读取并写入 /data/adb/ksu/log/sulog-*.log(日切+轮转)。开启 sulog feature 时 ksud 会自动拉起 sulogd。
3. 模块系统进阶
早期实现是 ksud 直接用 OverlayFS 挂载模块;当前已改为 metamodule + meta-overlayfs 解耦架构。基础见 用户空间实现 §4。
3.1 metamodule 与 meta-overlayfs
- ksud 自身不做 OverlayFS 挂载,而是委托给唯一活动的 metamodule(
module.prop含metamodule=1,并在/data/adb/metamodule建 symlink); - metamodule 提供
metamount.sh(挂载/overlayfs 入口)、metainstall.sh(普通模块安装 hook)、metauninstall.sh及各 stage 脚本; - 每个 init 阶段,metamodule 脚本优先于普通模块执行;
- 这把"如何叠加模块到系统分区"变成可插拔策略(
userspace/meta-overlayfs),让模块系统不绑死某种挂载方式。
3.2 模块状态与 preinit rc
模块状态用空文件标记(disable/remove/update/skip_mount);安装走 modules_update/ 暂存 → post-fs-data 搬到 modules/。各启用模块的 initrc/*.rc 由 ksud 拼接成 /metadata[/watchdog]/ksu/modules.rc,内核 init.rc 注入 hook 在下次开机把它拼进 init.rc(见 §4.1、内核层实现 runtime)。
3.3 模块配置与 feature 托管
ksud 的模块配置系统(/data/adb/ksu/module_configs/<id>/,persist + temp 两层)支持:
override.description:覆盖模块描述;manage.<feature>=true:声明该模块"托管"某内核 feature——之后只有该模块(KSU_MODULE环境变量匹配)能改这个 feature,ksud feature set直接命令会被拒绝。用于让模块独占管理某项内核行为。
4. 启动形态:GKI 与 LKM
KernelSU 有两种安装形态,对应 内核层实现 §1.2 的两条初始化路径。
4.1 GKI 模式(boot 内置)
ksud boot-patch 用内嵌的 android-bootimg 修补 boot 镜像:
- 解包 boot,取 ramdisk cpio;
- 用
ksuinit替换 ramdisk 的/init(原 init 改名init.real),并把对应 KMI 的<kmi>_kernelsu.ko加为/kernelsu.ko; - 维护 cpio 内
ksu_config(norc/allow_shell等); - 重打包,
--flash写回块设备(do_backup按 sha1 备份原 boot),--ota切 slot。
开机时 ksuinit(#![no_main])先挂 /proc、/sys,加载 /kernelsu.ko(此时模块以 pid==1 加载 → ksu_late_loaded=false,走正常路径并注入 init.rc),再 execve 真正的 init。boot-restore 从备份还原。
4.2 LKM 运行时加载(late-load)
ksud late-load 在系统已启动后加载内核模块:用 ksuinit::load_module(解析 ELF 未定义符号,逐行读 /proc/kallsyms 手动重定位后 init_module)加载 <kmi>_kernelsu.ko。此时 current->pid != 1 → ksu_late_loaded=true,走 late-load 路径(立即 apply rules / cache sid / escape / 强制 enforce,不注入 init.rc),随后跑全套 stage 并重启 Manager。
4.3 magica(adb root 越狱注入)
ksud late-load --magica <port>:在受限 root(magica 提供)下临时开启 adb tcp root(设 ro.debuggable=1 等 prop + 重启 adbd),用 adb_client 自连,再通过 adb shell 在完整 root + ksu 域下执行 late-load --post-magica 加载 ko,完成后还原 adb 相关 prop。用于不补 boot 的情况下注入 KernelSU。
5. 安全特性
5.1 Manager 认证(纯 V2 签名)
只接受纯 V2 签名的 Manager APK:V2 块必须恰好 1 个,存在 V1(JAR) 共存或任何 V3/V3.1 即拒绝。期望证书 SHA-256 与长度由构建脚本注入到 kernel/Makefile。详见 内核层实现 §5.2。Manager 身份以 appid(uid%100000)记录,支持更新/重装/多用户场景,并由 fsnotify 监听包变化自动重扫。
5.2 安全模式
按住音量下键开机触发:内核 kprobe input_event 统计 KEY_VOLUMEDOWN 按下次数,≥3 次即进入安全模式(IOCTL CHECK_SAFEMODE 查询)。ksud 在 post-fs-data 检测到安全模式时 disable_all_modules()(禁用所有模块),用于从模块导致的 bootloop 中恢复。
5.3 权限检查层级
supercall 的 4+1 类权限检查(always_allow/only_root/only_manager/manager_or_root/allowed_for_su)见 内核层实现 §4.3。关键约束:
- App Profile 读写仅 Manager(
only_manager); - sepolicy 注入、sulog fd、事件上报仅 root;
- GRANT_ROOT 需
allowed_for_su(Manager 或已授权 uid)。
5.4 防提权约束
- uid==0 域校验:
__ksu_is_allow_uid_for_current在 uid==0 时返回is_ksu_domain()——只有处于 ksu domain 的 root 才算"被允许",防止任意 root 进程冒用接口; - 系统 uid 保护:
forbid_system_uid(uid<2000 且 ≠1000 直接拒); - NO_NEW_PRIVS:见 §1.2,提权后可禁止再次提权;
- zygote 前置校验:模块卸载前必须确认旧进程是 zygote(见 Android 安全机制与绕过 §6.3),防止误卸载破坏系统。
6. 反检测能力
| 手段 | 实现 |
|---|---|
| selinux_hide | 对 app 伪造 SELinux 状态页/上下文校验(§2.2) |
| 模块卸载 | 未授权应用看不到模块修改(kernel_umount) |
| ext4 sysfs 清理 | IOCTL NUKE_EXT4_SYSFS → ext4_unregister_sysfs,移除模块 ext4 镜像痕迹 |
| 匿名通信 | [ksu_driver] 匿名 inode + IOCTL,无 /dev 节点 |
| 模块自隐藏 | 非 debug LKM 在 init 末尾 kobject_del 从 /sys/module 摘除 |
| file_wrapper | [ksu_fdwrapper] 包装 fd,inode sid 设为 ksu_file_sid 绕 SELinux(su tty 用) |
| 避开 hypervisor | 内存改写用 fixmap+stop_machine 而非改 PTE,避开 MTK MKP 等保护 |
7. 潜在风险与缓解
| 风险 | 缓解 |
|---|---|
| 内核稳定性(panic/兼容) | 构建期 check_symbol 校验 .ko 依赖符号都在 vmlinux;fixmap 避开 hypervisor;大量 LINUX_VERSION_CODE 版本分支;RCU + kref 保护数据结构 |
| 权限滥用 | Manager 纯 V2 认证;per-app profile 限权;NO_NEW_PRIVS;可选 sulog 审计 |
| 检测对抗 | selinux_hide、模块卸载、匿名通信、自隐藏;与检测方持续博弈 |
| 版本兼容 | kallsyms + CFI 符号解析动态适配;GKI/LKM 双形态;KMI 检测 |
8. 最佳实践
应用开发者:遵循最小权限(只申请必要 capabilities/groups);明确告知用户用途;用完及时降权或 NO_NEW_PRIVS。
Manager 使用者:默认拒绝、按需授权;为不信任的敏感应用保持"卸载模块";用 sulog 审计授权;遇 bootloop 用安全模式恢复。
模块开发者:遵循 metamodule 约定;用 initrc/*.rc 做 preinit 注入;需要独占内核 feature 时用 manage.<feature> 托管;WebUI 用 kernelsu js 库(见 libsu 与 su 兼容层)。
9. 总结
| 特性 | 实现要点 |
|---|---|
| App Profile | v4 结构,可定制 uid/gid/groups/caps/domain/namespace/flags + 模板 |
| Feature 系统 | su_compat / kernel_umount / selinux_hide / adb_root / sulog 运行时开关 |
| 模块系统 | metamodule + meta-overlayfs 解耦,空文件标记状态,preinit rc |
| 启动形态 | GKI(boot-patch + ksuinit)与 LKM(late-load / magica) |
| 安全 | 纯 V2 认证、音量键安全模式、uid==0 域校验、NO_NEW_PRIVS、zygote 校验 |
| 反检测 | selinux_hide、模块卸载、ext4 sysfs 清理、匿名通信、自隐藏 |
附录:文档导航
评论
- 还没有评论,来说点什么吧。