ksud: Modified KPM to use the prctl system call instead of external execution.

This commit is contained in:
ShirkNeko
2025-09-23 20:37:40 +08:00
parent 5497c0004d
commit bf4e12ce80
2 changed files with 169 additions and 50 deletions

View File

@@ -9,8 +9,6 @@ use std::path::Path;
pub fn on_post_data_fs() -> Result<()> { pub fn on_post_data_fs() -> Result<()> {
ksucalls::report_post_fs_data(); ksucalls::report_post_fs_data();
kpm::start_kpm_watcher()?;
utils::umask(0); utils::umask(0);
#[cfg(unix)] #[cfg(unix)]
@@ -72,6 +70,14 @@ pub fn on_post_data_fs() -> Result<()> {
warn!("apply root profile sepolicy failed: {e}"); 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 // mount temp dir
if !Path::new(NO_TMPFS_PATH).exists() { if !Path::new(NO_TMPFS_PATH).exists() {
if let Err(e) = mount( if let Err(e) = mount(
@@ -109,9 +115,6 @@ pub fn on_post_data_fs() -> Result<()> {
run_stage("post-mount", true); run_stage("post-mount", true);
// load kpm modules
kpm::load_kpm_modules()?;
Ok(()) Ok(())
} }

View File

@@ -1,39 +1,95 @@
use anyhow::Result; use anyhow::{anyhow, Result};
use anyhow::anyhow; use libc::{prctl, c_char, c_void, c_int};
use notify::{RecursiveMode, Watcher}; use notify::{RecursiveMode, Watcher};
use std::ffi::OsStr; use std::ffi::{CStr, CString, OsStr};
use std::fs; use std::fs;
use std::path::Path; use std::path::Path;
use std::ptr;
use std::os::unix::fs::PermissionsExt;
pub const KPM_DIR: &str = "/data/adb/kpm"; 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<String> {
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<()> { pub fn ensure_kpm_dir() -> Result<()> {
if !Path::new(KPM_DIR).exists() { let path = Path::new(KPM_DIR);
fs::create_dir_all(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(()) Ok(())
} }
pub fn start_kpm_watcher() -> Result<()> { 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()?; ensure_kpm_dir()?;
// 检查是否处于安全模式 // 检查是否处于安全模式
if crate::utils::is_safe_mode() { 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() { 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(()); return Ok(());
} }
let mut watcher = notify::recommended_watcher(|res| match res { let mut watcher = notify::recommended_watcher(|res| match res {
Ok(event) => handle_kpm_event(event), 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)?; watcher.watch(Path::new(KPM_DIR), RecursiveMode::NonRecursive)?;
log::info!("KPM: Started file watcher for directory: {}", KPM_DIR);
Ok(()) Ok(())
} }
@@ -50,8 +106,9 @@ pub fn handle_kpm_event(event: notify::Event) {
fn handle_create_event(paths: Vec<std::path::PathBuf>) { fn handle_create_event(paths: Vec<std::path::PathBuf>) {
for path in paths { for path in paths {
if path.extension() == Some(OsStr::new("kpm")) { if path.extension() == Some(OsStr::new("kpm")) {
log::info!("KPM: Detected new KPM file: {}", path.display());
if let Err(e) = load_kpm(&path) { 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<std::path::PathBuf>) {
fn handle_remove_event(paths: Vec<std::path::PathBuf>) { fn handle_remove_event(paths: Vec<std::path::PathBuf>) {
for path in paths { for path in paths {
if let Some(name) = path.file_stem().and_then(|s| s.to_str()) { 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) { if let Err(e) = unload_kpm(name) {
log::warn!("Failed to unload {}: {}", name, e); log::warn!("KPM: Failed to unload {}: {}", name, e);
}
if let Err(e) = fs::remove_file(&path) {
log::error!("Failed to delete file: {}: {}", path.display(), e);
} }
} }
} }
@@ -72,7 +127,7 @@ fn handle_remove_event(paths: Vec<std::path::PathBuf>) {
fn handle_modify_event(paths: Vec<std::path::PathBuf>) { fn handle_modify_event(paths: Vec<std::path::PathBuf>) {
for path in paths { 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<std::path::PathBuf>) {
pub fn load_kpm(path: &Path) -> Result<()> { pub fn load_kpm(path: &Path) -> Result<()> {
let path_str = path let path_str = path
.to_str() .to_str()
.ok_or_else(|| anyhow!("Invalid path: {}", path.display()))?; .ok_or_else(|| anyhow!("KPM: Invalid path: {}", path.display()))?;
let status = std::process::Command::new(KPMMGR_PATH)
.args(["load", path_str, ""]) let path_cstring = CString::new(path_str)
.status()?; .map_err(|e| anyhow!("KPM: Failed to convert path to CString: {}", e))?;
let mut out: c_int = -1;
if status.success() { let _ret = unsafe {
log::info!("Loaded KPM: {}", path.display()); prctl(
KSU_OPTIONS as c_int,
SUKISU_KPM_LOAD,
path_cstring.as_ptr() as *mut c_void,
ptr::null_mut::<c_void>(),
&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(()) Ok(())
} }
// 卸载 KPM 模块并尝试删除对应文件 // 卸载 KPM 模块
pub fn unload_kpm(name: &str) -> Result<()> { pub fn unload_kpm(name: &str) -> Result<()> {
let status = std::process::Command::new(KPMMGR_PATH) let name_cstring = CString::new(name)
.args(["unload", name]) .map_err(|e| anyhow!("KPM: Failed to convert name to CString: {}", e))?;
.status()
.map_err(|e| anyhow!("Failed to execute kpmmgr: {}", e))?;
if status.success() { let mut out: c_int = -1;
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());
}
log::info!("Successfully unloaded KPM: {}", name); let _ret = unsafe {
} else { prctl(
log::warn!("KPM unloading may have failed: {}", name); KSU_OPTIONS as c_int,
SUKISU_KPM_UNLOAD,
name_cstring.as_ptr() as *mut c_void,
ptr::null_mut::<c_void>(),
&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(()) Ok(())
} }
@@ -136,17 +220,23 @@ fn find_kpm_file(name: &str) -> Result<Option<std::path::PathBuf>> {
// 安全模式下删除所有 KPM 模块 // 安全模式下删除所有 KPM 模块
pub fn remove_all_kpms() -> Result<()> { 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)? { for entry in fs::read_dir(KPM_DIR)? {
let path = entry?.path(); let path = entry?.path();
if path.extension().is_some_and(|ext| ext == "kpm") { if path.extension().is_some_and(|ext| ext == "kpm") {
if let Some(name) = path.file_stem() { if let Some(name) = path.file_stem() {
if let Err(e) = unload_kpm(name.to_string_lossy().as_ref()) { let name_str = name.to_string_lossy();
log::error!("Failed to remove KPM: {}", e); 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) { 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(()) Ok(())
} }
// 加载 KPM 模块 // 加载所有 KPM 模块
pub fn load_kpm_modules() -> Result<()> { 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()?; 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)? { for entry in std::fs::read_dir(KPM_DIR)? {
let path = entry?.path(); let path = entry?.path();
if let Some(file_name) = path.file_stem() { if let Some(file_name) = path.file_stem() {
if let Some(file_name_str) = file_name.to_str() { if let Some(file_name_str) = file_name.to_str() {
if file_name_str.is_empty() { if file_name_str.is_empty() {
log::warn!("Invalid KPM file name: {}", path.display()); log::warn!("KPM: Invalid KPM file name: {}", path.display());
continue; continue;
} }
} }
} }
if path.extension().is_some_and(|ext| ext == "kpm") { if path.extension().is_some_and(|ext| ext == "kpm") {
match load_kpm(&path) { match load_kpm(&path) {
Ok(()) => log::info!("Successfully loaded KPM module: {}", path.display()), Ok(()) => {
Err(e) => log::warn!("Failed to load KPM module {}: {}", path.display(), e), 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(()) Ok(())
} }