Skip to content

ksud: support inject the KernelSU LKM into x86-64 kernel images - #3745

Open
u9521 wants to merge 2 commits into
tiann:mainfrom
u9521:lkm-x64
Open

u9521 wants to merge 2 commits into
tiann:mainfrom
u9521:lkm-x64

Conversation

@u9521

@u9521 u9521 commented Sep 22, 2026

Copy link
Copy Markdown
Contributor
  • The LKM-in-kernel-image flow (ksud boot-patch-v2) now works on x86-64 bzImage next to arm64: it decodes the compressed payload, recovers kallsyms and BTF from the decompressed image, links the bootstrap into unused .text padding, patches the kernel image reservation, kernel_init() and load_module() call sites, and appends the capsule that carries kernelsu.ko between _end and the relocation table.
  • New ksud boot-restore-v2 [--verify-only] [--flash] undoes an injection from the restore record inside the capsule (capsule v2); no backup file is involved. arm64 comes back byte for byte, x86-64 comes back byte for byte after decompression, so the boot image itself differs and AVB/vbmeta has to be re-signed. --verify-only checks the record without writing anything.
  • The bootstrap logs through printk (resolved as an optional symbol, with a local no-op fallback) and can rewrite the module's vermagic to match the target kernel (--override-vermagic, off by default) for kernels that insist on an exact match.

@u9521
u9521 marked this pull request as draft September 22, 2026 09:46
@u9521
u9521 marked this pull request as ready for review September 22, 2026 10:14
@u9521
u9521 force-pushed the lkm-x64 branch 2 times, most recently from f808216 to 6056fc8 Compare October 6, 2026 03:42
@u9521
u9521 force-pushed the lkm-x64 branch 2 times, most recently from 3c9d9e8 to 0b949eb Compare October 11, 2026 13:23
u9521 added 2 commits October 21, 2026 22:28
boot-patch-v2 now supports x86-64 next to arm64: it decodes the bzImage
payload, recovers kallsyms and BTF from the decompressed image, links
the
bootstrap into unused .text padding, patches the kernel image
reservation,
kernel_init() and load_module() call sites, and appends the KSULKM1
capsule
that carries kernelsu.ko between _end and the kernel relocation table.
The
stub data behind the payload is relocated by a whole number of pages and
every link-time reference that crosses the payload boundary is adjusted;
the capsule is reached through the direct map, because it lives outside
the
kernel image mapping and the virtual and physical KASLR offsets are
independent.

The module is split per architecture (lkm_image/arm64.rs, x86_64.rs)
around
a shared core -- image layout, branch encoding, symbol map, capsule and
report -- so both architectures run the same patch-site scan, resolve
the
same symbol spec lists and print the same report.  The bootstrap link
definitions are pinned by a test that checks them against the embedded
objects.

boot-patch-v2 also writes a restore record into the capsule (capsule v2:
96
-> 112 byte header) and boot-restore-v2 undoes the injection from that
record alone, with no backup file: arm64 comes back byte for byte,
x86-64
comes back byte for byte after decompression (the payload is compressed
again, so the boot image itself differs and AVB/vbmeta has to be
re-signed).  Patching an already patched image restores it in memory
first
and carries the original container fields forward, so updating the
module
is a single command that is idempotent byte for byte.  --verify-only
checks
the record without writing anything.

The injected bootstrap logs what it does through printk (an optional
symbol,
with a cave-local no-op fallback), takes the load_module() argument
string
from the capsule (--module-args, or the --allow-shell/--no-custom-rc/
--bundled switches that mirror boot-patch), and can rewrite the module's
vermagic to match the target kernel (--override-vermagic, off by
default).
The module that ships with KernelSU is called the "bundled" one
throughout,
so that "embedded" keeps meaning "bytes compiled into a binary" and the
kernel image side reads as injected.

Tested against real arm64 GKI and x86-64 AVD kernels: the patched
kernels
boot with the module loaded, boot-restore-v2 gives the original kernel
back
byte for byte, and patching the patched image is a no-op.
Route the shared --block-module option into the capsule params, so
boot-patch-v2 can block vendor anti-root modules the same way boot-patch
does through the ramdisk's /ksu_config.

- Call KsuConfigArgs::validate() before the params are joined: the kernel
  copies block_modules into a 255-byte buffer and truncates silently, which
  would leave some modules unblocked.
- Add block_module to --module-args' conflicts: that flag replaces the
  whole params string, so the combination would silently drop the list.

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant