[skip ci]ksud: support vendor_boot patching for some odd devices (#2650)

This will add support to patch vendor_boot with LKM for devices which
have their init ramdisk inside of vendor_boot and not boot/init_boot.

---------

Co-authored-by: Rifat Azad <rifat.44.azad.rifs@gmail.com>
Co-authored-by: 5ec1cff <ewtqyqyewtqyqy@gmail.com>
Co-authored-by: 5ec1cff <56485584+5ec1cff@users.noreply.github.com>
This commit is contained in:
ShirkNeko
2025-08-10 17:31:43 +08:00
parent 0754fc8920
commit c1c648e34d

View File

@@ -153,82 +153,40 @@ fn parse_kmi_from_boot(magiskboot: &Path, image: &PathBuf, workdir: &Path) -> Re
parse_kmi_from_kernel(&image_path, workdir) parse_kmi_from_kernel(&image_path, workdir)
} }
fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> { fn do_cpio_cmd(magiskboot: &Path, workdir: &Path, cpio_path: &Path, cmd: &str) -> Result<()> {
let status = Command::new(magiskboot) let status = Command::new(magiskboot)
.current_dir(workdir) .current_dir(workdir)
.stdout(Stdio::null()) .stdout(Stdio::null())
.stderr(Stdio::null()) .stderr(Stdio::null())
.arg("cpio") .arg("cpio")
.arg("ramdisk.cpio") .arg(cpio_path)
.arg(cmd) .arg(cmd)
.status()?; .status()?;
ensure!(status.success(), "magiskboot cpio {} failed", cmd); ensure!(status.success(), "magiskboot cpio {} failed", cmd);
Ok(()) Ok(())
} }
fn do_vendor_init_boot_cpio_cmd(magiskboot: &Path, workdir: &Path, cmd: &str) -> Result<()> { fn is_magisk_patched(magiskboot: &Path, workdir: &Path, cpio_path: &Path) -> Result<bool> {
let vendor_init_boot_cpio = workdir.join("vendor_ramdisk").join("init_boot.cpio");
let status = Command::new(magiskboot) let status = Command::new(magiskboot)
.current_dir(workdir) .current_dir(workdir)
.stdout(Stdio::null()) .stdout(Stdio::null())
.stderr(Stdio::null()) .stderr(Stdio::null())
.arg("cpio") .arg("cpio")
.arg(vendor_init_boot_cpio) .arg(cpio_path)
.arg(cmd) .arg("test")
.status()?; .status()?;
ensure!(status.success(), "magiskboot cpio {} failed", cmd);
Ok(())
}
fn is_magisk_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args(["cpio", "ramdisk.cpio", "test"])
.status()?;
// 0: stock, 1: magisk // 0: stock, 1: magisk
Ok(status.code() == Some(1)) Ok(status.code() == Some(1))
} }
fn is_magisk_patched_vendor_init_boot(magiskboot: &Path, workdir: &Path) -> Result<bool> { fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path, cpio_path: &Path) -> Result<bool> {
let vendor_init_boot_cpio = workdir.join("vendor_ramdisk").join("init_boot.cpio");
let status = Command::new(magiskboot) let status = Command::new(magiskboot)
.current_dir(workdir) .current_dir(workdir)
.stdout(Stdio::null()) .stdout(Stdio::null())
.stderr(Stdio::null()) .stderr(Stdio::null())
.args(["cpio", vendor_init_boot_cpio.to_str().unwrap(), "test"]) .arg("cpio")
.status()?; .arg(cpio_path)
.arg("exists kernelsu.ko")
// 0: stock, 1: magisk
Ok(status.code() == Some(1))
}
fn is_kernelsu_patched(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args(["cpio", "ramdisk.cpio", "exists kernelsu.ko"])
.status()?;
Ok(status.success())
}
fn is_kernelsu_patched_vendor_init_boot(magiskboot: &Path, workdir: &Path) -> Result<bool> {
let vendor_ramdisk_cpio = workdir.join("vendor_ramdisk").join("init_boot.cpio");
let status = Command::new(magiskboot)
.current_dir(workdir)
.stdout(Stdio::null())
.stderr(Stdio::null())
.args([
"cpio",
vendor_ramdisk_cpio.to_str().unwrap(),
"exists kernelsu.ko",
])
.status()?; .status()?;
Ok(status.success()) Ok(status.success())
@@ -278,24 +236,37 @@ pub fn restore(
.status()?; .status()?;
ensure!(status.success(), "magiskboot unpack failed"); ensure!(status.success(), "magiskboot unpack failed");
let no_ramdisk = !workdir.join("ramdisk.cpio").exists(); let mut ramdisk = workdir.join("ramdisk.cpio");
let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?; if !ramdisk.exists() {
let is_kernelsu_patched_vendor_init_boot = ramdisk = workdir.join("vendor_ramdisk").join("init_boot.cpio")
is_kernelsu_patched_vendor_init_boot(&magiskboot, workdir)?; }
ensure!( if !ramdisk.exists() {
is_kernelsu_patched || is_kernelsu_patched_vendor_init_boot, ramdisk = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
"boot image is not patched by KernelSU" }
); if !ramdisk.exists() {
bail!("No compatible ramdisk found.")
}
let ramdisk = ramdisk.as_path();
let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir, ramdisk)?;
ensure!(is_kernelsu_patched, "boot image is not patched by KernelSU");
let mut new_boot = None; let mut new_boot = None;
let mut from_backup = false; let mut from_backup = false;
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
if do_cpio_cmd(&magiskboot, workdir, &format!("exists {BACKUP_FILENAME}")).is_ok() { if do_cpio_cmd(
&magiskboot,
workdir,
ramdisk,
&format!("exists {BACKUP_FILENAME}"),
)
.is_ok()
{
do_cpio_cmd( do_cpio_cmd(
&magiskboot, &magiskboot,
workdir, workdir,
&format!("extract {0} {0}", BACKUP_FILENAME), ramdisk,
&format!("extract {BACKUP_FILENAME} {BACKUP_FILENAME}"),
)?; )?;
let sha = std::fs::read(workdir.join(BACKUP_FILENAME))?; let sha = std::fs::read(workdir.join(BACKUP_FILENAME))?;
let sha = String::from_utf8(sha)?; let sha = String::from_utf8(sha)?;
@@ -317,29 +288,13 @@ pub fn restore(
} }
if new_boot.is_none() { if new_boot.is_none() {
if no_ramdisk { // remove kernelsu.ko
// vendor init_boot restore do_cpio_cmd(&magiskboot, workdir, ramdisk, "rm kernelsu.ko")?;
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
// if init.real exists, restore it // if init.real exists, restore it
let status = let status = do_cpio_cmd(&magiskboot, workdir, ramdisk, "exists init.real").is_ok();
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok(); if status {
if status { do_cpio_cmd(&magiskboot, workdir, ramdisk, "mv init.real init")?;
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
} else {
let vendor_init_boot = workdir.join("vendor_ramdisk").join("init_boot.cpio");
std::fs::remove_file(vendor_init_boot)?;
}
} else {
// remove kernelsu.ko
do_cpio_cmd(&magiskboot, workdir, "rm kernelsu.ko")?;
// if init.real exists, restore it
let status = do_cpio_cmd(&magiskboot, workdir, "exists init.real").is_ok();
if status {
do_cpio_cmd(&magiskboot, workdir, "mv init.real init")?;
} else {
let ramdisk = workdir.join("ramdisk.cpio");
std::fs::remove_file(ramdisk)?;
}
} }
println!("- Repacking boot image"); println!("- Repacking boot image");
@@ -348,7 +303,7 @@ pub fn restore(
.stdout(Stdio::null()) .stdout(Stdio::null())
.stderr(Stdio::null()) .stderr(Stdio::null())
.arg("repack") .arg("repack")
.arg(bootimage.display().to_string()) .arg(&bootimage)
.status()?; .status()?;
ensure!(status.success(), "magiskboot repack failed"); ensure!(status.success(), "magiskboot repack failed");
new_boot = Some(workdir.join("new-boot.img")); new_boot = Some(workdir.join("new-boot.img"));
@@ -447,7 +402,7 @@ fn do_patch(
match get_current_kmi() { match get_current_kmi() {
Ok(value) => value, Ok(value) => value,
Err(e) => { Err(e) => {
println!("- {}", e); println!("- {e}");
if let Some(image_path) = &image { if let Some(image_path) = &image {
println!( println!(
"- Trying to auto detect KMI version for {}", "- Trying to auto detect KMI version for {}",
@@ -472,7 +427,7 @@ fn do_patch(
let (bootimage, bootdevice) = let (bootimage, bootdevice) =
find_boot_image(&image, skip_init, ota, is_replace_kernel, workdir)?; find_boot_image(&image, skip_init, ota, is_replace_kernel, workdir)?;
let bootimage = bootimage.display().to_string(); let bootimage = bootimage.as_path();
// try extract magiskboot/bootctl // try extract magiskboot/bootctl
let _ = assets::ensure_binaries(false); let _ = assets::ensure_binaries(false);
@@ -501,71 +456,54 @@ fn do_patch(
assets::copy_assets_to_file("ksuinit", init_file).context("copy ksuinit failed")?; assets::copy_assets_to_file("ksuinit", init_file).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 <kmod> kernelsu.ko'
println!("- Unpacking boot image"); println!("- Unpacking boot image");
let status = Command::new(&magiskboot) let status = Command::new(&magiskboot)
.current_dir(workdir) .current_dir(workdir)
.stdout(Stdio::null()) .stdout(Stdio::null())
.stderr(Stdio::null()) .stderr(Stdio::null())
.arg("unpack") .arg("unpack")
.arg(&bootimage) .arg(bootimage)
.status()?; .status()?;
ensure!(status.success(), "magiskboot unpack failed"); ensure!(status.success(), "magiskboot unpack failed");
let no_ramdisk = !workdir.join("ramdisk.cpio").exists(); let mut ramdisk = workdir.join("ramdisk.cpio");
let no_vendor_init_boot = !workdir if !ramdisk.exists() {
.join("vendor_ramdisk") ramdisk = workdir.join("vendor_ramdisk").join("init_boot.cpio")
.join("init_boot.cpio") }
.exists(); if !ramdisk.exists() {
if no_ramdisk && no_vendor_init_boot { ramdisk = workdir.join("vendor_ramdisk").join("ramdisk.cpio");
}
if !ramdisk.exists() {
bail!("No compatible ramdisk found."); bail!("No compatible ramdisk found.");
} }
let is_magisk_patched = is_magisk_patched(&magiskboot, workdir)?; let ramdisk = ramdisk.as_path();
let is_magisk_patched_vendor_init_boot = let is_magisk_patched = is_magisk_patched(&magiskboot, workdir, ramdisk)?;
is_magisk_patched_vendor_init_boot(&magiskboot, workdir)?; ensure!(!is_magisk_patched, "Cannot work with Magisk patched image");
ensure!(
!is_magisk_patched || !is_magisk_patched_vendor_init_boot,
"Cannot work with Magisk patched image"
);
println!("- Adding KernelSU LKM"); println!("- Adding KernelSU LKM");
let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir)?; let is_kernelsu_patched = is_kernelsu_patched(&magiskboot, workdir, ramdisk)?;
let is_kernelsu_patched_vendor_init_boot =
is_kernelsu_patched_vendor_init_boot(&magiskboot, workdir)?;
let mut need_backup = false; let mut need_backup = false;
if !is_kernelsu_patched || (no_ramdisk && !is_kernelsu_patched_vendor_init_boot) { if !is_kernelsu_patched {
if no_ramdisk { // kernelsu.ko is not exist, backup init if necessary
// vendor init_boot patching let status = do_cpio_cmd(&magiskboot, workdir, ramdisk, "exists init");
let status = do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "exists init"); if status.is_ok() {
if status.is_ok() { do_cpio_cmd(&magiskboot, workdir, ramdisk, "mv init init.real")?;
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
}
} else {
// kernelsu.ko is not exist, backup init if necessary
let status = do_cpio_cmd(&magiskboot, workdir, "exists init");
if status.is_ok() {
do_cpio_cmd(&magiskboot, workdir, "mv init init.real")?;
}
need_backup = flash;
} }
need_backup = flash;
} }
if no_ramdisk { do_cpio_cmd(&magiskboot, workdir, ramdisk, "add 0755 init init")?;
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?; do_cpio_cmd(
do_vendor_init_boot_cpio_cmd(&magiskboot, workdir, "add 0755 kernelsu.ko kernelsu.ko")?; &magiskboot,
} else { workdir,
do_cpio_cmd(&magiskboot, workdir, "add 0755 init init")?; ramdisk,
do_cpio_cmd(&magiskboot, workdir, "add 0755 kernelsu.ko kernelsu.ko")?; "add 0755 kernelsu.ko kernelsu.ko",
} )?;
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
if need_backup { if need_backup {
if let Err(e) = do_backup(&magiskboot, workdir, &bootimage) { if let Err(e) = do_backup(&magiskboot, workdir, ramdisk, bootimage) {
println!("- Backup stock image failed: {e}"); println!("- Backup stock image failed: {e}");
} }
} }
@@ -577,7 +515,7 @@ fn do_patch(
.stdout(Stdio::null()) .stdout(Stdio::null())
.stderr(Stdio::null()) .stderr(Stdio::null())
.arg("repack") .arg("repack")
.arg(&bootimage) .arg(bootimage)
.status()?; .status()?;
ensure!(status.success(), "magiskboot repack failed"); ensure!(status.success(), "magiskboot repack failed");
let new_boot = workdir.join("new-boot.img"); let new_boot = workdir.join("new-boot.img");
@@ -587,7 +525,7 @@ fn do_patch(
let output_dir = out.unwrap_or(std::env::current_dir()?); let output_dir = out.unwrap_or(std::env::current_dir()?);
let now = chrono::Utc::now(); let now = chrono::Utc::now();
let output_image = output_dir.join(format!( let output_image = output_dir.join(format!(
"SukiSU_patched_{}.img", "kernelsu_patched_{}.img",
now.format("%Y%m%d_%H%M%S") now.format("%Y%m%d_%H%M%S")
)); ));
@@ -628,11 +566,11 @@ fn calculate_sha1(file_path: impl AsRef<Path>) -> Result<String> {
} }
let result = hasher.finalize(); let result = hasher.finalize();
Ok(format!("{:x}", result)) Ok(format!("{result:x}"))
} }
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
fn do_backup(magiskboot: &Path, workdir: &Path, image: &str) -> Result<()> { fn do_backup(magiskboot: &Path, workdir: &Path, cpio_path: &Path, image: &Path) -> Result<()> {
let sha1 = calculate_sha1(image)?; let sha1 = calculate_sha1(image)?;
let filename = format!("{KSU_BACKUP_FILE_PREFIX}{sha1}"); let filename = format!("{KSU_BACKUP_FILE_PREFIX}{sha1}");
@@ -644,7 +582,8 @@ fn do_backup(magiskboot: &Path, workdir: &Path, image: &str) -> Result<()> {
do_cpio_cmd( do_cpio_cmd(
magiskboot, magiskboot,
workdir, workdir,
&format!("add 0755 {0} {0}", BACKUP_FILENAME), cpio_path,
&format!("add 0755 {BACKUP_FILENAME} {BACKUP_FILENAME}"),
)?; )?;
println!("- Stock image has been backup to"); println!("- Stock image has been backup to");
println!("- {target}"); println!("- {target}");
@@ -654,7 +593,7 @@ fn do_backup(magiskboot: &Path, workdir: &Path, image: &str) -> Result<()> {
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
fn clean_backup(sha1: &str) -> Result<()> { fn clean_backup(sha1: &str) -> Result<()> {
println!("- Clean up backup"); println!("- Clean up backup");
let backup_name = format!("{}{}", KSU_BACKUP_FILE_PREFIX, sha1); let backup_name = format!("{KSU_BACKUP_FILE_PREFIX}{sha1}");
let dir = std::fs::read_dir(defs::KSU_BACKUP_DIR)?; let dir = std::fs::read_dir(defs::KSU_BACKUP_DIR)?;
for entry in dir.flatten() { for entry in dir.flatten() {
let path = entry.path(); let path = entry.path();