A kernel-root framework does not reach a mystical privilege level “above UID 0.” It installs code where Linux implements credential and security decisions. That placement explains its power—and why installation, authorization, maintenance, and defects in that code matter so much.
Before you start#
Read How a process becomes root, Inside systemless root, GKI and kernel builds, and Rooting methods. This is source analysis, not a kernel-patching or exploit lab. KernelSU v1.0.1, commit 59ba84eb2b45c7ee7cded8774c918100d62a2712, and APatch 11282, commit e8e4651c16fb5075882a25813c8732285fdb3505, are historical examples. Their current installation methods and supported kernels may differ.
Learning goals#
Trace a historical kernel-side request gate to credential mutation; separate a hook, allowlist, root profile, manager, and boot prerequisite; compare this with a userspace broker; and explain why successful boot or an allowlisted UID is not proof of a secure implementation.
A hook is an interception point, not authorization#
A hook arranges for additional code to run when another kernel operation occurs. Hooks can be integrated into source or attached through supported mechanisms; exact attachment depends on the project/version/configuration. Intercepting an exec operation means the framework can examine a task about to execute a program. It does not mean every such task should become root.
An allowlist is a policy decision about callers. A root profile specifies the credentials/security configuration selected for an authorized caller. A manager changes or displays policy through a project-specific channel. None of these nouns alone proves that callers cannot spoof identity, that concurrent policy changes are safe, or that policy persists correctly across app removal and UID reuse.
- Reach compatible exec hook
Validate the execution-path argument and compare the expected su path.
- Check current task UID
The allowlist uses kernel task identity, not a client-supplied package label.
- Authorized path and profile
Select the project destination/profile before the traced credential change.
- Change security state
This revision directly modifies credential fields and configures capabilities, groups, seccomp, and SELinux state.
The authority origin is the booted modified kernel. An APK cannot supply it by declaring an Android permission. The bootloader must accept the containing kernel/image, which is a separate question from whether the runtime allowlist permits a request. GKI/KMI compatibility constrains binaries and modules; it is not an automatic permission to load arbitrary code or proof that a root hook is compatible with a product's configuration.
A concrete KernelSU v1.0.1 trace#
Open pinned kernel/sucompat.c. In ksu_handle_execveat_sucompat:
- The function rejects a missing/error filename reference.
- It compares the proposed executable path with the project's
SU_PATH. - It calls
ksu_is_allow_uid(current_uid().val); the identity comes from the current kernel task, not a package-name argument from the app. - Only after that gate, it rewrites the execution destination toward
KSUD_PATHand callsescape_to_root().
The related ksu_handle_execve_sucompat handles another argument form. Reading both prevents a common audit error: proving one path has a check and assuming sibling entry points have the same behavior. The presence of these functions alone does not establish that the hooks are attached in a particular built kernel. Follow the registration/configuration path before making that stronger claim.
Now open kernel/core_hook.c, escape_to_root(). This revision obtains the current credential pointer with __task_cred(current), casts it, selects a root profile using the original UID, and writes UID/GID fields according to that profile. It configures capability sets, adjusts seccomp state under configuration guards, applies supplementary groups, and calls setup_selinux(profile->selinux_domain).
Do not replace that reading with a generic prepare_creds() → commit_creds() story. This particular historical implementation directly modifies credential fields. Linux's documented general credential model treats published credentials as immutable and describes preparing/replacing credentials; the difference is a real implementation-review question, not something to silently smooth over. Consult Linux 6.1 credentials. This lesson explains observed source; it does not recommend copying its mutation pattern into a driver.
The profile is also important: a function called escape_to_root does not prove every profile always sets every field to a universal maximum. Follow the selected profile and configuration. Capability and SELinux state are explicit pieces of the transition, not consequences one may infer solely from euid == 0.
Why seccomp and SELinux appear in the transition
Seccomp filters which system calls a task can make. It is distinct from file ownership, capabilities, and SELinux. An app-derived process can retain restrictions even if its UID changes. The pinned function's explicit seccomp handling shows why a real kernel-root implementation changes more than one number. This is an expansion of authority and TCB, not evidence that ordinary UID 0 automatically disables syscall filtering.
Similarly, SELinux domain setup matters because mandatory policy can still reject an operation allowed by DAC. A modified kernel/policy can change this result. The correct claim is “the active implementation configures these controls,” not either “root always bypasses SELinux” or “stock SELinux always constrains any root framework identically.”
Kernel mediation versus a userspace broker#
| Question | Magisk v28.1 example | KernelSU v1.0.1 example |
|---|---|---|
| Initial enforcement location | Privileged daemon validates a socket request | Kernel compatibility hook checks current task identity |
| Typical process transition in the traced path | Daemon forks a command child | Intercepted execution path changes the current task's security state before its next executable |
| Policy input | Peer UID, daemon configuration/database, optional manager query | Kernel allowlist/profile state and project-specific management |
| Important failure class | Broker request parsing, policy, process/namespace setup | Hook coverage, kernel memory/lifetime, profile and credential handling |
| Shared prerequisite | Booted trusted-to-enforce root component and a supported image | Booted trusted-to-enforce root component and a supported image |
“In kernel” does not establish faster request handling without measurement, stronger consent without policy analysis, or smaller attack surface without inventory. A kernel defect may affect the whole OS, while a compromised root broker is also extremely powerful. Compare concrete boundaries rather than marketing labels.
What APatch changes in the comparison#
Pinned APatch's README.md describes a KernelPatch-based kernel modification approach, APM modules, KPM facilities, and a SuperKey. This places patching and project-specific authorization in the trust model; it does not prove that APatch uses the KernelSU functions just examined.
A key is a credential accepted by particular code. The phrase “higher privileges than root” in the README is not a Linux UID or a mathematical ordering over all security boundaries. The relevant questions are who checks it, which operations acceptance enables, where it is stored, and what a compromise permits. Protect it as a secret; do not publish or embed one in a lab artifact.
The README alone cannot establish the complete patch format, runtime hook sequence, or cryptographic quality of that authorization channel. A deeper APatch implementation audit would need version-matched KernelPatch source, its integration, kernel configuration, and tests. Keeping that boundary explicit is better than inventing a common “kernel-root algorithm” for two separate projects.
Practice#
Build an eight-row source ledger: path validation, task identity, allowlist decision, destination change, profile selection, UID/GID changes, capability changes, and seccomp/SELinux handling. For each row record the exact pinned function, the branch that prevents it, and what runtime evidence would be necessary to show your kernel actually executes it.
Worked negative case: an ordinary task reaches the compatibility function with a matching SU_PATH, but its UID is not allowed. The function returns before rewriting the path and before calling escape_to_root. A manager screenshot saying “installed” does not alter that branch. Conversely, a missing hook means the function is not reached at all; no prompt can repair that absent authority origin.
Then review two proposals: “authorize by a caller-provided package string” and “grant the request before checking policy so the manager opens faster.” Reject both: the former replaces kernel-established identity with untrusted input; the latter crosses the boundary before authorization. No kernel, image, policy, or device changes are needed for this exercise.
Knowledge check#
- Does a function present in source prove its hook is live?
- Does this pinned KernelSU function use the generic prepare/commit credential sequence?
- Why inspect seccomp after inspecting UID?
- Can APatch's README establish KernelSU's exact call chain?
Answers#
- No. Build configuration, attachment, and the running artifact must be established.
- No. It directly modifies fields obtained from the current credentials; that distinction requires review, not substitution with a nicer generic model.
- Syscall filtering is separate state; UID changes alone do not explain the effective restrictions.
- No. They are different projects and mechanisms; each implementation needs its own evidence.
Checkpoint#
Ready when the ledger identifies the denial-before-mutation gate and accurately describes this revision rather than a generic kernel-root diagram. Revise if kernel location is used as a safety ranking, or source presence is treated as running-kernel evidence. Revisit the allowlist branch and Linux credential lifecycle, then annotate the exact differences. Current device compatibility and live authorization remain not yet evidenced.
Sources#
- KernelSU v1.0.1
sucompat.c,core_hook.c, andallowlist.c— historical implementation, not current installation instructions. - Linux 6.1 credentials and seccomp filtering — distinct credential-lifecycle and syscall-filtering mechanisms.
- APatch 11282
README.md— project-specific claims and terminology; not a complete KernelPatch source audit. - Magisk v28.1
su_daemon.cpp— comparison broker path.