Open-source project
xiaoleGun/KernelSU_Action avatar
xiaoleGun/KernelSU_Action

KernelSU_Action and building a rooted Android kernel in CI

A action for build KernelSU into your kernel

727 stars2,935 forksShellLicense varies

At a glance

What is it?
KernelSU_Action is a GitHub Actions workflow that integrates KernelSU and its forks, SUSFS and a set of common patches into an Android kernel source tree, then packages a flashable AnyKernel3 zip. It is aimed at kernel authors and hobbyists who already know how to build a kernel, and it saves the most tedious part rather than the hardest part.
Who is it for?
KernelSU_Action is the right tool for a kernel maintainer who already has a working source tree, a defconfig and a device image name, and who wants a repeatable CI build that produces a flashable AnyKernel3 package with KernelSU, SUSFS and chosen patches applied. It is the wrong tool for a user who only wants root on a stock device, and for anyone who cannot supply a matching boot image or a working clang combination.
Can I use it commercially?
Not without permission. GitHub finds no licence file in the repository, and without a licence all rights are reserved by default: you may read the code but not reuse it. Check the README, or ask the authors, before using it.
Is it still maintained?
Yes. The repository last received commits 88 days ago.
What is it written in?
Mainly Shell, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The workflow builds a flashable kernel, not a root solution for a stock device

KernelSU_Action is a GitHub Actions workflow for integrating KernelSU, and its various forks, along with SUSFS and a set of common patches, into an Android kernel, and for producing a flashable AnyKernel3 package. The README is direct about the audience: it requires a certain amount of kernel and Android knowledge.

That framing matters, because the project is often mistaken for a one click root solution. It is not. The output is a kernel image built from a source tree you supply, and flashing it replaces your device's kernel. A user who just wants root on an unmodified phone is the wrong reader here; the intended reader is someone with a kernel source tree, a defconfig and a build pipeline that already works locally.

What the workflow actually removes from that job is the repetitive part: checking out the right KernelSU branch, applying patches in the right order, resolving a clang toolchain, and packaging the result into a zip you can flash from recovery. The README also asks that builds produced from another author's work be kept for personal use rather than redistributed.

The repository is small and shell based. Its top level holds `.github/`, two READMEs, a `boot/` directory, `config.env`, a `config/` directory, `patches/` and `scripts/`.

Supported kernels run from 4.9 to 6.12, and only as built-in

The support table splits by kernel generation. Versions `4.9`, `4.14`, `4.19` and `5.4` are listed as Non-GKI with full support. Versions `5.10`, `5.15`, `6.1`, `6.6` and `6.12` are GKI source trees, built with `make`.

The GKI rows matter because GKI normally offers two deployment routes: a loadable kernel module, `kernelsu.ko`, built against a DDK, and a built-in kernel where the source is patched and recompiled. The README states plainly that this repository builds the built-in variant, and that if you only want the `kernelsu.ko` module you should use the upstream DDK approach instead.

So for a GKI device, choosing this workflow means committing to rebuilding the kernel rather than shipping a module. That is a heavier operation, it needs a matching boot image, and it is a different maintenance commitment.

The consequence for a Non-GKI device is the opposite and worse: the source tree is entirely yours, so every kernel version quirk has to be handled by the patch set or by the KernelSU branch you select.

Five steps, and the config.env file is the contract

The quick start is five steps. Fork the repository. Edit `config.env` and fill in at least `KERNEL_SOURCE`, `KERNEL_SOURCE_BRANCH`, `KERNEL_CONFIG` and `KERNEL_IMAGE_NAME`. Open the `Actions` tab, choose `Build Kernel` and use `Run workflow`. In the form that appears, pick the KernelSU branch and whether to enable SUSFS. When the build finishes, download the AnyKernel3 archive from the Artifacts and flash it in recovery.

The dispatch form deserves a note, because it is unusual. Every dropdown in the form defaults to `config`, which means use the value written in the configuration file. The dropdown only overrides `config.env` when you actively pick something else. The stated consequence is that daily tuning needs no committed change, and that pressing Run always builds with your configured settings rather than silently disabling a feature you turned on in the file.

