KernelSU 内核级 Root 方案:架构、白名单授权与可插拔模块系统全解析

KernelSU 内核级 Root 方案:架构、白名单授权与可插拔模块系统全解析 KernelSU 内核级 Root 方案架构、白名单授权与可插拔模块系统全解析【免费下载链接】KernelSUA Kernel based root solution for Android项目地址: https://gitcode.com/GitHub_Trending/ke/KernelSU导读本文以 KernelSU 官方文档首页所阐述的四大核心特性——基于内核的权限授予、白名单访问控制、受限制的 root 权限Root Profile以及 Metamodule 模块系统——为主线结合本仓库内核态与用户态源码系统讲解 KernelSU 的设计思路与实现原理。读完本文你将理解 KernelSU 与 Magisk 等传统 root 方案的本质差异掌握白名单与 App Profile 的配置语义并了解模块系统如何以可插拔方式实现无系统修改。一、KernelSU 是什么Android 上的内核级 Root 方案KernelSU 是面向 Android GKIGeneric Kernel Image通用内核镜像设备的 root 解决方案。与在用户空间以守护进程方式注入 root 的传统方案不同KernelSU 直接以内核模式运行在内核空间中为用户空间应用程序授予 root 权限这意味着它可以提供传统方案无法触及的内核级能力详见 website/docs/zh_CN/guide/what-is-kernelsu.md。从官方文档的定位描述来看KernelSU 的四大设计支柱分别是基于内核Kernel-based运行在内核空间对用户空间应用拥有更强的掌控力白名单访问控制Allowlist只有被授权的 App 才能访问su其他 App 无法感知其存在受限制的 root 权限Root Profile可自定义su的 uid、gid、groups、capabilities 与 SELinux 规则把 root 权限关进笼子里Metamodule 模块系统可插拔的模块基础架构支持无系统修改systemless通过安装 meta-overlayfs 等 metamodule 来启用模块挂载。这四项能力分别对应仓库中kernel/内核态实现、uapi/内核与用户态共享的接口定义、userspace/ksud/用户态守护进程等核心目录下文逐一展开。二、基于内核从内核空间掌控一切2.1 内核态 hook 体系基于内核是 KernelSU 最根本的设计选择。因为权限授予与隐藏逻辑都运行在内核空间KernelSU 可以做到为任何进程添加硬件断点、访问任意进程的物理内存而不被发现在内核空间拦截任意系统调用在进程真正获得权限之前就以内核强制的方式完成身份与能力设置。仓库中 kernel/hook/ 目录集中体现了这套内核态能力lsm_hook.c通过 LSMLinux Security Module钩子介入安全决策setuid_hook.c负责 hooksetuid相关的系统调用路径syscall_hook.c与syscall_hook_manager.c提供了跨架构arm64 / x86_64见 kernel/hook/arm64/syscall_hook.c 与 kernel/hook/x86_64/syscall_hook.c的系统调用拦截框架。此外 kernel/feature/ 下的sucompat.csu 兼容层、kernel_umount.c内核态卸载、selinux_hide.cSELinux 隐藏等模块都是在内核空间直接完成的功能。2.2 内核与用户态之间的 UAPI 通道内核能力需要暴露给用户态守护进程ksud使用这一层由 uapi/ksu.h 统一组织。它聚合了五个子头文件uapi/supercall.h定义了KSU_IOCTL_*系列 ioctl 命令包括GRANT_ROOT、GET_INFO、SET_APP_PROFILE、GET_APP_PROFILE、UID_GRANTED_ROOT、UID_SHOULD_UMOUNT、GET_SULOG_FD、DISABLE_ESCAPE_TO_ROOT等uapi/app_profile.hstruct app_profile/struct root_profile等授权配置结构uapi/feature.henum ksu_feature_id功能开关枚举uapi/selinux.h 与 uapi/sulog.hSELinux 策略下发与 su 日志接口。其中 uapi/supercall.h 中KERNEL_SU_UAPI_VERSION 3记录了当前 UAPI 版本KSU_IOCTL_GRANT_ROOT等命令号则是 ksud 与内核握手的关键可对照 userspace/ksud/src/ksucalls.rs 的调用实现。例如ksud在su时会先通过grant_root()内核调用见 userspace/ksud/src/su.rs由内核完成凭据切换后再exec出目标 shell。三、白名单访问控制只有授权的 App 才能访问 su3.1 白名单Allowlist而非黑名单KernelSU 采用白名单模型只有被用户显式授权的 App 才能访问su未授权的 App 在内核层面直接被拒绝甚至无法感知 KernelSU 的存在。这与传统 root 管理器询问所有请求 root 的应用的模式有本质区别也从机制上减少了 root 被滥用的攻击面。白名单的内核实现位于 kernel/policy/allowlist.c内核维护一个基于哈希表DEFINE_HASHTABLE(allow_list, ALLOW_LIST_BITS)的授权表每个条目是一个struct perm_data内部封装struct app_profile见 uapi/app_profile.h__ksu_is_allow_uid()是核心判定函数先快速拒绝系统 UIDforbid_system_uid再检查是否为管理器 UID管理器永远放行最后遍历白名单哈希表确认allow_su标志授权数据持久化存储在/data/adb/ksu/.allowlist文件KERNEL_SU_ALLOWLIST宏带文件魔数0x7f4b5355与格式版本号通过ksu_load_allow_list()/ksu_persistent_allow_list()实现开机加载与异步落盘。3.2 授权条目与 UID 语义每个授权条目以包名key 当前 UIDcurr_uid为标识见 uapi/app_profile.h。理解 Android 的 UID 体系是配置白名单的前提0是 root1000是 system2000是 ADB shell普通应用通常落在10000-19999Android 多用户/工作资料是对 UID 分片实现的如110000-119999属于工作资料这与 Linux 传统的 UID 概念并不冲突。内核会在设备启动完成后通过ksu_prune_allowlist()清理已卸载应用的条目保留KSU_APP_PROFILE_PRESERVE_UID等特殊 UID保持白名单与已安装应用的一致性。四、受限制的 root 权限把 root 关进笼子里这是 KernelSU 最具特色的能力即使某个 App 被授予了 rootsu之后的进程凭据也完全可以按需裁剪而不是无条件的完整 root。官方文档将这种能力称为 Root Profile其配置载体就是 uapi/app_profile.h 中的struct root_profilestruct root_profile { __s32 uid; __s32 gid; __u32 groups_count; __s32 groups[KSU_MAX_GROUPS]; // KSU_MAX_GROUPS 32 struct { __u64 effective; __u64 permitted; __u64 inheritable; } capabilities; char selinux_domain[KSU_SELINUX_DOMAIN]; // KSU_SELINUX_DOMAIN 64 __s32 namespaces; __u64 flags; // 如 FLAG_KSU_NO_NEW_PRIVS };4.1 UID、GID 与 groupsLinux 中 UID 为 0 即 root 用户GID 为 0 即 root 组。Android 每个 App 独占一个 UID不考虑 shared uid并隶属于若干组GID 是主组通常等于 UID其余为补充组groups网络、蓝牙等权限正是通过组来控制的。官方文档给出的示例在 shell 中执行id展示了典型输出oriole:/ $ id uid2000(shell) gid2000(shell) groups2000(shell),1004(input),1007(log),1011(adb), 1015(sdcard_rw),1028(sdcard_r),3003(inet),... contextu:r:shell:s0Root Profile 可以自定义执行su后进程的 UID、GID 和 groups。例如把某应用的 su 进程 UID 设为2000则它实际只拥有 ADB shell 级别权限若再从 groups 中去掉inet该组代表可创建 AF_INET/AF_INET6 socket则这个 su 进程将无法联网。注意App Profile 控制的是su 之后的进程权限而不是 App 本身的权限。App 自身申请了网络权限即使 su 进程没有inet组App 本体依然可以联网。另一个关键点是这种限制是内核强制实施的见 kernel/policy/allowlist.c 中ksu_get_root_profile()对每个 UID 返回对应 profile 的逻辑不依赖 root 应用的自觉su的授予权完全掌握在用户手里。4.2 Capabilities 分权Capabilities 是 Linux 2.2 引入的分权机制把传统上属于超级用户的特权拆分成可独立启停的单元。例如CAP_DAC_READ_SEARCH控制是否绕过文件读取权限检查——一个有效 UID 为 0 的进程如果缺失该能力即便身为 root 也无法随意读取文件。Root Profile 可以裁剪su后进程的effective/permitted/inheritable三组 capability 位图实现部分 root。当某些 root 应用必须要求 UID 为 0 时通过裁剪 capabilities 仍能限制其可执行操作。如果打算深入自定义 capabilities建议先通读 Linux 官方 capabilities(7) 手册每个能力的确切语义都在其中。4.3 SELinux 域切换SELinux 是强制访问控制MAC机制遵循默认拒绝原则。现代 Android 极度依赖 SELinux 保障系统安全因此官方文档明确警告不要使用以宽容permissive模式运行的自定义系统。默认情况下应用执行su后会切换到不受限制的 SELinux 域例如u:r:ksu:s0。Root Profile 可以把它切换到自定义域并为该域定制规则type app1 enforce app1 typeattribute app1 mlstrustedsubject allow app1 * * *注意上例中的allow app1 * * *仅为演示格式实际使用中不应照搬它与 permissive 差别不大。在内核侧默认域u:r:ksu:s0由 kernel/policy/allowlist.c 的KSU_DEFAULT_SELINUX_DOMAIN宏定义即KERNEL_SU_DOMAIN并在 kernel/selinux/rules.c 中为其声明domain类型、mlstrustedsubject等属性以及宽松的 allow 规则作为 su 进程的默认归宿。4.4 逃逸风险与 NO_NEW_PRIVS配置不当会导致权限逃逸限制意外失效。官方文档给出经典场景你为 ADB shell 用户UID 2000授予了 root 权限很常见某普通应用被授予 root但其 Root Profile 把 UID 设成了 2000该应用第一次su正常切换到 UID 2000受 App Profile 限制第二次su时因 UID 已是 2000、而 2000 本身被允许 root从而获得完整 root 权限。防御手段是在 App Profile 中启用FLAG_KSU_NO_NEW_PRIVS定义于 uapi/app_profile.h即NO_NEW_PRIVS标志阻止该进程再次通过su逃逸提权。需要明确的是该标志只阻止 KernelSU 为进程提权进程仍可能利用其他 Linux 机制逃逸因此权限配置本身必须谨慎。内核侧也提供了KSU_IOCTL_DISABLE_ESCAPE_TO_ROOT见 uapi/supercall.h作为面向此类场景的加固通道。4.5 Non Root Profile对未授权应用的隐藏对于未授予 root的普通应用App Profile 依然有意义——它控制内核与模块系统对该应用的行为核心配置项是卸载模块umount modulesKernelSU 通过 overlayfs 实现无系统修改但部分 App 对这种挂载痕迹敏感管理器设置中默认卸载模块开关默认开启即未单独配置的应用默认会被执行卸载操作可以按需选择策略保持默认开启再针对个别不需要卸载的 App 单独关闭白名单式关闭默认开关再针对需要卸载的 App 单独开启黑名单式。内核中该逻辑由ksu_uid_should_umount()见 kernel/policy/allowlist.c实现未命中 profile 时回落到default_non_root_profile其umount_modules默认为true命中后根据是否use_default决定采用默认配置还是该 App 的个性化配置。平台差异在 5.10 及以上内核卸载操作由内核执行在 5.10 以下设备上该开关仅是配置项内核本身不动作由 Zygisksu 等模块依据它决定是否卸载。另外ksu_set_app_profile()同文件在写入时会校验groups_count上限、selinux_domain长度与 profile 版本KSU_APP_PROFILE_VER当前为 4并在CONFIG_KSU_DISABLE_POLICY编译选项下强制回落到默认配置确保策略开关可被整体关闭。五、Metamodule 模块系统可插拔的挂载基础设施5.1 什么是 MetamoduleMetamodule元模块是 KernelSU 的一项革新性架构把模块系统能力从核心中剥离出来委托给可插拔的模块实现。KernelSU 核心本身不执行挂载从而减少检测面挂载策略交给 metamodule 演进社区可以自由实现替代方案。关键特征详见 website/docs/zh_CN/guide/metamodule.md基础设施角色为常规模块提供依赖的服务单实例同一时刻只允许一个 metamodule 处于运行状态优先执行metamodule 脚本先于常规模块脚本运行三个特殊钩子metamount.sh挂载、metainstall.sh安装钩子、metauninstall.sh清理钩子。重要未安装 metamodule 时依赖挂载的模块其挂载功能不会生效。全新安装 KernelSU 后需要安装meta-overlayfs等 metamodule 才能让模块正常工作。仅使用脚本、sepolicy 或 system.prop 的模块则无需 metamodule。5.2 挂载策略的多样性由于挂载被委托用户可以选择完全不同的挂载实现无挂载仅使用无挂载模块时完全避免挂载开销OverlayFS 挂载传统方式支持读写层官方meta-overlayfsMagic MountMagisk 兼容挂载获得更好的应用兼容性自定义实现基于 FUSE 的 overlayfs、自定义 VFS 挂载或全新方法。5.3 用户视角安装、检查与卸载安装 metamodule与安装常规模块一致下载meta-overlayfs.zip→ 打开 KernelSU Manager → 点击浮动操作按钮➕→ 选择 ZIP → 重启设备。检查在 Manager 模块页面可看到当前活动 metamodule它在模块列表中带特殊标识。卸载注意卸载 metamodule 会影响所有模块——移除后模块将不再被挂载直到安装另一个 metamodule。操作路径为模块列表中找到 metamodule → 卸载会看到特殊警告→ 确认 → 重启。切换 metamodule需要卸载所有常规模块 → 卸载当前 metamodule → 重启 → 安装新 metamodule → 重新安装常规模块 → 再次重启。同一时刻只能有一个 metamodule尝试安装第二个会被阻止该约束在 userspace/ksud/src/module.rs 的安装流程中有明确校验与提示如 A metamodule is already installed。5.4 模块开发者视角常规模块开发者几乎无需感知 metamodule 的存在模块中的system目录只有在用户安装了提供挂载功能的 metamodule 时才会被挂载现有模块无需修改代码即可工作熟悉 Magisk 模块开发的用户在安装 metamodule 后模块将以相同方式工作因为提供了 Magisk 兼容挂载。5.5 Metamodule 开发者视角钩子脚本与文件结构元模块通过module.prop中的metamodule1或metamoduletrue属性被识别idmeta-example nameMy Custom Metamodule version1.0 versionCode1 authorYour Name descriptionCustom module mounting implementation metamodule1文件结构meta-example/ ├── module.prop (必须包含 metamodule1) │ *** 元模块特定钩子 *** ├── metamount.sh (可选: 自定义挂载处理程序) ├── metainstall.sh (可选: 常规模块的安装钩子) ├── metauninstall.sh (可选: 常规模块的清理钩子) │ *** 标准模块文件(全部可选) *** ├── customize.sh (安装自定义) ├── post-fs-data.sh (post-fs-data 阶段脚本) ├── service.sh (late_start service 脚本) ├── boot-completed.sh (启动完成脚本) ├── uninstall.sh (元模块自己的卸载脚本) └── [任何其他文件]三个钩子脚本的作用分别是1.metamount.sh挂载处理程序——控制启动期间模块的挂载方式环境变量包括MODDIR如/data/adb/modules/meta-example及所有标准 KernelSU 环境变量职责是遍历并挂载所有已启用的模块、检查skip_mount标志、处理特定模块的挂载需求。官方文档特别强调一个关键要求执行挂载操作时必须将源/设备名称设置为KSU这会把挂载标识为属于 KernelSU内核卸载与 Zygisksu 卸载依赖该标识才能正确卸载。# 正确示例overlay 挂载 mount -t overlay -o lowerdir/lower,upperdir/upper,workdir/work KSU /target// 现代 mount API 设置源字符串meta-overlayfs/src/mount.rs 的做法 fsconfig_set_string(fs, source, KSU)?;2.metainstall.sh安装钩子——自定义常规模块的安装方式在文件提取后、安装完成前被内置安装程序 source而非执行。它继承内置install.sh的全部变量与函数MODPATH、TMPDIR、ZIPFILE、ARCH、API、IS64BIT、KSU、KSU_VER、KSU_VER_CODE、KSU_UAPI_VER、KSU_RUNTIME_MODE、KSU_LATE_LOAD、BOOTMODE等以及ui_print、abort、set_perm、set_perm_recursive、install_module等函数。注意安装 metamodule 自身时不会调用此脚本。3.metauninstall.sh清理钩子——卸载常规模块时清理资源在删除模块目录之前执行环境变量为MODULE_ID典型用途包括清理符号链接、释放资源、更新内部跟踪。5.6 启动执行顺序理解启动时序对 metamodule 开发至关重要post-fs-data 阶段: 1. 执行通用 post-fs-data.d 脚本 2. restorecon加载 sepolicy.rule 3. 执行元模块的 post-fs-data.sh(如果存在) 4. 执行常规模块的 post-fs-data.sh 5. 加载 system.prop 6. 执行元模块的 metamount.sh └─ 以无系统方式挂载所有模块 7. post-mount.d 阶段运行 - 通用 post-mount.d 脚本 - 元模块的 post-mount.sh(如果存在) - 常规模块的 post-mount.sh service 阶段: 1. 执行通用 service.d 脚本 2. 执行元模块的 service.sh(如果存在) 3. 执行常规模块的 service.sh boot-completed 阶段: 1. 执行通用 boot-completed.d 脚本 2. 执行元模块的 boot-completed.sh(如果存在) 3. 执行常规模块的 boot-completed.sh要点metamount.sh在所有 post-fs-data 脚本元模块与常规模块之后运行元模块的生命周期脚本始终先于常规模块脚本.d目录中的通用脚本先于元模块脚本post-mount阶段在挂载完成后运行。5.7 符号链接机制与官方参考实现安装 metamodule 时KernelSU 会创建符号链接/data/adb/metamodule - /data/adb/modules/metamodule_id这为访问活动 metamodule 提供了稳定路径相关逻辑可在 userspace/ksud/src/module.rs 中看到ensure_symlink/remove_symlink等实现。官方参考实现meta-overlayfs采用双目录架构元数据目录/data/adb/modules/存放module.prop、disable、skip_mount等标记启动时快速扫描、占用小内容目录/data/adb/metamodule/mnt/存放实际模块文件system、vendor、product 等位于 ext4 镜像modules.img中。其metamount.sh的核心流程是挂载 ext4 镜像 → 导出MODULE_METADATA_DIR/MODULE_CONTENT_DIR环境变量 → 调用 Rust 挂载二进制真实挂载逻辑在 Rust 中通过fsconfig_set_string(fs, source, KSU)设置源标识。特性包括基于内核 overlayfs 的真正的 systemless 修改、支持 system/vendor/product/system_ext/odm/oem 多分区、通过/data/adb/modules/.rw/支持读写层。5.8 开发最佳实践与测试清单开发 metamodule 时应遵循始终将挂载源设置为KSU——内核卸载与 Zygisksu 卸载依赖此标识优雅处理错误——启动过程对时间敏感尊重标准标志——支持skip_mount与disable记录操作——用 echo 或日志便于调试彻底测试——挂载错误可能导致开机循环记录行为——清晰说明 metamodule 的用途提供迁移路径——帮助用户从其他方案切换。发布前建议在干净的 KernelSU 环境上依次验证安装、各类模块挂载、与常见模块的兼容性、卸载与清理、启动性能metamount.sh是阻塞的、错误处理避免 bootloop。5.9 常见问题速答我需要 metamodule 吗只有想使用需要挂载的模块时才需要仅运行脚本、不修改系统文件的模块不需要。可以同时装多个 metamodule 吗不可以一次只能一个以防冲突并保证行为可预期。卸载唯一的 metamodule 会怎样模块不再被挂载设备正常启动但模块修改不生效直到安装新的 metamodule。meta-overlayfs 是必需的吗不是。它只是提供与大多数模块兼容的标准 overlayfs 挂载需要不同行为时可自行实现 metamodule。六、总结四大特性如何协同回看官方首页的定位KernelSU 的四个特性构成一条完整链路内核态底座kernel/提供强掌控力与隐藏能力并通过 uapi/ 与ksuduserspace/ksud/src/通信白名单kernel/policy/allowlist.c决定谁能用 suApp Profileuapi/app_profile.h决定用了 su 之后拥有多少权限以内核强制的方式落实最小权限原则Metamodule 系统userspace/ksud/src/module.rs把挂载这一高风险、易被检测的环节做成可插拔扩展让核心保持精简稳定。对普通用户而言理解白名单与默认卸载模块开关即可安全使用对希望深度定制的用户App Profile 提供了从 UID/GID/groups 到 capabilities、再到 SELinux 域的完整裁剪能力对高级开发者Metamodule 钩子体系则打开了一扇自定义挂载与模块管理行为的大门。【免费下载链接】KernelSUA Kernel based root solution for Android项目地址: https://gitcode.com/GitHub_Trending/ke/KernelSU创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考