diff --git a/kernel/allowlist.c b/kernel/allowlist.c index 23a041ce..1cf5ab2a 100644 --- a/kernel/allowlist.c +++ b/kernel/allowlist.c @@ -21,7 +21,7 @@ struct perm_data { static struct list_head allow_list; -#define KERNEL_SU_ALLOWLIST "/data/adb/.ksu_allowlist" +#define KERNEL_SU_ALLOWLIST "/data/adb/ksu/.allowlist" static struct work_struct ksu_save_work; static struct work_struct ksu_load_work; @@ -159,7 +159,7 @@ void do_load_allow_list(struct work_struct *work) u32 magic; u32 version; - fp = filp_open("/data/adb/", O_RDONLY, 0); + fp = filp_open("/data/adb", O_RDONLY, 0); if (IS_ERR(fp)) { int errno = PTR_ERR(fp); pr_err("load_allow_list open '/data/adb': %d\n", PTR_ERR(fp)); diff --git a/kernel/ksud.c b/kernel/ksud.c index 9a3a2258..fe6efc2f 100644 --- a/kernel/ksud.c +++ b/kernel/ksud.c @@ -13,6 +13,7 @@ #include "allowlist.h" #include "arch.h" #include "klog.h" // IWYU pragma: keep +#include "ksud.h" #include "selinux/selinux.h" static const char KERNEL_SU_RC[] = @@ -20,19 +21,19 @@ static const char KERNEL_SU_RC[] = "on post-fs-data\n" // We should wait for the post-fs-data finish - " exec u:r:su:s0 root -- /data/adb/ksud post-fs-data\n" + " exec u:r:su:s0 root -- "KSUD_PATH" post-fs-data\n" "\n" "on nonencrypted\n" - " exec u:r:su:s0 root -- /data/adb/ksud services\n" + " exec u:r:su:s0 root -- "KSUD_PATH" services\n" "\n" "on property:vold.decrypt=trigger_restart_framework\n" - " exec u:r:su:s0 root -- /data/adb/ksud services\n" + " exec u:r:su:s0 root -- "KSUD_PATH" services\n" "\n" "on property:sys.boot_completed=1\n" - " exec u:r:su:s0 root -- /data/adb/ksud boot-completed\n" + " exec u:r:su:s0 root -- "KSUD_PATH" boot-completed\n" "\n" "\n"; diff --git a/kernel/ksud.h b/kernel/ksud.h index 99423c58..c8821486 100644 --- a/kernel/ksud.h +++ b/kernel/ksud.h @@ -1,6 +1,8 @@ #ifndef __KSU_H_KSUD #define __KSU_H_KSUD +#define KSUD_PATH "/data/adb/ksud" + void on_post_fs_data(void); #endif \ No newline at end of file diff --git a/kernel/selinux/rules.c b/kernel/selinux/rules.c index ffc1e2a8..959d7288 100644 --- a/kernel/selinux/rules.c +++ b/kernel/selinux/rules.c @@ -59,7 +59,7 @@ void apply_kernelsu_rules() ksu_allowxperm(db, KERNEL_SU_DOMAIN, ALL, "chr_file", ALL); } - // we need to save allowlist in /data/adb + // we need to save allowlist in /data/adb/ksu ksu_allow(db, "kernel", "adb_data_file", "dir", ALL); ksu_allow(db, "kernel", "adb_data_file", "file", ALL); // we may need to do mount on shell diff --git a/userspace/ksud/bin/aarch64/busybox b/userspace/ksud/bin/aarch64/busybox new file mode 100755 index 00000000..61b2ec16 Binary files /dev/null and b/userspace/ksud/bin/aarch64/busybox differ diff --git a/userspace/ksud/bin/aarch64/resetprop b/userspace/ksud/bin/aarch64/resetprop new file mode 100644 index 00000000..b667d2ea Binary files /dev/null and b/userspace/ksud/bin/aarch64/resetprop differ diff --git a/userspace/ksud/bin/x86_64/busybox b/userspace/ksud/bin/x86_64/busybox new file mode 100644 index 00000000..87a4d95f Binary files /dev/null and b/userspace/ksud/bin/x86_64/busybox differ diff --git a/userspace/ksud/bin/x86_64/resetprop b/userspace/ksud/bin/x86_64/resetprop new file mode 100644 index 00000000..0997f251 Binary files /dev/null and b/userspace/ksud/bin/x86_64/resetprop differ diff --git a/userspace/ksud/src/defs.rs b/userspace/ksud/src/defs.rs index 37b9f883..9293a114 100644 --- a/userspace/ksud/src/defs.rs +++ b/userspace/ksud/src/defs.rs @@ -1,7 +1,11 @@ use const_format::concatcp; -pub const DAEMON_PATH: &str = "/data/adb/ksud"; -pub const WORKING_DIR: &str = "/data/adb/ksu/"; +pub const ADB_DIR: &str = "/data/adb/"; + +pub const DAEMON_PATH: &str = concatcp!(ADB_DIR, "ksud"); + +pub const WORKING_DIR: &str = concatcp!(ADB_DIR, "ksu/"); +pub const BINARY_DIR: &str = concatcp!(WORKING_DIR, "bin/"); pub const MODULE_DIR: &str = concatcp!(WORKING_DIR, "modules/"); pub const MODULE_IMG: &str = concatcp!(WORKING_DIR, "modules.img"); diff --git a/userspace/ksud/src/event.rs b/userspace/ksud/src/event.rs index 01b3a270..b5c43b7e 100644 --- a/userspace/ksud/src/event.rs +++ b/userspace/ksud/src/event.rs @@ -2,7 +2,7 @@ use std::{collections::HashMap, path::Path}; use crate::{ defs, - utils::{ensure_clean_dir, mount_image}, + utils::{ensure_clean_dir, ensure_dir_exists, mount_image}, }; use anyhow::{bail, Result}; use sys_mount::{FilesystemType, Mount, MountFlags}; @@ -176,9 +176,8 @@ pub fn daemon() -> Result<()> { } pub fn install() -> Result<()> { - let src = "/proc/self/exe"; - let dst = defs::DAEMON_PATH; - - std::fs::copy(src, dst)?; - Ok(()) + ensure_dir_exists(defs::ADB_DIR)?; + std::fs::copy("/proc/self/exe", defs::DAEMON_PATH) + .map(|_| ()) + .map_err(anyhow::Error::from) } diff --git a/userspace/ksud/src/module.rs b/userspace/ksud/src/module.rs index 0d5836b0..dd1d93b3 100644 --- a/userspace/ksud/src/module.rs +++ b/userspace/ksud/src/module.rs @@ -1,14 +1,19 @@ -use crate::{defs, restorecon, sepolicy}; -use crate::{restorecon::setsyscon, utils::*}; +use crate::{ + defs, + restorecon::{restore_syscon, setsyscon}, + sepolicy, + utils::*, +}; use const_format::concatcp; use java_properties::PropertiesIter; use log::{info, warn}; use std::{ collections::HashMap, - fs::{create_dir_all, remove_dir_all, File, OpenOptions}, + env::var as env_var, + fs::{remove_dir_all, File, OpenOptions}, io::{Cursor, Read, Write}, - os::unix::{prelude::PermissionsExt, process::CommandExt}, + os::unix::process::CommandExt, path::{Path, PathBuf}, process::{Command, Stdio}, str::FromStr, @@ -27,6 +32,10 @@ fn exec_install_script(module_file: &str) -> Result<()> { let result = Command::new("sh") .args(["-c", INSTALL_MODULE_SCRIPT]) + .env( + "PATH", + format!("{}:{}", env_var("PATH").unwrap(), defs::MODULE_DIR), + ) .env("OUTFD", "1") .env("ZIPFILE", realpath) .stderr(Stdio::null()) @@ -48,30 +57,19 @@ fn ensure_boot_completed() -> Result<()> { } fn mark_update() -> Result<()> { - let update_file = Path::new(defs::WORKING_DIR).join(defs::UPDATE_FILE_NAME); - if update_file.exists() { - return Ok(()); - } - - std::fs::File::create(update_file)?; - Ok(()) + ensure_file_exists(concatcp!(defs::WORKING_DIR, defs::UPDATE_FILE_NAME)) } fn mark_module_state(module: &str, flag_file: &str, create_or_delete: bool) -> Result<()> { let module_state_file = Path::new(defs::MODULE_DIR).join(module).join(flag_file); if create_or_delete { - if module_state_file.exists() { - return Ok(()); - } - std::fs::File::create(module_state_file)?; + ensure_file_exists(module_state_file) } else { - if !module_state_file.exists() { - return Ok(()); + if module_state_file.exists() { + std::fs::remove_file(module_state_file)?; } - std::fs::remove_file(module_state_file)?; + Ok(()) } - - Ok(()) } fn get_minimal_image_size(img: &str) -> Result { @@ -84,8 +82,8 @@ fn get_minimal_image_size(img: &str) -> Result { println!("- {}", output.trim()); let regex = regex::Regex::new(r"filesystem: (\d+)")?; let result = regex - .captures(output.as_ref()) - .ok_or_else(|| anyhow::anyhow!("regex not match"))?; + .captures(&output) + .ok_or(anyhow::anyhow!("regex not match"))?; let result = &result[1]; let result = u64::from_str(result)?; Ok(result) @@ -161,7 +159,7 @@ fn switch_cgroups() { } fn is_executable(path: &Path) -> bool { - let mut buffer: [u8; 2] = [0; 2]; + let mut buffer = [0u8; 2]; is_executable::is_executable(path) && File::open(path).unwrap().read_exact(&mut buffer).is_ok() && ( @@ -227,6 +225,10 @@ pub fn exec_post_fs_data() -> Result<()> { command = command .process_group(0) .current_dir(path) + .env( + "PATH", + format!("{}:{}", env_var("PATH").unwrap(), defs::MODULE_DIR), + ) .env("KSU", "true"); unsafe { command = command.pre_exec(|| { @@ -273,6 +275,10 @@ pub fn exec_services() -> Result<()> { command = command .process_group(0) .current_dir(path) + .env( + "PATH", + format!("{}:{}", env_var("PATH").unwrap(), defs::MODULE_DIR), + ) .env("KSU", "true"); unsafe { command = command.pre_exec(|| { @@ -289,20 +295,21 @@ pub fn exec_services() -> Result<()> { Ok(()) } -const RESETPROP: &[u8] = include_bytes!("./resetprop"); -const RESETPROP_PATH: &str = concatcp!(defs::WORKING_DIR, "/resetprop"); +const RESETPROP_PATH: &str = concatcp!(defs::BINARY_DIR, "resetprop"); +#[cfg(target_arch = "aarch64")] +const RESETPROP: &[u8] = include_bytes!("../bin/aarch64/resetprop"); +#[cfg(target_arch = "x86_64")] +const RESETPROP: &[u8] = include_bytes!("../bin/x86_64/resetprop"); -fn ensure_resetprop() -> Result<()> { - if Path::new(RESETPROP_PATH).exists() { - return Ok(()); - } - std::fs::write(RESETPROP_PATH, RESETPROP)?; - std::fs::set_permissions(RESETPROP_PATH, std::fs::Permissions::from_mode(0o755))?; - Ok(()) -} +const BUSYBOX_PATH: &str = concatcp!(defs::BINARY_DIR, "busybox"); +#[cfg(target_arch = "aarch64")] +const BUSYBOX: &[u8] = include_bytes!("../bin/aarch64/busybox"); +#[cfg(target_arch = "x86_64")] +const BUSYBOX: &[u8] = include_bytes!("../bin/x86_64/busybox"); pub fn load_system_prop() -> Result<()> { - ensure_resetprop()?; + ensure_binary(RESETPROP_PATH, RESETPROP)?; + ensure_binary(BUSYBOX_PATH, BUSYBOX)?; let modules_dir = Path::new(defs::MODULE_DIR); let dir = std::fs::read_dir(modules_dir)?; @@ -339,15 +346,8 @@ pub fn install_module(zip: String) -> Result<()> { println!(include_str!("banner")); // first check if workding dir is usable - let working_dir = Path::new(defs::WORKING_DIR); - if !working_dir.exists() { - create_dir_all(working_dir)?; - } - - ensure!( - working_dir.is_dir(), - "working dir exists but it is not a regular directory!" - ); + ensure_dir_exists(defs::WORKING_DIR)?; + ensure_dir_exists(defs::BINARY_DIR)?; // read the module_id from zip, if faild if will return early. let mut buffer: Vec = Vec::new(); @@ -460,8 +460,8 @@ pub fn install_module(zip: String) -> Result<()> { module_system_dir.push("system"); let module_system_dir = module_system_dir.as_path(); if module_system_dir.exists() { - let path = format!("{}", module_system_dir.display()); - restorecon::restore_syscon(&path)?; + let path = module_system_dir.to_str().unwrap(); + restore_syscon(&path)?; } exec_install_script(&zip) @@ -589,8 +589,8 @@ fn do_enable_module(module_dir: &str, mid: &str, enable: bool) -> Result<()> { format!("Failed to remove disable file: {}", &disable_path.display()) })?; } - } else if !disable_path.exists() { - std::fs::File::create(disable_path)?; + } else { + ensure_file_exists(disable_path)?; } let _ = mark_module_state(mid, defs::DISABLE_FILE_NAME, !enable); diff --git a/userspace/ksud/src/resetprop b/userspace/ksud/src/resetprop deleted file mode 100755 index 6be6c10e..00000000 Binary files a/userspace/ksud/src/resetprop and /dev/null differ diff --git a/userspace/ksud/src/utils.rs b/userspace/ksud/src/utils.rs index 09270f18..d749557d 100644 --- a/userspace/ksud/src/utils.rs +++ b/userspace/ksud/src/utils.rs @@ -1,7 +1,11 @@ -use std::path::Path; - -use anyhow::{ensure, Context, Result}; +use anyhow::{bail, ensure, Context, Error, Ok, Result}; use retry::delay::NoDelay; +use std::{ + fs::{create_dir_all, set_permissions, write, File, Permissions}, + io::ErrorKind::AlreadyExists, + os::unix::prelude::PermissionsExt, + path::Path, +}; use sys_mount::{unmount, FilesystemType, Mount, UnmountFlags}; fn do_mount_image(src: &str, target: &str) -> Result<()> { @@ -33,6 +37,52 @@ pub fn ensure_clean_dir(dir: &str) -> Result<()> { Ok(std::fs::create_dir_all(path)?) } +pub fn ensure_file_exists>(file: T) -> Result<()> { + match File::options().write(true).create_new(true).open(&file) { + std::result::Result::Ok(_) => Ok(()), + Err(err) => { + if err.kind() == AlreadyExists && file.as_ref().is_file() { + Ok(()) + } else { + Err(Error::from(err)).with_context(|| { + format!("{} is not a regular file", file.as_ref().to_str().unwrap()) + }) + } + } + } +} + +pub fn ensure_dir_exists>(dir: T) -> Result<()> { + let result = create_dir_all(&dir).map_err(Error::from); + if dir.as_ref().is_dir() { + result + } else if result.is_ok() { + bail!( + "{} is not a regular directory", + dir.as_ref().to_str().unwrap() + ) + } else { + result + } +} + +pub fn ensure_binary>(path: T, contents: &[u8]) -> Result<()> { + if path.as_ref().exists() { + return Ok(()); + } + + ensure_dir_exists(path.as_ref().parent().ok_or_else(|| { + anyhow::anyhow!( + "{} does not have parent directory", + path.as_ref().to_string_lossy() + ) + })?)?; + + write(&path, contents)?; + set_permissions(&path, Permissions::from_mode(0o755))?; + Ok(()) +} + pub fn getprop(prop: &str) -> Option { android_properties::getprop(prop).value() }