If you want a separate configuration per device, the README's instruction is to copy `config.env` to `config/<device name>.env` and enter that path in the `Config file to build` field.

The relevant keys are worth knowing by name: `KERNEL_IMAGE_NAME` must match `BOARD_KERNEL_IMAGE_NAME` in the device tree, commonly `Image.gz-dtb`, `Image.gz` or `Image`. `EXTRA_CMDS` and `CUSTOM_CMDS` append arguments to every `make` invocation, and their values may contain `=`. `USE_LLVM` selects a full LLVM build with `LLVM=1 LLVM_IAS=1`, which the README recommends for 5.10 and later. `ADD_OVERLAYFS_CONFIG` enables overlayfs support for the KernelSU module and for system read-write access. `DISABLE_LTO` turns off link time optimisation, which the README says can otherwise cause compile errors, and `DISABLE_CC_WERROR` fixes kernels that treat KernelSU warnings as errors. `EXTRA_DEFCONFIG` appends arbitrary defconfig lines such as `CONFIG_TMPFS_XATTR=y`.

KSU_REF is validated before setup.sh, because a wrong ref fails silently upstream

The KernelSU implementation is selected with `KSU_VARIANT`, and the supported values map to distinct upstream projects. `none` integrates no root solution and just compiles the kernel. `kernelsu` is the official original, which from v1.0 no longer supports Non-GKI, and old kernels are automatically pinned to `v0.9.5`. `kernelsu-next` is KernelSU-Next, whose branches are `dev` (default), `stable` and `legacy`, with `legacy` recommended for old kernels. `sukisu-ultra` is SukiSU-Ultra, where `main` is a v4 modular tree supporting KPM and `builtin` is the built-in tree, and it is the only branch that ships SUSFS itself. `resukisu` is a further branch of SukiSU-Ultra focused on old kernel and Non-GKI compatibility and multi-manager support. `rsuntk` is RKSU, and `backslashxx` is a KernelSU variant built around manual hooks.

`KSU_REF` takes a branch name, a tag or a commit, and leaving it empty makes the action pick a suitable reference for your kernel version.

The reason the action validates that reference is the most useful piece of engineering in the repository, and it is worth understanding. Every branch's `setup.sh` ends with `git checkout "$1" || echo "[-] Checkout default branch"`. In other words, asking for a branch that does not exist is not an error. The checkout fails, the message is printed, and the build continues on the default branch. The README gives a concrete instance: passing `susfs-main` to SukiSU-Ultra, a branch that does not exist, produces a build that reports success while the resulting kernel has no SUSFS at all. This action checks that the ref exists before invoking `setup.sh`, failing the job and listing the available branches when it does not.

SUSFS branches are picked from the kernel version, and the Non-GKI patch is stale

SUSFS is enabled with `ENABLE_SUSFS=true`, and the patches come from the susfs4ksu project. The branch is selected automatically from the kernel version: `kernel-<version>` for 4.9, 4.14, 4.19 and 5.4, `gki-android12-5.10` for 5.10, `gki-android13-5.15` for 5.15, `gki-android14-6.1` for 6.1, `gki-android15-6.6` for 6.6, and `gki-android16-6.12` for 6.12. When the automatic mapping is wrong, for example a 5.10 tree that is really based on android13, `SUSFS_BRANCH` sets it by hand.

The flow is: copy `fs/susfs.c` and `include/linux/susfs*.h`, apply the kernel side patch `50_add_susfs_in_*.patch`, then apply the KernelSU side patch `10_enable_susfs_for_ksu.patch`. The last step is skipped automatically when the selected branch already bundles SUSFS, which is the case for SukiSU-Ultra's `builtin` tree.

The README flags a known trap. The Non-GKI branches of susfs4ksu have not been updated since early 2025 and still target the old flat directory layout of KernelSU, while most branches have since been restructured into a modular `kernel/` directory. The combination of an old kernel, a new branch and SUSFS may therefore fail to apply the KernelSU side patch. The suggested workaround is to switch to `KSU_VARIANT=sukisu-ultra` with `KSU_REF=builtin`, which carries SUSFS itself and does not need that patch. The build log prints this advice when the step fails.

