diff --git a/userspace/ksud/src/boot_patch.rs b/userspace/ksud/src/boot_patch.rs index c665cb8185f5..24fa6ef24e48 100644 --- a/userspace/ksud/src/boot_patch.rs +++ b/userspace/ksud/src/boot_patch.rs @@ -162,10 +162,14 @@ pub fn patch( .status()?; ensure!(status.success(), "magiskboot unpack failed"); - let status = do_cpio_cmd(&magiskboot, workding_dir.path(), "exists init"); - if status.is_ok() { - // init exist, backup it. - do_cpio_cmd(&magiskboot, workding_dir.path(), "mv init init.real")?; + 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")?; diff --git a/userspace/ksud/src/cli.rs b/userspace/ksud/src/cli.rs index f8892b67255e..ffca157a2142 100644 --- a/userspace/ksud/src/cli.rs +++ b/userspace/ksud/src/cli.rs @@ -7,7 +7,7 @@ use android_logger::Config; #[cfg(target_os = "android")] use log::LevelFilter; -use crate::{apk_sign, debug, defs, event, module, utils}; +use crate::{apk_sign, debug, defs, init_event, ksucalls, module, utils}; /// KernelSU userspace cli #[derive(Parser, Debug)] @@ -239,7 +239,7 @@ pub fn run() -> Result<()> { // the kernel executes su with argv[0] = "su" and replace it with us let arg0 = std::env::args().next().unwrap_or_default(); if arg0 == "su" || arg0 == "/system/bin/su" { - return crate::ksu::root_shell(); + return crate::su::root_shell(); } let cli = Args::parse(); @@ -247,8 +247,8 @@ pub fn run() -> Result<()> { log::info!("command: {:?}", cli.command); let result = match cli.command { - Commands::PostFsData => event::on_post_data_fs(), - Commands::BootCompleted => event::on_boot_completed(), + Commands::PostFsData => init_event::on_post_data_fs(), + Commands::BootCompleted => init_event::on_boot_completed(), Commands::Module { command } => { #[cfg(any(target_os = "linux", target_os = "android"))] @@ -265,13 +265,13 @@ pub fn run() -> Result<()> { Module::Shrink => module::shrink_ksu_images(), } } - Commands::Install => event::install(), + Commands::Install => utils::install(), Commands::Sepolicy { command } => match command { Sepolicy::Patch { sepolicy } => crate::sepolicy::live_patch(&sepolicy), Sepolicy::Apply { file } => crate::sepolicy::apply_file(file), Sepolicy::Check { sepolicy } => crate::sepolicy::check_rule(&sepolicy), }, - Commands::Services => event::on_services(), + Commands::Services => init_event::on_services(), Commands::Profile { command } => match command { Profile::GetSepolicy { package } => crate::profile::get_sepolicy(package), Profile::SetSepolicy { package, policy } => { @@ -291,11 +291,11 @@ pub fn run() -> Result<()> { Ok(()) } Debug::Version => { - println!("Kernel Version: {}", crate::ksu::get_version()); + println!("Kernel Version: {}", ksucalls::get_version()); Ok(()) } - Debug::Su { global_mnt } => crate::ksu::grant_root(global_mnt), - Debug::Mount => event::mount_systemlessly(defs::MODULE_DIR), + Debug::Su { global_mnt } => crate::su::grant_root(global_mnt), + Debug::Mount => init_event::mount_modules_systemlessly(defs::MODULE_DIR), Debug::Xcp { src, dst, diff --git a/userspace/ksud/src/event.rs b/userspace/ksud/src/init_event.rs similarity index 87% rename from userspace/ksud/src/event.rs rename to userspace/ksud/src/init_event.rs index a7a16b11a315..7107ff74225d 100644 --- a/userspace/ksud/src/event.rs +++ b/userspace/ksud/src/init_event.rs @@ -1,13 +1,11 @@ use anyhow::{bail, Context, Result}; use log::{info, warn}; -#[cfg(target_os = "android")] -use std::path::PathBuf; use std::{collections::HashMap, path::Path}; use crate::module::prune_modules; use crate::{ - assets, defs, mount, restorecon, - utils::{self, ensure_clean_dir, ensure_dir_exists}, + assets, defs, ksucalls, mount, restorecon, + utils::{self, ensure_clean_dir}, }; fn mount_partition(partition_name: &str, lowerdir: &Vec) -> Result<()> { @@ -35,7 +33,7 @@ fn mount_partition(partition_name: &str, lowerdir: &Vec) -> Result<()> { mount::mount_overlay(&partition, lowerdir, workdir, upperdir) } -pub fn mount_systemlessly(module_dir: &str) -> Result<()> { +pub fn mount_modules_systemlessly(module_dir: &str) -> Result<()> { // construct overlay mount params let dir = std::fs::read_dir(module_dir); let Ok(dir) = dir else { @@ -99,12 +97,14 @@ pub fn mount_systemlessly(module_dir: &str) -> Result<()> { } pub fn on_post_data_fs() -> Result<()> { - crate::ksu::report_post_fs_data(); + ksucalls::report_post_fs_data(); utils::umask(0); #[cfg(unix)] - let _ = catch_bootlog(); + let _ = catch_bootlog("logcat", vec!["logcat"]); + #[cfg(unix)] + let _ = catch_bootlog("dmesg", vec!["dmesg", "-w"]); if utils::has_magisk() { warn!("Magisk detected, skip post-fs-data!"); @@ -162,7 +162,7 @@ pub fn on_post_data_fs() -> Result<()> { .with_context(|| "mount module image failed".to_string())?; // tell kernel that we've mount the module, so that it can do some optimization - crate::ksu::report_module_mounted(); + ksucalls::report_module_mounted(); // if we are in safe mode, we should disable all modules if safe_mode { @@ -207,7 +207,7 @@ pub fn on_post_data_fs() -> Result<()> { } // mount module systemlessly by overlay - if let Err(e) = mount_systemlessly(module_dir) { + if let Err(e) = mount_modules_systemlessly(module_dir) { warn!("do systemless mount failed: {}", e); } @@ -247,7 +247,7 @@ pub fn on_services() -> Result<()> { } pub fn on_boot_completed() -> Result<()> { - crate::ksu::report_boot_complete(); + ksucalls::report_boot_complete(); info!("on_boot_completed triggered!"); let module_update_img = Path::new(defs::MODULE_UPDATE_IMG); let module_img = Path::new(defs::MODULE_IMG); @@ -266,38 +266,15 @@ pub fn on_boot_completed() -> Result<()> { Ok(()) } -pub fn install() -> Result<()> { - ensure_dir_exists(defs::ADB_DIR)?; - std::fs::copy("/proc/self/exe", defs::DAEMON_PATH)?; - restorecon::lsetfilecon(defs::DAEMON_PATH, restorecon::ADB_CON)?; - // install binary assets - assets::ensure_binaries(false).with_context(|| "Failed to extract assets")?; - - #[cfg(target_os = "android")] - link_ksud_to_bin()?; - - Ok(()) -} - -#[cfg(target_os = "android")] -fn link_ksud_to_bin() -> Result<()> { - let ksu_bin = PathBuf::from(defs::DAEMON_PATH); - let ksu_bin_link = PathBuf::from(defs::DAEMON_LINK_PATH); - if ksu_bin.exists() && !ksu_bin_link.exists() { - std::os::unix::fs::symlink(&ksu_bin, &ksu_bin_link)?; - } - Ok(()) -} - #[cfg(unix)] -fn catch_bootlog() -> Result<()> { +fn catch_bootlog(logname: &str, command: Vec<&str>) -> Result<()> { use std::os::unix::process::CommandExt; use std::process::Stdio; let logdir = Path::new(defs::LOG_DIR); utils::ensure_dir_exists(logdir)?; - let bootlog = logdir.join("boot.log"); - let oldbootlog = logdir.join("boot.old.log"); + let bootlog = logdir.join(format!("{logname}.log")); + let oldbootlog = logdir.join(format!("{logname}.old.log")); if bootlog.exists() { std::fs::rename(&bootlog, oldbootlog)?; @@ -305,6 +282,8 @@ fn catch_bootlog() -> Result<()> { let bootlog = std::fs::File::create(bootlog)?; + let mut args = vec!["-s", "9", "30s"]; + args.extend_from_slice(&command); // timeout -s 9 30s logcat > boot.log let result = unsafe { std::process::Command::new("timeout") @@ -313,10 +292,7 @@ fn catch_bootlog() -> Result<()> { utils::switch_cgroups(); Ok(()) }) - .arg("-s") - .arg("9") - .arg("30s") - .arg("logcat") + .args(args) .stdout(Stdio::from(bootlog)) .spawn() }; diff --git a/userspace/ksud/src/ksucalls.rs b/userspace/ksud/src/ksucalls.rs new file mode 100644 index 000000000000..596df5458670 --- /dev/null +++ b/userspace/ksud/src/ksucalls.rs @@ -0,0 +1,43 @@ +const EVENT_POST_FS_DATA: u64 = 1; +const EVENT_BOOT_COMPLETED: u64 = 2; +const EVENT_MODULE_MOUNTED: u64 = 3; + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn get_version() -> i32 { + rustix::process::ksu_get_version() +} + +#[cfg(not(any(target_os = "linux", target_os = "android")))] +pub fn get_version() -> i32 { + 0 +} + +#[cfg(any(target_os = "linux", target_os = "android"))] +fn report_event(event: u64) { + rustix::process::ksu_report_event(event) +} + +#[cfg(not(any(target_os = "linux", target_os = "android")))] +fn report_event(_event: u64) {} + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub fn check_kernel_safemode() -> bool { + rustix::process::ksu_check_kernel_safemode() +} + +#[cfg(not(any(target_os = "linux", target_os = "android")))] +pub fn check_kernel_safemode() -> bool { + false +} + +pub fn report_post_fs_data() { + report_event(EVENT_POST_FS_DATA); +} + +pub fn report_boot_complete() { + report_event(EVENT_BOOT_COMPLETED); +} + +pub fn report_module_mounted() { + report_event(EVENT_MODULE_MOUNTED); +} diff --git a/userspace/ksud/src/main.rs b/userspace/ksud/src/main.rs index f95ab0371e83..3b51720557c1 100644 --- a/userspace/ksud/src/main.rs +++ b/userspace/ksud/src/main.rs @@ -4,13 +4,14 @@ mod boot_patch; mod cli; mod debug; mod defs; -mod event; -mod ksu; +mod init_event; +mod ksucalls; mod module; mod mount; mod profile; mod restorecon; mod sepolicy; +mod su; mod utils; fn main() -> anyhow::Result<()> { diff --git a/userspace/ksud/src/module.rs b/userspace/ksud/src/module.rs index 189306b6adcf..ccb5367ffbb8 100644 --- a/userspace/ksud/src/module.rs +++ b/userspace/ksud/src/module.rs @@ -1,7 +1,7 @@ #[allow(clippy::wildcard_imports)] use crate::utils::*; use crate::{ - assets, defs, mount, + assets, defs, ksucalls, mount, restorecon::{restore_syscon, setsyscon}, sepolicy, utils, }; @@ -53,7 +53,7 @@ fn exec_install_script(module_file: &str) -> Result<()> { ), ) .env("KSU", "true") - .env("KSU_KERNEL_VER_CODE", crate::ksu::get_version().to_string()) + .env("KSU_KERNEL_VER_CODE", ksucalls::get_version().to_string()) .env("KSU_VER", defs::VERSION_NAME) .env("KSU_VER_CODE", defs::VERSION_CODE) .env("OUTFD", "1") @@ -178,7 +178,7 @@ fn exec_script>(path: T, wait: bool) -> Result<()> { .arg(path.as_ref()) .env("ASH_STANDALONE", "1") .env("KSU", "true") - .env("KSU_KERNEL_VER_CODE", crate::ksu::get_version().to_string()) + .env("KSU_KERNEL_VER_CODE", ksucalls::get_version().to_string()) .env("KSU_VER_CODE", defs::VERSION_CODE) .env("KSU_VER", defs::VERSION_NAME) .env( diff --git a/userspace/ksud/src/ksu.rs b/userspace/ksud/src/su.rs similarity index 89% rename from userspace/ksud/src/ksu.rs rename to userspace/ksud/src/su.rs index 3e6e4072e964..6baec10da93d 100644 --- a/userspace/ksud/src/ksu.rs +++ b/userspace/ksud/src/su.rs @@ -17,10 +17,6 @@ use rustix::{ thread::{set_thread_res_gid, set_thread_res_uid, Gid, Uid}, }; -const EVENT_POST_FS_DATA: u64 = 1; -const EVENT_BOOT_COMPLETED: u64 = 2; -const EVENT_MODULE_MOUNTED: u64 = 3; - #[cfg(any(target_os = "linux", target_os = "android"))] pub fn grant_root(global_mnt: bool) -> Result<()> { const KERNEL_SU_OPTION: u32 = 0xDEAD_BEEF; @@ -303,43 +299,3 @@ fn add_path_to_env(path: &str) -> Result<()> { env::set_var("PATH", new_path_env); Ok(()) } - -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn get_version() -> i32 { - rustix::process::ksu_get_version() -} - -#[cfg(not(any(target_os = "linux", target_os = "android")))] -pub fn get_version() -> i32 { - 0 -} - -#[cfg(any(target_os = "linux", target_os = "android"))] -fn report_event(event: u64) { - rustix::process::ksu_report_event(event) -} - -#[cfg(not(any(target_os = "linux", target_os = "android")))] -fn report_event(_event: u64) {} - -#[cfg(any(target_os = "linux", target_os = "android"))] -pub fn check_kernel_safemode() -> bool { - rustix::process::ksu_check_kernel_safemode() -} - -#[cfg(not(any(target_os = "linux", target_os = "android")))] -pub fn check_kernel_safemode() -> bool { - false -} - -pub fn report_post_fs_data() { - report_event(EVENT_POST_FS_DATA); -} - -pub fn report_boot_complete() { - report_event(EVENT_BOOT_COMPLETED); -} - -pub fn report_module_mounted() { - report_event(EVENT_MODULE_MOUNTED); -} diff --git a/userspace/ksud/src/utils.rs b/userspace/ksud/src/utils.rs index 7e7a83ba8fa1..1c8d66bf5bca 100644 --- a/userspace/ksud/src/utils.rs +++ b/userspace/ksud/src/utils.rs @@ -5,7 +5,7 @@ use std::{ path::Path, }; -use crate::defs; +use crate::{assets, defs, ksucalls, restorecon}; use std::fs::metadata; #[allow(unused_imports)] use std::fs::{set_permissions, Permissions}; @@ -16,6 +16,7 @@ use hole_punch::*; use std::io::{Read, Seek, SeekFrom}; use jwalk::WalkDir; +use std::path::PathBuf; #[cfg(any(target_os = "linux", target_os = "android"))] use rustix::{ @@ -108,7 +109,7 @@ pub fn is_safe_mode() -> bool { if safemode { return true; } - let safemode = crate::ksu::check_kernel_safemode(); + let safemode = ksucalls::check_kernel_safemode(); log::info!("kernel_safemode: {}", safemode); safemode } @@ -193,6 +194,29 @@ pub fn get_tmp_path() -> &'static str { "" } +#[cfg(target_os = "android")] +fn link_ksud_to_bin() -> Result<()> { + let ksu_bin = PathBuf::from(defs::DAEMON_PATH); + let ksu_bin_link = PathBuf::from(defs::DAEMON_LINK_PATH); + if ksu_bin.exists() && !ksu_bin_link.exists() { + std::os::unix::fs::symlink(&ksu_bin, &ksu_bin_link)?; + } + Ok(()) +} + +pub fn install() -> Result<()> { + ensure_dir_exists(defs::ADB_DIR)?; + std::fs::copy("/proc/self/exe", defs::DAEMON_PATH)?; + restorecon::lsetfilecon(defs::DAEMON_PATH, restorecon::ADB_CON)?; + // install binary assets + assets::ensure_binaries(false).with_context(|| "Failed to extract assets")?; + + #[cfg(target_os = "android")] + link_ksud_to_bin()?; + + Ok(()) +} + // TODO: use libxcp to improve the speed if cross's MSRV is 1.70 pub fn copy_sparse_file, Q: AsRef>( src: P,