diff --git a/userspace/ksud/src/kpm.rs b/userspace/ksud/src/kpm.rs index 3a7acbf5..5c1f2b10 100644 --- a/userspace/ksud/src/kpm.rs +++ b/userspace/ksud/src/kpm.rs @@ -1,6 +1,3 @@ -use crate::ksucalls; -use anyhow::{Result, anyhow, bail}; -use notify::{RecursiveMode, Watcher}; use std::{ ffi::{CStr, CString, OsStr}, fs, @@ -8,19 +5,24 @@ use std::{ path::{Path, PathBuf}, }; +use anyhow::{Result, anyhow, bail}; +use notify::{RecursiveMode, Watcher}; + +use crate::ksucalls; + pub const KPM_DIR: &str = "/data/adb/kpm"; -const SUKISU_KPM_LOAD: u64 = 1; -const SUKISU_KPM_UNLOAD: u64 = 2; -const SUKISU_KPM_NUM: u64 = 3; -const SUKISU_KPM_LIST: u64 = 4; -const SUKISU_KPM_INFO: u64 = 5; -const SUKISU_KPM_CONTROL: u64 = 6; -const SUKISU_KPM_VERSION: u64 = 7; +const KPM_LOAD: u64 = 1; +const KPM_UNLOAD: u64 = 2; +const KPM_NUM: u64 = 3; +const KPM_LIST: u64 = 4; +const KPM_INFO: u64 = 5; +const KPM_CONTROL: u64 = 6; +const KPM_VERSION: u64 = 7; /// Convert raw kernel return code to `Result`. #[inline(always)] -fn check_out(rc: i32) -> Result { +fn check_ret(rc: i32) -> Result { if rc < 0 { bail!("KPM error: {}", std::io::Error::from_raw_os_error(-rc)); } @@ -34,14 +36,14 @@ pub fn kpm_load(path: &str, args: Option<&str>) -> Result<()> { let mut result: i32 = -1; let mut cmd = ksucalls::KsuKpmCmd { - arg2: SUKISU_KPM_LOAD, - arg3: path_c.as_ptr() as u64, - arg4: args_c.as_ref().map_or(0, |s| s.as_ptr() as u64), - arg5: &mut result as *mut i32 as u64, + control_code: KPM_LOAD, + arg1: path_c.as_ptr() as u64, + arg2: args_c.as_ref().map_or(0, |s| s.as_ptr() as u64), + result_code: &mut result as *mut i32 as u64, }; ksucalls::kpm_ioctl(&mut cmd)?; - check_out(result)?; + check_ret(result)?; println!("Success"); Ok(()) } @@ -52,14 +54,14 @@ pub fn kpm_unload(name: &str) -> Result<()> { let mut result: i32 = -1; let mut cmd = ksucalls::KsuKpmCmd { - arg2: SUKISU_KPM_UNLOAD, - arg3: name_c.as_ptr() as u64, - arg4: 0, - arg5: &mut result as *mut i32 as u64, + control_code: KPM_UNLOAD, + arg1: name_c.as_ptr() as u64, + arg2: 0, + result_code: &mut result as *mut i32 as u64, }; ksucalls::kpm_ioctl(&mut cmd)?; - check_out(result)?; + check_ret(result)?; Ok(()) } @@ -67,14 +69,14 @@ pub fn kpm_unload(name: &str) -> Result<()> { pub fn kpm_num() -> Result { let mut result: i32 = -1; let mut cmd = ksucalls::KsuKpmCmd { - arg2: SUKISU_KPM_NUM, - arg3: 0, - arg4: 0, - arg5: &mut result as *mut i32 as u64, + control_code: KPM_NUM, + arg1: 0, + arg2: 0, + result_code: &mut result as *mut i32 as u64, }; ksucalls::kpm_ioctl(&mut cmd)?; - let n = check_out(result)?; + let n = check_ret(result)?; println!("{n}"); Ok(n) } @@ -85,14 +87,14 @@ pub fn kpm_list() -> Result<()> { let mut result: i32 = -1; let mut cmd = ksucalls::KsuKpmCmd { - arg2: SUKISU_KPM_LIST, - arg3: buf.as_mut_ptr() as u64, - arg4: buf.len() as u64, - arg5: &mut result as *mut i32 as u64, + control_code: KPM_LIST, + arg1: buf.as_mut_ptr() as u64, + arg2: buf.len() as u64, + result_code: &mut result as *mut i32 as u64, }; ksucalls::kpm_ioctl(&mut cmd)?; - check_out(result)?; + check_ret(result)?; print!("{}", buf2str(&buf)); Ok(()) } @@ -104,14 +106,14 @@ pub fn kpm_info(name: &str) -> Result<()> { let mut result: i32 = -1; let mut cmd = ksucalls::KsuKpmCmd { - arg2: SUKISU_KPM_INFO, - arg3: name_c.as_ptr() as u64, - arg4: buf.as_mut_ptr() as u64, - arg5: &mut result as *mut i32 as u64, + control_code: KPM_INFO, + arg1: name_c.as_ptr() as u64, + arg2: buf.as_mut_ptr() as u64, + result_code: &mut result as *mut i32 as u64, }; ksucalls::kpm_ioctl(&mut cmd)?; - check_out(result)?; + check_ret(result)?; println!("{}", buf2str(&buf)); Ok(()) } @@ -123,14 +125,14 @@ pub fn kpm_control(name: &str, args: &str) -> Result { let mut result: i32 = -1; let mut cmd = ksucalls::KsuKpmCmd { - arg2: SUKISU_KPM_CONTROL, - arg3: name_c.as_ptr() as u64, - arg4: args_c.as_ptr() as u64, - arg5: &mut result as *mut i32 as u64, + control_code: KPM_CONTROL, + arg1: name_c.as_ptr() as u64, + arg2: args_c.as_ptr() as u64, + result_code: &mut result as *mut i32 as u64, }; ksucalls::kpm_ioctl(&mut cmd)?; - check_out(result) + check_ret(result) } /// Print loader version string. @@ -139,14 +141,14 @@ pub fn kpm_version_loader() -> Result<()> { let mut result: i32 = -1; let mut cmd = ksucalls::KsuKpmCmd { - arg2: SUKISU_KPM_VERSION, - arg3: buf.as_mut_ptr() as u64, - arg4: buf.len() as u64, - arg5: &mut result as *mut i32 as u64, + control_code: KPM_VERSION, + arg1: buf.as_mut_ptr() as u64, + arg2: buf.len() as u64, + result_code: &mut result as *mut i32 as u64, }; ksucalls::kpm_ioctl(&mut cmd)?; - check_out(result)?; + check_ret(result)?; print!("{}", buf2str(&buf)); Ok(()) } @@ -157,14 +159,14 @@ pub fn check_kpm_version() -> Result { let mut result: i32 = -1; let mut cmd = ksucalls::KsuKpmCmd { - arg2: SUKISU_KPM_VERSION, - arg3: buf.as_mut_ptr() as u64, - arg4: buf.len() as u64, - arg5: &mut result as *mut i32 as u64, + control_code: KPM_VERSION, + arg1: buf.as_mut_ptr() as u64, + arg2: buf.len() as u64, + result_code: &mut result as *mut i32 as u64, }; ksucalls::kpm_ioctl(&mut cmd)?; - check_out(result)?; + check_ret(result)?; let ver = buf2str(&buf); if ver.is_empty() { bail!("KPM: invalid version response: {ver}"); @@ -177,6 +179,7 @@ pub fn check_kpm_version() -> Result { pub fn ensure_kpm_dir() -> Result<()> { fs::create_dir_all(KPM_DIR)?; let meta = fs::metadata(KPM_DIR)?; + if meta.permissions().mode() & 0o777 != 0o777 { fs::set_permissions(KPM_DIR, fs::Permissions::from_mode(0o777))?; } @@ -187,6 +190,7 @@ pub fn ensure_kpm_dir() -> Result<()> { pub fn start_kpm_watcher() -> Result<()> { check_kpm_version()?; // bails if loader too old ensure_kpm_dir()?; + if crate::utils::is_safe_mode() { log::warn!("KPM: safe-mode – removing all modules"); remove_all_kpms()?; @@ -205,7 +209,10 @@ pub fn start_kpm_watcher() -> Result<()> { fn handle_kpm_event(evt: notify::Event) { if let notify::EventKind::Create(_) = evt.kind { for p in evt.paths { - if p.extension() == Some(OsStr::new("kpm")) && load_kpm(&p).is_err() { + if let Some(ex) = p.extension() + && ex == OsStr::new("kpm") + && load_kpm(&p).is_err() + { log::warn!("KPM: failed to load {}", p.display()); } } @@ -221,22 +228,30 @@ pub fn load_kpm(path: &Path) -> Result<()> { /// Unload module and delete file. pub fn unload_kpm(name: &str) -> Result<()> { kpm_unload(name)?; + if let Some(p) = find_kpm_file(name)? { let _ = fs::remove_file(&p); log::info!("KPM: deleted {}", p.display()); } + Ok(()) } /// Locate `/data/adb/kpm/.kpm`. fn find_kpm_file(name: &str) -> Result> { let dir = Path::new(KPM_DIR); + if !dir.is_dir() { return Ok(None); } + for entry in fs::read_dir(dir)? { let p = entry?.path(); - if p.extension() == Some(OsStr::new("kpm")) && p.file_stem() == Some(OsStr::new(name)) { + if let Some(ex) = p.extension() + && ex == OsStr::new("kpm") + && let Some(fs) = p.file_stem() + && fs == OsStr::new(name) + { return Ok(Some(p)); } } @@ -251,7 +266,8 @@ pub fn remove_all_kpms() -> Result<()> { } for entry in fs::read_dir(dir)? { let p = entry?.path(); - if p.extension() == Some(OsStr::new("kpm")) + if let Some(ex) = p.extension() + && ex == OsStr::new("kpm") && let Some(name) = p.file_stem().and_then(|s| s.to_str()) && let Err(e) = unload_kpm(name) { @@ -265,14 +281,19 @@ pub fn remove_all_kpms() -> Result<()> { pub fn load_kpm_modules() -> Result<()> { check_kpm_version()?; ensure_kpm_dir()?; + let dir = Path::new(KPM_DIR); if !dir.is_dir() { return Ok(()); } + let (mut ok, mut ng) = (0, 0); + for entry in fs::read_dir(dir)? { let p = entry?.path(); - if p.extension() == Some(OsStr::new("kpm")) { + if let Some(ex) = p.extension() + && ex == OsStr::new("kpm") + { match load_kpm(&p) { Ok(_) => ok += 1, Err(e) => { diff --git a/userspace/ksud/src/ksucalls.rs b/userspace/ksud/src/ksucalls.rs index 82a2c712..eaaf6475 100644 --- a/userspace/ksud/src/ksucalls.rs +++ b/userspace/ksud/src/ksucalls.rs @@ -243,10 +243,10 @@ pub fn proxy_file(fd: RawFd) -> std::io::Result { #[derive(Clone, Copy, Default)] #[allow(dead_code)] pub struct KsuKpmCmd { + pub control_code: u64, + pub arg1: u64, pub arg2: u64, - pub arg3: u64, - pub arg4: u64, - pub arg5: u64, + pub result_code: u64, } #[allow(dead_code)] diff --git a/userspace/ksud/src/su.rs b/userspace/ksud/src/su.rs index 34924788..33b60623 100644 --- a/userspace/ksud/src/su.rs +++ b/userspace/ksud/src/su.rs @@ -1,7 +1,7 @@ use crate::{ + defs, ksucalls::proxy_file, utils::{self, umask}, - defs, }; use anyhow::{Context, Ok, Result, bail}; use getopts::Options; diff --git a/userspace/ksud/src/uid_scanner.rs b/userspace/ksud/src/uid_scanner.rs index fa2b7eba..64be9d99 100644 --- a/userspace/ksud/src/uid_scanner.rs +++ b/userspace/ksud/src/uid_scanner.rs @@ -5,21 +5,20 @@ use std::{ fs::{PermissionsExt, symlink}, process::CommandExt, }, - path::Path, process::{Command, Stdio}, }; use anyhow::Result; use log::{info, warn}; -pub fn start_uid_scanner_daemon() -> Result<()> { - const SCANNER_PATH: &str = "/data/adb/uid_scanner"; - const LINK_DIR: &str = "/data/adb/ksu/bin"; - const LINK_PATH: &str = "/data/adb/ksu/bin/uid_scanner"; - const SERVICE_DIR: &str = "/data/adb/service.d"; - const SERVICE_PATH: &str = "/data/adb/service.d/uid_scanner.sh"; +const SCANNER_PATH: &str = "/data/adb/uid_scanner"; +const LINK_DIR: &str = "/data/adb/ksu/bin"; +const LINK_PATH: &str = "/data/adb/ksu/bin/uid_scanner"; +const SERVICE_DIR: &str = "/data/adb/service.d"; +const SERVICE_PATH: &str = "/data/adb/service.d/uid_scanner.sh"; - if !Path::new(SCANNER_PATH).exists() { +pub fn start_uid_scanner_daemon() -> Result<()> { + if !fs::exists(SCANNER_PATH)? { warn!("uid scanner binary not found at {}", SCANNER_PATH); return Ok(()); } @@ -32,7 +31,7 @@ pub fn start_uid_scanner_daemon() -> Result<()> { { if let Err(e) = fs::create_dir_all(LINK_DIR) { warn!("failed to create {}: {}", LINK_DIR, e); - } else if !Path::new(LINK_PATH).exists() { + } else if !fs::exists(LINK_PATH)? { match symlink(SCANNER_PATH, LINK_PATH) { Ok(_) => info!("created symlink {} -> {}", SCANNER_PATH, LINK_PATH), Err(e) => warn!("failed to create symlink: {}", e), @@ -42,13 +41,11 @@ pub fn start_uid_scanner_daemon() -> Result<()> { if let Err(e) = fs::create_dir_all(SERVICE_DIR) { warn!("failed to create {}: {}", SERVICE_DIR, e); - } else if !Path::new(SERVICE_PATH).exists() { - let content = r#"#!/system/bin/sh -# KSU uid_scanner auto-restart script -until [ -d "/sdcard/Android" ]; do sleep 1; done -sleep 10 -/data/adb/uid_scanner restart -"#; + } + + if !fs::exists(SERVICE_PATH)? { + let content = include_str!("uid_scanner.sh"); + match fs::OpenOptions::new() .write(true) .create_new(true) diff --git a/userspace/ksud/src/uid_scanner.sh b/userspace/ksud/src/uid_scanner.sh new file mode 100644 index 00000000..6c7000e3 --- /dev/null +++ b/userspace/ksud/src/uid_scanner.sh @@ -0,0 +1,5 @@ +#!/system/bin/sh +# KSU uid_scanner auto-restart script +until [ -d "/sdcard/Android" ]; do sleep 1; done +sleep 10 +/data/adb/uid_scanner restart \ No newline at end of file