From 9759a779cd784e83b3480a5f8aecb9afc09dbec2 Mon Sep 17 00:00:00 2001 From: weishu Date: Mon, 18 Mar 2024 23:12:46 +0800 Subject: [PATCH] embed LKM to ksud (#1472) --- .github/workflows/build-ksud.yml | 4 + .github/workflows/ksud.yml | 8 ++ userspace/ksud/bin/.gitignore | 1 + userspace/ksud/src/assets.rs | 3 +- userspace/ksud/src/boot_patch.rs | 137 +++++++++++++++++++------------ userspace/ksud/src/cli.rs | 9 +- 6 files changed, 105 insertions(+), 57 deletions(-) create mode 100644 userspace/ksud/bin/.gitignore diff --git a/.github/workflows/build-ksud.yml b/.github/workflows/build-ksud.yml index 4190fcc0..45e853b9 100644 --- a/.github/workflows/build-ksud.yml +++ b/.github/workflows/build-ksud.yml @@ -13,7 +13,11 @@ on: - '.github/workflows/ksud.yml' - 'userspace/ksud/**' jobs: + build-lkm: + uses: ./.github/workflows/build-lkm.yml + secrets: inherit build: + needs: build-lkm strategy: matrix: include: diff --git a/.github/workflows/ksud.yml b/.github/workflows/ksud.yml index fa786f92..0480e79e 100644 --- a/.github/workflows/ksud.yml +++ b/.github/workflows/ksud.yml @@ -20,6 +20,14 @@ jobs: - uses: actions/checkout@v4 with: fetch-depth: 0 + + - name: Download artifacts + uses: actions/download-artifact@v4 + + - name: Prepare LKM fies + run: | + cp android*-lkm/*_kernelsu.ko ./userspace/ksud/bin/aarch64/ + # cross build failed after Rust 1.68, see https://github.com/cross-rs/cross/issues/1222 - name: Setup rustup run: | diff --git a/userspace/ksud/bin/.gitignore b/userspace/ksud/bin/.gitignore new file mode 100644 index 00000000..1464b7ed --- /dev/null +++ b/userspace/ksud/bin/.gitignore @@ -0,0 +1 @@ +**/*.ko \ No newline at end of file diff --git a/userspace/ksud/src/assets.rs b/userspace/ksud/src/assets.rs index e99193ae..b9ed994d 100644 --- a/userspace/ksud/src/assets.rs +++ b/userspace/ksud/src/assets.rs @@ -22,7 +22,8 @@ struct Asset; pub fn ensure_binaries(ignore_if_exist: bool) -> Result<()> { for file in Asset::iter() { - if file == "ksuinit" { + if file == "ksuinit" || file.ends_with(".ko") { + // don't extract ksuinit and kernel modules continue; } let asset = Asset::get(&file).ok_or(anyhow::anyhow!("asset not found: {}", file))?; diff --git a/userspace/ksud/src/boot_patch.rs b/userspace/ksud/src/boot_patch.rs index 9ec90334..a2e1914a 100644 --- a/userspace/ksud/src/boot_patch.rs +++ b/userspace/ksud/src/boot_patch.rs @@ -47,6 +47,25 @@ pub fn get_kernel_version() -> Result<(i32, i32, i32)> { } } +#[cfg(target_os = "android")] +fn parse_kmi() -> Result { + use regex::Regex; + let uname = rustix::system::uname(); + let version = uname.release().to_string_lossy(); + let re = Regex::new(r"(.* )?(\d+\.\d+)(\S+)?(android\d+)(.*)")?; + let cap = re + .captures(&version) + .ok_or_else(|| anyhow::anyhow!("No match found"))?; + let android_version = cap.get(4).map_or("", |m| m.as_str()); + let kernel_version = cap.get(2).map_or("", |m| m.as_str()); + Ok(format!("{android_version}-{kernel_version}")) +} + +#[cfg(not(target_os = "android"))] +fn parse_kmi() -> Result { + bail!("Unknown KMI, try use --kmi to specify it.") +} + fn do_cpio_cmd(magiskboot: &Path, workding_dir: &Path, cmd: &str) -> Result<()> { let status = Command::new(magiskboot) .current_dir(workding_dir) @@ -98,9 +117,10 @@ pub fn patch( ota: bool, flash: bool, out: Option, - magiskboot_path: Option, + magiskboot: Option, + kmi: Option, ) -> Result<()> { - let result = do_patch(image, kernel, kmod, init, ota, flash, out, magiskboot_path); + let result = do_patch(image, kernel, kmod, init, ota, flash, out, magiskboot, kmi); if let Err(ref e) = result { println!("- Install Error: {e}"); } @@ -117,6 +137,7 @@ fn do_patch( flash: bool, out: Option, magiskboot_path: Option, + kmi: Option, ) -> Result<()> { println!(include_str!("banner")); @@ -132,8 +153,6 @@ fn do_patch( init.is_none() && kmod.is_none(), "init and module must not be specified." ); - } else { - ensure!(kmod.is_some(), "module must be specified"); } let workding_dir = @@ -207,61 +226,71 @@ fn do_patch( .with_context(|| "copy kernel from failed".to_string())?; } + println!("- Preparing assets"); + + let kmod_file = workding_dir.path().join("kernelsu.ko"); if let Some(kmod) = kmod { - println!("- Preparing assets"); - - std::fs::copy(kmod, workding_dir.path().join("kernelsu.ko")) - .with_context(|| "copy kernel module failed".to_string())?; - let init_file = workding_dir.path().join("init"); - if let Some(init) = init { - std::fs::copy(init, workding_dir.path().join("init")) - .with_context(|| "copy init failed".to_string())?; + std::fs::copy(kmod, kmod_file).with_context(|| "copy kernel module failed".to_string())?; + } else { + // If kmod is not specified, extract from assets + let kmi = if let Some(kmi) = kmi { + kmi } else { - crate::assets::copy_assets_to_file("ksuinit", init_file) - .with_context(|| "copy ksuinit failed")?; - } + parse_kmi()? + }; + println!("- KMI: {kmi}"); + let name = format!("{kmi}_kernelsu.ko"); + assets::copy_assets_to_file(&name, kmod_file) + .with_context(|| format!("Failed to copy {name}"))?; + }; - // magiskboot unpack boot.img - // magiskboot cpio ramdisk.cpio 'cp init init.real' - // magiskboot cpio ramdisk.cpio 'add 0755 ksuinit init' - // magiskboot cpio ramdisk.cpio 'add 0755 kernelsu.ko' - - println!("- Unpacking boot image"); - let status = Command::new(&magiskboot) - .current_dir(workding_dir.path()) - .stdout(Stdio::null()) - .stderr(Stdio::null()) - .arg("unpack") - .arg(bootimage.display().to_string()) - .status()?; - ensure!(status.success(), "magiskboot unpack failed"); - - let no_ramdisk = !workding_dir.path().join("ramdisk.cpio").exists(); - let is_magisk_patched = is_magisk_patched(&magiskboot, workding_dir.path())?; - ensure!( - no_ramdisk || !is_magisk_patched, - "Cannot work with Magisk patched image" - ); - - println!("- Adding KernelSU LKM"); - let is_kernelsu_patched = - do_cpio_cmd(&magiskboot, workding_dir.path(), "exists kernelsu.ko").is_ok(); - if !is_kernelsu_patched { - // kernelsu.ko is not exist, backup init if necessary - let status = do_cpio_cmd(&magiskboot, workding_dir.path(), "exists init"); - if status.is_ok() { - do_cpio_cmd(&magiskboot, workding_dir.path(), "mv init init.real")?; - } - } - - do_cpio_cmd(&magiskboot, workding_dir.path(), "add 0755 init init")?; - do_cpio_cmd( - &magiskboot, - workding_dir.path(), - "add 0755 kernelsu.ko kernelsu.ko", - )?; + let init_file = workding_dir.path().join("init"); + if let Some(init) = init { + std::fs::copy(init, init_file).with_context(|| "copy init failed".to_string())?; + } else { + assets::copy_assets_to_file("ksuinit", init_file).with_context(|| "copy ksuinit failed")?; } + // magiskboot unpack boot.img + // magiskboot cpio ramdisk.cpio 'cp init init.real' + // magiskboot cpio ramdisk.cpio 'add 0755 ksuinit init' + // magiskboot cpio ramdisk.cpio 'add 0755 kernelsu.ko' + + println!("- Unpacking boot image"); + let status = Command::new(&magiskboot) + .current_dir(workding_dir.path()) + .stdout(Stdio::null()) + .stderr(Stdio::null()) + .arg("unpack") + .arg(bootimage.display().to_string()) + .status()?; + ensure!(status.success(), "magiskboot unpack failed"); + + let no_ramdisk = !workding_dir.path().join("ramdisk.cpio").exists(); + let is_magisk_patched = is_magisk_patched(&magiskboot, workding_dir.path())?; + ensure!( + no_ramdisk || !is_magisk_patched, + "Cannot work with Magisk patched image" + ); + + println!("- Adding KernelSU LKM"); + let is_kernelsu_patched = + do_cpio_cmd(&magiskboot, workding_dir.path(), "exists kernelsu.ko").is_ok(); + if !is_kernelsu_patched { + // kernelsu.ko is not exist, backup init if necessary + let status = do_cpio_cmd(&magiskboot, workding_dir.path(), "exists init"); + if status.is_ok() { + do_cpio_cmd(&magiskboot, workding_dir.path(), "mv init init.real")?; + } + } + + do_cpio_cmd(&magiskboot, workding_dir.path(), "add 0755 init init")?; + do_cpio_cmd( + &magiskboot, + workding_dir.path(), + "add 0755 kernelsu.ko kernelsu.ko", + )?; + println!("- Repacking boot image"); // magiskboot repack boot.img let status = Command::new(&magiskboot) diff --git a/userspace/ksud/src/cli.rs b/userspace/ksud/src/cli.rs index 1d272319..4f8537d5 100644 --- a/userspace/ksud/src/cli.rs +++ b/userspace/ksud/src/cli.rs @@ -59,7 +59,7 @@ enum Commands { #[arg(short, long)] kernel: Option, - /// LKM module path to replace + /// LKM module path to replace, if not specified, will use the builtin one #[arg(short, long)] module: Option, @@ -82,6 +82,10 @@ enum Commands { /// magiskboot path, if not specified, will use builtin one #[arg(long, default_value = None)] magiskboot: Option, + + /// KMI version, if specified, will use the specified KMI + #[arg(long, default_value = None)] + kmi: Option, }, /// For developers Debug { @@ -316,7 +320,8 @@ pub fn run() -> Result<()> { flash, out, magiskboot, - } => crate::boot_patch::patch(boot, kernel, module, init, ota, flash, out, magiskboot), + kmi, + } => crate::boot_patch::patch(boot, kernel, module, init, ota, flash, out, magiskboot, kmi), }; if let Err(e) = &result {