embed LKM to ksud (#1472)
This commit is contained in:
4
.github/workflows/build-ksud.yml
vendored
4
.github/workflows/build-ksud.yml
vendored
@@ -13,7 +13,11 @@ on:
|
|||||||
- '.github/workflows/ksud.yml'
|
- '.github/workflows/ksud.yml'
|
||||||
- 'userspace/ksud/**'
|
- 'userspace/ksud/**'
|
||||||
jobs:
|
jobs:
|
||||||
|
build-lkm:
|
||||||
|
uses: ./.github/workflows/build-lkm.yml
|
||||||
|
secrets: inherit
|
||||||
build:
|
build:
|
||||||
|
needs: build-lkm
|
||||||
strategy:
|
strategy:
|
||||||
matrix:
|
matrix:
|
||||||
include:
|
include:
|
||||||
|
|||||||
8
.github/workflows/ksud.yml
vendored
8
.github/workflows/ksud.yml
vendored
@@ -20,6 +20,14 @@ jobs:
|
|||||||
- uses: actions/checkout@v4
|
- uses: actions/checkout@v4
|
||||||
with:
|
with:
|
||||||
fetch-depth: 0
|
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
|
# cross build failed after Rust 1.68, see https://github.com/cross-rs/cross/issues/1222
|
||||||
- name: Setup rustup
|
- name: Setup rustup
|
||||||
run: |
|
run: |
|
||||||
|
|||||||
1
userspace/ksud/bin/.gitignore
vendored
Normal file
1
userspace/ksud/bin/.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
|||||||
|
**/*.ko
|
||||||
@@ -22,7 +22,8 @@ struct Asset;
|
|||||||
|
|
||||||
pub fn ensure_binaries(ignore_if_exist: bool) -> Result<()> {
|
pub fn ensure_binaries(ignore_if_exist: bool) -> Result<()> {
|
||||||
for file in Asset::iter() {
|
for file in Asset::iter() {
|
||||||
if file == "ksuinit" {
|
if file == "ksuinit" || file.ends_with(".ko") {
|
||||||
|
// don't extract ksuinit and kernel modules
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
let asset = Asset::get(&file).ok_or(anyhow::anyhow!("asset not found: {}", file))?;
|
let asset = Asset::get(&file).ok_or(anyhow::anyhow!("asset not found: {}", file))?;
|
||||||
|
|||||||
@@ -47,6 +47,25 @@ pub fn get_kernel_version() -> Result<(i32, i32, i32)> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(target_os = "android")]
|
||||||
|
fn parse_kmi() -> Result<String> {
|
||||||
|
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<String> {
|
||||||
|
bail!("Unknown KMI, try use --kmi to specify it.")
|
||||||
|
}
|
||||||
|
|
||||||
fn do_cpio_cmd(magiskboot: &Path, workding_dir: &Path, cmd: &str) -> Result<()> {
|
fn do_cpio_cmd(magiskboot: &Path, workding_dir: &Path, cmd: &str) -> Result<()> {
|
||||||
let status = Command::new(magiskboot)
|
let status = Command::new(magiskboot)
|
||||||
.current_dir(workding_dir)
|
.current_dir(workding_dir)
|
||||||
@@ -98,9 +117,10 @@ pub fn patch(
|
|||||||
ota: bool,
|
ota: bool,
|
||||||
flash: bool,
|
flash: bool,
|
||||||
out: Option<PathBuf>,
|
out: Option<PathBuf>,
|
||||||
magiskboot_path: Option<PathBuf>,
|
magiskboot: Option<PathBuf>,
|
||||||
|
kmi: Option<String>,
|
||||||
) -> Result<()> {
|
) -> 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 {
|
if let Err(ref e) = result {
|
||||||
println!("- Install Error: {e}");
|
println!("- Install Error: {e}");
|
||||||
}
|
}
|
||||||
@@ -117,6 +137,7 @@ fn do_patch(
|
|||||||
flash: bool,
|
flash: bool,
|
||||||
out: Option<PathBuf>,
|
out: Option<PathBuf>,
|
||||||
magiskboot_path: Option<PathBuf>,
|
magiskboot_path: Option<PathBuf>,
|
||||||
|
kmi: Option<String>,
|
||||||
) -> Result<()> {
|
) -> Result<()> {
|
||||||
println!(include_str!("banner"));
|
println!(include_str!("banner"));
|
||||||
|
|
||||||
@@ -132,8 +153,6 @@ fn do_patch(
|
|||||||
init.is_none() && kmod.is_none(),
|
init.is_none() && kmod.is_none(),
|
||||||
"init and module must not be specified."
|
"init and module must not be specified."
|
||||||
);
|
);
|
||||||
} else {
|
|
||||||
ensure!(kmod.is_some(), "module must be specified");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
let workding_dir =
|
let workding_dir =
|
||||||
@@ -207,61 +226,71 @@ fn do_patch(
|
|||||||
.with_context(|| "copy kernel from failed".to_string())?;
|
.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 {
|
if let Some(kmod) = kmod {
|
||||||
println!("- Preparing assets");
|
std::fs::copy(kmod, kmod_file).with_context(|| "copy kernel module failed".to_string())?;
|
||||||
|
} else {
|
||||||
std::fs::copy(kmod, workding_dir.path().join("kernelsu.ko"))
|
// If kmod is not specified, extract from assets
|
||||||
.with_context(|| "copy kernel module failed".to_string())?;
|
let kmi = if let Some(kmi) = kmi {
|
||||||
let init_file = workding_dir.path().join("init");
|
kmi
|
||||||
if let Some(init) = init {
|
|
||||||
std::fs::copy(init, workding_dir.path().join("init"))
|
|
||||||
.with_context(|| "copy init failed".to_string())?;
|
|
||||||
} else {
|
} else {
|
||||||
crate::assets::copy_assets_to_file("ksuinit", init_file)
|
parse_kmi()?
|
||||||
.with_context(|| "copy ksuinit failed")?;
|
};
|
||||||
}
|
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
|
let init_file = workding_dir.path().join("init");
|
||||||
// magiskboot cpio ramdisk.cpio 'cp init init.real'
|
if let Some(init) = init {
|
||||||
// magiskboot cpio ramdisk.cpio 'add 0755 ksuinit init'
|
std::fs::copy(init, init_file).with_context(|| "copy init failed".to_string())?;
|
||||||
// magiskboot cpio ramdisk.cpio 'add 0755 <kmod> kernelsu.ko'
|
} else {
|
||||||
|
assets::copy_assets_to_file("ksuinit", init_file).with_context(|| "copy ksuinit failed")?;
|
||||||
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",
|
|
||||||
)?;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 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 <kmod> 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");
|
println!("- Repacking boot image");
|
||||||
// magiskboot repack boot.img
|
// magiskboot repack boot.img
|
||||||
let status = Command::new(&magiskboot)
|
let status = Command::new(&magiskboot)
|
||||||
|
|||||||
@@ -59,7 +59,7 @@ enum Commands {
|
|||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
kernel: Option<PathBuf>,
|
kernel: Option<PathBuf>,
|
||||||
|
|
||||||
/// LKM module path to replace
|
/// LKM module path to replace, if not specified, will use the builtin one
|
||||||
#[arg(short, long)]
|
#[arg(short, long)]
|
||||||
module: Option<PathBuf>,
|
module: Option<PathBuf>,
|
||||||
|
|
||||||
@@ -82,6 +82,10 @@ enum Commands {
|
|||||||
/// magiskboot path, if not specified, will use builtin one
|
/// magiskboot path, if not specified, will use builtin one
|
||||||
#[arg(long, default_value = None)]
|
#[arg(long, default_value = None)]
|
||||||
magiskboot: Option<PathBuf>,
|
magiskboot: Option<PathBuf>,
|
||||||
|
|
||||||
|
/// KMI version, if specified, will use the specified KMI
|
||||||
|
#[arg(long, default_value = None)]
|
||||||
|
kmi: Option<String>,
|
||||||
},
|
},
|
||||||
/// For developers
|
/// For developers
|
||||||
Debug {
|
Debug {
|
||||||
@@ -316,7 +320,8 @@ pub fn run() -> Result<()> {
|
|||||||
flash,
|
flash,
|
||||||
out,
|
out,
|
||||||
magiskboot,
|
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 {
|
if let Err(e) = &result {
|
||||||
|
|||||||
Reference in New Issue
Block a user