Hook mode, path_umount and trace hiding are the options that decide whether it works

Beyond SUSFS, the patch set covers three behaviours that are easy to get wrong by hand.

`KSU_HOOK_MODE` selects how KernelSU hooks the kernel: `auto`, which uses kprobes on 5.10 and later and manual hooking on older kernels, or explicitly `kprobes`, `manual`, `tracepoint`, `syscall` or `none`. The README notes that on old kernels kprobes are often the reason KernelSU installs but `su` does nothing, and in that case `manual` is the setting to use.

`ENABLE_PATH_UMOUNT=true` handles `path_umount()`, a function introduced in Linux 5.9 that KernelSU relies on to unmount its own mounts before an app detects root. On older kernels the function has to be backported, otherwise the unmount silently fails. The code is taken from upstream and inserted after `do_umount()` in `fs/namespace.c`, and the step is skipped on 5.9 and later or when the function is already present.

`ENABLE_HIDE_STUFF` additionally clears KernelSU traces from the kernel. `ENABLE_KPM` enables Kernel Patch Module support for SukiSU-Ultra, which runs `patch_linux` against the built Image and is restricted to `sukisu-ultra` with `arm64`.

Two options exist for advanced use. `BUILD_BOOT_IMG` with `SOURCE_BOOT_IMAGE` repacks a boot image and needs a direct link to a bootable image from the same device and ROM. `KSU_EXPECTED_SIZE` and `KSU_EXPECTED_HASH` set a custom manager signature, obtained with `ksud debug get-sign <apk>`.

The clang table exists because the wrong version fails late, not early

The toolchain section documents a specific trap in the AOSP prebuilt clang repository. Every `kernel-build` branch lists all version directories, but only one or two of them actually contain a toolchain, the rest being empty placeholders. A tarball built from an empty directory still downloads with an HTTP 200 and unpacks to nothing. The consequence is that a wrong version does not fail with a 404; it fails tens of minutes later with `clang: not found`.

The verified combinations, listed as of 2026-07, are `main-kernel` with `r596125`, `main-kernel-2026` with `r584948c`, `main-kernel-2025` with `r547379`, `main-kernel-build-2024` with `r510928` and `master-kernel-build-2022` with `r450784e`. Newer clang releases often fail to compile 4.x trees, so the README suggests `r450784e` for `4.9` to `4.19` and `r547379` or newer for `5.10` and up. The build script checks that the unpacked result really contains `bin/clang` and warns for combinations that are not in the table.

Third party clang is also possible, with `USE_CUSTOM_CLANG=true` and `CUSTOM_CLANG_SOURCE`, which accepts a git repository or a direct zip or tar link.

The repository is organised as a small set of shell scripts, and the layout is visible in the tree itself:

bash
.github/workflows/
scripts/
patches/

Under `scripts/`, `lib.sh` holds logging, retries, Kconfig reading and writing, patching and reference validation, `config.sh` handles configuration parsing, input overrides and validation, `toolchain.sh` covers clang, gcc and mkbootimg, `source.sh` fetches the kernel source, `kernelsu.sh` holds the KernelSU branch registry and installation, `patches.sh` applies SUSFS, path_umount, hide_stuff, hooks and KPM, `build.sh` injects defconfig options and compiles, and `package.sh` produces the AnyKernel3 package and the boot image. Under `patches/` there is `legacy_ksu_hooks.sh`, the sed based hook script used as a fallback in manual mode. The CI workflow `ci.yml` runs shellcheck, actionlint, configuration validation and upstream link checks, and `build-kernel.yml` can also be reused through `workflow_call` so each device can have a very short workflow of its own.

Old configuration keys are translated, and the release history is thin

