Skip to content

Commit

Permalink
some fixes
Browse files Browse the repository at this point in the history
  • Loading branch information
tiann committed Mar 13, 2024
1 parent 46a35bb commit f411018
Show file tree
Hide file tree
Showing 6 changed files with 106 additions and 54 deletions.
Binary file added userspace/ksud/bin/aarch64/bootctl
Binary file not shown.
Binary file added userspace/ksud/bin/aarch64/ksuinit
Binary file not shown.
Binary file added userspace/ksud/bin/x86_64/ksuinit
Binary file not shown.
17 changes: 12 additions & 5 deletions userspace/ksud/src/assets.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use anyhow::Result;
use const_format::concatcp;
use rust_embed::RustEmbed;
use std::path::Path;

use crate::{defs::BINARY_DIR, utils};

Expand All @@ -19,11 +20,17 @@ struct Asset;

pub fn ensure_binaries(ignore_if_exist: bool) -> Result<()> {
for file in Asset::iter() {
utils::ensure_binary(
format!("{BINARY_DIR}{file}"),
&Asset::get(&file).unwrap().data,
ignore_if_exist,
)?
if file == "ksuinit" {
continue;
}
let asset = Asset::get(&file).ok_or(anyhow::anyhow!("asset not found: {}", file))?;
utils::ensure_binary(format!("{BINARY_DIR}{file}"), &asset.data, ignore_if_exist)?
}
Ok(())
}

pub fn copy_assets_to_file(name: &str, dst: impl AsRef<Path>) -> Result<()> {
let asset = Asset::get(name).ok_or(anyhow::anyhow!("asset not found: {}", name))?;
std::fs::write(dst, asset.data)?;
Ok(())
}
135 changes: 90 additions & 45 deletions userspace/ksud/src/boot_patch.rs
Original file line number Diff line number Diff line change
@@ -1,27 +1,52 @@
#[cfg(unix)]
use std::os::unix::fs::PermissionsExt;

use anyhow::anyhow;
use anyhow::bail;
use anyhow::ensure;
use anyhow::Context;
use anyhow::Result;
use is_executable::IsExecutable;
use std::path::Path;
use std::path::PathBuf;
use std::process::Command;
use std::process::Stdio;
use which::which;

use crate::utils;
use crate::{assets, utils};

#[cfg(unix)]
fn ensure_gki_kernel() -> Result<()> {
let version =
procfs::sys::kernel::Version::current().with_context(|| "get kernel version failed")?;
let is_gki = version.major == 5 && version.minor >= 10 || version.major > 5;
let version = get_kernel_version()?;
let is_gki = version.0 == 5 && version.1 >= 10 || version.2 > 5;
ensure!(is_gki, "only support GKI kernel");
Ok(())
}

#[cfg(unix)]
pub fn get_kernel_version() -> Result<(i32, i32, i32)> {
use regex::Regex;
let uname = rustix::system::uname();
let version = uname.release().to_string_lossy();
let re = Regex::new(r"(\d+)\.(\d+)\.(\d+)")?;
if let Some(captures) = re.captures(&version) {
let major = captures
.get(1)
.and_then(|m| m.as_str().parse::<i32>().ok())
.ok_or_else(|| anyhow!("Major version parse error"))?;
let minor = captures
.get(2)
.and_then(|m| m.as_str().parse::<i32>().ok())
.ok_or_else(|| anyhow!("Minor version parse error"))?;
let patch = captures
.get(3)
.and_then(|m| m.as_str().parse::<i32>().ok())
.ok_or_else(|| anyhow!("Patch version parse error"))?;
Ok((major, minor, patch))
} else {
Err(anyhow!("Invalid kernel version string"))
}
}

fn do_cpio_cmd(magiskboot: &Path, workding_dir: &Path, cmd: &str) -> Result<()> {
let status = Command::new(magiskboot)
.current_dir(workding_dir)
Expand Down Expand Up @@ -65,7 +90,7 @@ pub fn patch(
) -> Result<()> {
let result = do_patch(image, kernel, kmod, init, ota, flash, out, magiskboot_path);
if let Err(ref e) = result {
println!("Error: {e}");
println!("-Install Error: {e}");
}
result
}
Expand Down Expand Up @@ -96,19 +121,17 @@ fn do_patch(
"init and module must not be specified."
);
} else {
ensure!(
init.is_some() && kmod.is_some(),
"init and module must be specified"
);
ensure!(kmod.is_some(), "module must be specified");
}

let workding_dir = tempdir::TempDir::new("KernelSU")?;
let workding_dir =
tempdir::TempDir::new("KernelSU").with_context(|| "create temp dir failed")?;

let bootimage;

let mut bootdevice = None;

