From bf4e12ce80e036946ee0b487f1b61e62f844994f Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 23 Sep 2025 20:37:40 +0800 Subject: [PATCH] ksud: Modified KPM to use the prctl system call instead of external execution. --- userspace/ksud/src/init_event.rs | 13 +- userspace/ksud/src/kpm.rs | 206 ++++++++++++++++++++++++------- 2 files changed, 169 insertions(+), 50 deletions(-) diff --git a/userspace/ksud/src/init_event.rs b/userspace/ksud/src/init_event.rs index 4d4a5c4e..26a278dd 100644 --- a/userspace/ksud/src/init_event.rs +++ b/userspace/ksud/src/init_event.rs @@ -9,8 +9,6 @@ use std::path::Path; pub fn on_post_data_fs() -> Result<()> { ksucalls::report_post_fs_data(); - kpm::start_kpm_watcher()?; - utils::umask(0); #[cfg(unix)] @@ -72,6 +70,14 @@ pub fn on_post_data_fs() -> Result<()> { warn!("apply root profile sepolicy failed: {e}"); } + if let Err(e) = kpm::start_kpm_watcher() { + warn!("KPM: Failed to start KPM watcher: {}", e); + } + + if let Err(e) = kpm::load_kpm_modules() { + warn!("KPM: Failed to load KPM modules: {}", e); + } + // mount temp dir if !Path::new(NO_TMPFS_PATH).exists() { if let Err(e) = mount( @@ -109,9 +115,6 @@ pub fn on_post_data_fs() -> Result<()> { run_stage("post-mount", true); - // load kpm modules - kpm::load_kpm_modules()?; - Ok(()) } diff --git a/userspace/ksud/src/kpm.rs b/userspace/ksud/src/kpm.rs index 7a8c80a9..fba0b188 100644 --- a/userspace/ksud/src/kpm.rs +++ b/userspace/ksud/src/kpm.rs @@ -1,39 +1,95 @@ -use anyhow::Result; -use anyhow::anyhow; +use anyhow::{anyhow, Result}; +use libc::{prctl, c_char, c_void, c_int}; use notify::{RecursiveMode, Watcher}; -use std::ffi::OsStr; +use std::ffi::{CStr, CString, OsStr}; use std::fs; use std::path::Path; +use std::ptr; +use std::os::unix::fs::PermissionsExt; pub const KPM_DIR: &str = "/data/adb/kpm"; -pub const KPMMGR_PATH: &str = "/data/adb/ksu/bin/kpmmgr"; -// 确保 KPM 目录存在,如果不存在则创建 +const KSU_OPTIONS: u32 = 0xdeadbeef; +const SUKISU_KPM_LOAD: i32 = 28; +const SUKISU_KPM_UNLOAD: i32 = 29; +const SUKISU_KPM_VERSION: i32 = 34; + +pub fn check_kpm_version() -> Result { + let mut buffer: [u8; 1024] = [0; 1024]; + let mut out: c_int = -1; + + let _ret = unsafe { + prctl( + KSU_OPTIONS as c_int, + SUKISU_KPM_VERSION, + buffer.as_mut_ptr() as *mut c_void, + buffer.len() as *mut c_void, + &mut out as *mut c_int as *mut c_void, + ) + }; + + if out < 0 { + return Err(anyhow!("KPM: prctl returned error: {}", out)); + } + + let version_str = unsafe { + CStr::from_ptr(buffer.as_ptr() as *const c_char) + }.to_string_lossy().to_string(); + + log::info!("KPM: Version check result: {}", version_str); + + // 检查版本是否有效(不为空且不以Error开头) + if version_str.is_empty() || version_str.starts_with("Error") { + return Err(anyhow!("KPM: Invalid version response: {}", version_str)); + } + + Ok(version_str) +} + +// 确保 KPM 目录存在,并设置777权限 pub fn ensure_kpm_dir() -> Result<()> { - if !Path::new(KPM_DIR).exists() { - fs::create_dir_all(KPM_DIR)?; + let path = Path::new(KPM_DIR); + + if path.exists() { + let meta = fs::metadata(path)?; + let current = meta.permissions().mode() & 0o777; + if current != 0o777 { + log::info!("KPM: Fixing permissions to 777 for {}", KPM_DIR); + fs::set_permissions(path, fs::Permissions::from_mode(0o777))?; + } } Ok(()) } pub fn start_kpm_watcher() -> Result<()> { + match check_kpm_version() { + Ok(version) => { + log::info!("KPM: Version check passed, version: {}", version); + } + Err(e) => { + log::warn!("KPM: Version check failed, skipping KPM functionality: {}", e); + return Ok(()) + } + } + ensure_kpm_dir()?; // 检查是否处于安全模式 if crate::utils::is_safe_mode() { - log::warn!("The system is in safe mode and is deleting all KPM modules..."); + log::warn!("KPM: System is in safe mode, removing all KPM modules"); if let Err(e) = remove_all_kpms() { - log::error!("Error deleting all KPM modules: {}", e); + log::error!("KPM: Error removing all KPM modules: {}", e); } return Ok(()); } let mut watcher = notify::recommended_watcher(|res| match res { Ok(event) => handle_kpm_event(event), - Err(e) => log::error!("monitoring error: {:?}", e), + Err(e) => log::error!("KPM: File monitoring error: {:?}", e), })?; watcher.watch(Path::new(KPM_DIR), RecursiveMode::NonRecursive)?; + log::info!("KPM: Started file watcher for directory: {}", KPM_DIR); Ok(()) } @@ -50,8 +106,9 @@ pub fn handle_kpm_event(event: notify::Event) { fn handle_create_event(paths: Vec) { for path in paths { if path.extension() == Some(OsStr::new("kpm")) { + log::info!("KPM: Detected new KPM file: {}", path.display()); if let Err(e) = load_kpm(&path) { - log::warn!("Failed to load {}: {}", path.display(), e); + log::warn!("KPM: Failed to load {}: {}", path.display(), e); } } } @@ -60,11 +117,9 @@ fn handle_create_event(paths: Vec) { fn handle_remove_event(paths: Vec) { for path in paths { if let Some(name) = path.file_stem().and_then(|s| s.to_str()) { + log::info!("KPM: Detected KPM file removal: {}", name); if let Err(e) = unload_kpm(name) { - log::warn!("Failed to unload {}: {}", name, e); - } - if let Err(e) = fs::remove_file(&path) { - log::error!("Failed to delete file: {}: {}", path.display(), e); + log::warn!("KPM: Failed to unload {}: {}", name, e); } } } @@ -72,7 +127,7 @@ fn handle_remove_event(paths: Vec) { fn handle_modify_event(paths: Vec) { for path in paths { - log::info!("Modified file: {}", path.display()); + log::info!("KPM: Modified file detected: {}", path.display()); } } @@ -80,37 +135,66 @@ fn handle_modify_event(paths: Vec) { pub fn load_kpm(path: &Path) -> Result<()> { let path_str = path .to_str() - .ok_or_else(|| anyhow!("Invalid path: {}", path.display()))?; - let status = std::process::Command::new(KPMMGR_PATH) - .args(["load", path_str, ""]) - .status()?; + .ok_or_else(|| anyhow!("KPM: Invalid path: {}", path.display()))?; + + let path_cstring = CString::new(path_str) + .map_err(|e| anyhow!("KPM: Failed to convert path to CString: {}", e))?; + + let mut out: c_int = -1; - if status.success() { - log::info!("Loaded KPM: {}", path.display()); + let _ret = unsafe { + prctl( + KSU_OPTIONS as c_int, + SUKISU_KPM_LOAD, + path_cstring.as_ptr() as *mut c_void, + ptr::null_mut::(), + &mut out as *mut c_int as *mut c_void, + ) + }; + + if out < 0 { + return Err(anyhow!("KPM: prctl returned error: {}", out)); } + + if out > 0 { + log::info!("KPM: Successfully loaded module: {}", path.display()); + } + Ok(()) } -// 卸载 KPM 模块并尝试删除对应文件 +// 卸载 KPM 模块 pub fn unload_kpm(name: &str) -> Result<()> { - let status = std::process::Command::new(KPMMGR_PATH) - .args(["unload", name]) - .status() - .map_err(|e| anyhow!("Failed to execute kpmmgr: {}", e))?; + let name_cstring = CString::new(name) + .map_err(|e| anyhow!("KPM: Failed to convert name to CString: {}", e))?; - if status.success() { - let kpm_path = find_kpm_file(name)?; - if let Some(path) = kpm_path { - fs::remove_file(&path) - .map_err(|e| anyhow!("Failed to delete KPM file: {}: {}", path.display(), e))?; - log::info!("Deleted KPM file: {}", path.display()); - } + let mut out: c_int = -1; - log::info!("Successfully unloaded KPM: {}", name); - } else { - log::warn!("KPM unloading may have failed: {}", name); + let _ret = unsafe { + prctl( + KSU_OPTIONS as c_int, + SUKISU_KPM_UNLOAD, + name_cstring.as_ptr() as *mut c_void, + ptr::null_mut::(), + &mut out as *mut c_int as *mut c_void, + ) + }; + + if out < 0 { + log::warn!("KPM: prctl returned error for unload: {}", out); + return Err(anyhow!("KPM: prctl returned error: {}", out)); } + // 尝试删除对应的KPM文件 + if let Ok(Some(path)) = find_kpm_file(name) { + if let Err(e) = fs::remove_file(&path) { + log::warn!("KPM: Failed to delete KPM file {}: {}", path.display(), e); + } else { + log::info!("KPM: Deleted KPM file: {}", path.display()); + } + } + + log::info!("KPM: Successfully unloaded module: {}", name); Ok(()) } @@ -136,17 +220,23 @@ fn find_kpm_file(name: &str) -> Result> { // 安全模式下删除所有 KPM 模块 pub fn remove_all_kpms() -> Result<()> { - ensure_kpm_dir()?; + let kpm_dir = Path::new(KPM_DIR); + if !kpm_dir.exists() { + log::info!("KPM: KPM directory does not exist, nothing to remove"); + return Ok(()); + } for entry in fs::read_dir(KPM_DIR)? { let path = entry?.path(); if path.extension().is_some_and(|ext| ext == "kpm") { if let Some(name) = path.file_stem() { - if let Err(e) = unload_kpm(name.to_string_lossy().as_ref()) { - log::error!("Failed to remove KPM: {}", e); + let name_str = name.to_string_lossy(); + log::info!("KPM: Removing module in safe mode: {}", name_str); + if let Err(e) = unload_kpm(&name_str) { + log::error!("KPM: Failed to remove module {}: {}", name_str, e); } if let Err(e) = fs::remove_file(&path) { - log::error!("Failed to delete file: {}: {}", path.display(), e); + log::error!("KPM: Failed to delete file {}: {}", path.display(), e); } } } @@ -154,27 +244,53 @@ pub fn remove_all_kpms() -> Result<()> { Ok(()) } -// 加载 KPM 模块 +// 加载所有 KPM 模块 pub fn load_kpm_modules() -> Result<()> { + match check_kpm_version() { + Ok(version) => { + log::info!("KPM: Version check passed before loading modules, version: {}", version); + } + Err(e) => { + log::warn!("KPM: Version check failed, skipping module loading: {}", e); + return Ok(()); + } + } + ensure_kpm_dir()?; + let kpm_dir = Path::new(KPM_DIR); + if !kpm_dir.exists() { + log::info!("KPM: KPM directory does not exist, no modules to load"); + return Ok(()); + } + + let mut loaded_count = 0; + let mut failed_count = 0; + for entry in std::fs::read_dir(KPM_DIR)? { let path = entry?.path(); if let Some(file_name) = path.file_stem() { if let Some(file_name_str) = file_name.to_str() { if file_name_str.is_empty() { - log::warn!("Invalid KPM file name: {}", path.display()); + log::warn!("KPM: Invalid KPM file name: {}", path.display()); continue; } } } if path.extension().is_some_and(|ext| ext == "kpm") { match load_kpm(&path) { - Ok(()) => log::info!("Successfully loaded KPM module: {}", path.display()), - Err(e) => log::warn!("Failed to load KPM module {}: {}", path.display(), e), + Ok(()) => { + log::info!("KPM: Successfully loaded module: {}", path.display()); + loaded_count += 1; + } + Err(e) => { + log::warn!("KPM: Failed to load module {}: {}", path.display(), e); + failed_count += 1; + } } } } + log::info!("KPM: Module loading completed - loaded: {}, failed: {}", loaded_count, failed_count); Ok(()) }