Existing `config.env` files do not need to be edited. The README lists the automatic conversions, each of which also produces a notice. `ENABLE_KERNELSU=true` becomes `KSU_VARIANT=kernelsu`, `KERNELSU_TAG` becomes `KSU_REF`, `APPLY_KSU_PATCH=true` becomes `KSU_HOOK_MODE=manual`, and `DISABLE-LTO` becomes `DISABLE_LTO`.

The troubleshooting table is a good summary of the failure modes. An empty toolchain directory or `clang: not found` means the `CLANG_BRANCH` and `CLANG_VERSION` pair is invalid. A `ref '...' does not exist` message means `KSU_REF` named a branch that does not exist, and the log lists the available branches. A SUSFS kernel patch that will not apply means `SUSFS_BRANCH` does not match the kernel version or the tree has already been modified. KernelSU that installs but where `su` does nothing means the kprobes path is unreliable and `KSU_HOOK_MODE=manual` is the fix. Module mounts that will not unmount means the kernel is below 5.9 and needs `ENABLE_PATH_UMOUNT=true`. A missing defconfig means `KERNEL_CONFIG` is wrong, and the log lists the available defconfigs.

On project state, the repository is not archived and the last push was on 2026-07-27, but there are no GitHub releases, so there is no version stream to pin and no changelog to diff. The licence is not classified by GitHub, which is worth resolving with the maintainer before you base a build pipeline on it.

Editorial conclusion

KernelSU_Action is the right tool for a kernel maintainer who already has a working source tree, a defconfig and a device image name, and who wants a repeatable CI build that produces a flashable AnyKernel3 package with KernelSU, SUSFS and chosen patches applied. It is the wrong tool for a user who only wants root on a stock device, and for anyone who cannot supply a matching boot image or a working clang combination. Verify first that your `CLANG_BRANCH` and `CLANG_VERSION` pair appears in the verified table, that `KERNEL_SOURCE`, `KERNEL_SOURCE_BRANCH`, `KERNEL_CONFIG` and `KERNEL_IMAGE_NAME` in `config.env` match your device, and that the `KSU_REF` you pass is a branch that actually exists, since a wrong ref produces a successful build without the feature you asked for.

Frequently asked questions

What does KernelSU_Action produce?

It integrates KernelSU and its forks, SUSFS and common patches into an Android kernel source tree and packages the result as a flashable AnyKernel3 zip, which the workflow uploads as an Artifact to flash in recovery. It builds the built-in variant, not the `kernelsu.ko` LKM module.

How do I configure a KernelSU_Action build?

Fork the repository and edit `config.env`, filling in at least `KERNEL_SOURCE`, `KERNEL_SOURCE_BRANCH`, `KERNEL_CONFIG` and `KERNEL_IMAGE_NAME`. Then run the `Build Kernel` workflow, where every dropdown defaults to `config`, meaning the value from the configuration file is used unless you pick something else.

Which KernelSU variants can KernelSU_Action build?

The `KSU_VARIANT` option supports `none`, `kernelsu`, `kernelsu-next`, `sukisu-ultra`, `resukisu`, `rsuntk` and `backslashxx`. Each maps to a different upstream project, and `sukisu-ultra` is the only branch that ships SUSFS itself, on its `builtin` tree.

Why does KernelSU_Action validate KSU_REF before building?

Every branch's `setup.sh` ends with a checkout that falls back to the default branch on failure, so an invalid branch name does not fail the build. The action checks that the ref exists first and fails the job with the list of available branches, which prevents a successful build that silently lacks the feature you asked for.

What should I do if the SUSFS patch fails to apply?

The README documents the cause as a `SUSFS_BRANCH` that does not match the kernel version, or a tree that has been modified. For old kernels the suggested path is `KSU_VARIANT=sukisu-ultra` with `KSU_REF=builtin`, since that tree bundles SUSFS and needs no KernelSU side patch.

Official sources

  1. Issues
  2. README
  3. xiaoleGun/KernelSU_Action on GitHub
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/xiaolegun-kernelsu-action.svg)](https://hysenlabs.com/projects/xiaolegun-kernelsu-action)

Was this useful?