if let Some(image) = image {
if let Some(ref image) = image {
ensure!(image.exists(), "boot image not found");
bootimage = std::fs::canonicalize(image)?;
} else {
Expand All @@ -131,7 +154,7 @@ fn do_patch(
format!("/dev/block/by-name/boot{slot_suffix}")
};

println!("bootdevice: {boot_partition}");
println!("- Bootdevice: {boot_partition}");
let tmp_boot_path = workding_dir.path().join("boot.img");

dd(&boot_partition, &tmp_boot_path)?;
Expand All @@ -142,38 +165,53 @@ fn do_patch(
bootdevice = Some(boot_partition);
};

println!("- Boot image: {bootimage:?}");

let magiskboot = magiskboot_path
.map(std::fs::canonicalize)
.transpose()?
.unwrap_or_else(|| "magiskboot".into());

if !magiskboot.is_executable() {
#[cfg(unix)]
std::fs::set_permissions(&magiskboot, std::fs::Permissions::from_mode(0o755))
.with_context(|| "set magiskboot executable failed".to_string())?;
}

ensure!(magiskboot.exists(), "magiskboot not found");
// extract magiskboot
let magiskboot = {
if which("magiskboot").is_ok() {
let _ = assets::ensure_binaries(true);
"magiskboot".into()
} else {
// magiskboot is not in $PATH, use builtin or specified one
let magiskboot = if let Some(magiskboot_path) = magiskboot_path {
std::fs::canonicalize(magiskboot_path)?
} else {
let magiskboot_path = workding_dir.path().join("magiskboot");
assets::copy_assets_to_file("magiskboot", &magiskboot_path)
.with_context(|| "copy magiskboot failed")?;
magiskboot_path
};
ensure!(magiskboot.exists(), "{magiskboot:?} is not exist");
#[cfg(unix)]
let _ = std::fs::set_permissions(&magiskboot, std::fs::Permissions::from_mode(0o755));
magiskboot
}
};

if let Some(kernel) = kernel {
std::fs::copy(kernel, workding_dir.path().join("kernel"))
.with_context(|| "copy kernel from failed".to_string())?;
}

println!("- Patching boot image...");
if let (Some(kmod), Some(init)) = (kmod, init) {
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())?;
std::fs::copy(init, workding_dir.path().join("init"))
.with_context(|| "copy init 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())?;
} else {
crate::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 <kmod> kernelsu.ko'

println!("- Unpacking boot image");
let status = Command::new(&magiskboot)
.current_dir(workding_dir.path())
.stdout(Stdio::null())
Expand All @@ -183,6 +221,7 @@ fn do_patch(
.status()?;
ensure!(status.success(), "magiskboot unpack failed");

println!("- Adding KernelSU LKM");
let is_kernelsu_patched =
do_cpio_cmd(&magiskboot, workding_dir.path(), "exists kernelsu.ko").is_ok();
if !is_kernelsu_patched {
Expand All @@ -201,6 +240,7 @@ fn do_patch(
)?;
}

println!("- Repacking boot image");
// magiskboot repack boot.img
let status = Command::new(&magiskboot)
.current_dir(workding_dir.path())
Expand All @@ -210,20 +250,25 @@ fn do_patch(
.arg(bootimage.display().to_string())
.status()?;
ensure!(status.success(), "magiskboot repack failed");
let new_boot = workding_dir.path().join("new-boot.img");

if image.is_some() {
// if image is specified, write to output file
let output_dir = out.unwrap_or(std::env::current_dir()?);
let now = chrono::Utc::now();
let output_image =
output_dir.join(format!("kernelsu_boot_{}.img", now.format("%Y%m%d_%H%M%S")));

if std::fs::rename(&new_boot, &output_image).is_err() {
std::fs::copy(&new_boot, &output_image)
.with_context(|| "copy out new boot failed".to_string())?;
}
println!("- Output file is written to");
println!("- {}", output_image.display().to_string().trim_matches('"'));
}

let out = out.unwrap_or(std::env::current_dir()?);

let now = chrono::Utc::now();
let output_image = out.join(format!(
"kernelsu_patched_boot_{}.img",
now.format("%Y%m%d_%H%M%S")
));
std::fs::copy(workding_dir.path().join("new-boot.img"), &output_image)
.with_context(|| "copy out new boot failed".to_string())?;

println!("- Boot image patched: {output_image:?}");
if flash {
println!("- Flashing boot image...");
println!("- Flashing new boot image");
let Some(bootdevice) = bootdevice else {
bail!("boot device not found")
};
Expand All @@ -233,9 +278,9 @@ fn do_patch(
.status()?;
ensure!(status.success(), "set boot device rw failed");

dd(&output_image, &bootdevice).with_context(|| "flash boot failed")?;
dd(&new_boot, &bootdevice).with_context(|| "flash boot failed")?;
}

println!("- Done.");
println!("- Done!");
Ok(())
}
8 changes: 4 additions & 4 deletions userspace/ksud/src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use android_logger::Config;
#[cfg(target_os = "android")]
use log::LevelFilter;

use crate::{apk_sign, debug, defs, init_event, ksucalls, module, utils};
use crate::{apk_sign, assets, debug, defs, init_event, ksucalls, module, utils};

/// KernelSU userspace cli
#[derive(Parser, Debug)]
Expand Down Expand Up @@ -60,10 +60,10 @@ enum Commands {
kernel: Option<PathBuf>,

/// LKM module path to replace
#[arg(short, long, requires("init"))]
#[arg(short, long)]
module: Option<PathBuf>,

/// init to be replaced, if use LKM, this must be specified
/// init to be replaced
#[arg(short, long, requires("module"))]
init: Option<PathBuf>,

Expand Down Expand Up @@ -304,7 +304,7 @@ pub fn run() -> Result<()> {
utils::copy_sparse_file(src, dst, punch_hole)?;
Ok(())
}
Debug::Test => todo!(),
Debug::Test => assets::ensure_binaries(false),
},

Commands::BootPatch {
Expand Down

0 comments on commit f411018

Please sign in to comment.