From 7103779a1133c409aca33753d8a114f09755ae05 Mon Sep 17 00:00:00 2001 From: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> Date: Tue, 4 Nov 2025 00:35:26 +0800 Subject: [PATCH] ksud: Migrating KPM to ioctl - Fix compatibility manager issues with legacy kernels Co-authored-by: AlexLiuDev233 Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com> --- manager/app/src/main/cpp/legacy.c | 2 +- userspace/ksud/src/kpm.rs | 196 +++++++++++++++--------------- userspace/ksud/src/ksucalls.rs | 18 +++ 3 files changed, 114 insertions(+), 102 deletions(-) diff --git a/manager/app/src/main/cpp/legacy.c b/manager/app/src/main/cpp/legacy.c index de72a326..b49de312 100644 --- a/manager/app/src/main/cpp/legacy.c +++ b/manager/app/src/main/cpp/legacy.c @@ -50,7 +50,7 @@ static bool ksuctl(int cmd, void* arg1, void* arg2) { struct ksu_version_info legacy_get_info() { - int32_t version = -1; + int32_t version = 0; int32_t flags = 0; ksuctl(CMD_GET_VERSION, &version, &flags); return (struct ksu_version_info){version, flags}; diff --git a/userspace/ksud/src/kpm.rs b/userspace/ksud/src/kpm.rs index b9bac5f6..3a7acbf5 100644 --- a/userspace/ksud/src/kpm.rs +++ b/userspace/ksud/src/kpm.rs @@ -1,29 +1,26 @@ +use crate::ksucalls; use anyhow::{Result, anyhow, bail}; -use libc::{c_int, c_ulong, prctl}; use notify::{RecursiveMode, Watcher}; use std::{ ffi::{CStr, CString, OsStr}, fs, os::unix::fs::PermissionsExt, path::{Path, PathBuf}, - ptr, }; pub const KPM_DIR: &str = "/data/adb/kpm"; -// SukiSU KPM prctl command space -const KSU_OPTIONS: c_int = 0xdeadbeef_u32 as c_int; -const SUKISU_KPM_LOAD: c_int = 28; -const SUKISU_KPM_UNLOAD: c_int = 29; -const SUKISU_KPM_NUM: c_int = 30; -const SUKISU_KPM_LIST: c_int = 31; -const SUKISU_KPM_INFO: c_int = 32; -const SUKISU_KPM_CONTROL: c_int = 33; -const SUKISU_KPM_VERSION: c_int = 34; +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; /// Convert raw kernel return code to `Result`. #[inline(always)] -fn check_out(rc: c_int) -> Result { +fn check_out(rc: i32) -> Result { if rc < 0 { bail!("KPM error: {}", std::io::Error::from_raw_os_error(-rc)); } @@ -35,18 +32,16 @@ pub fn kpm_load(path: &str, args: Option<&str>) -> Result<()> { let path_c = CString::new(path)?; let args_c = args.map(CString::new).transpose()?; - let mut rc: c_int = -1; - // SAFETY: pointers live through the prctl; null-check done by CString. - unsafe { - prctl( - KSU_OPTIONS, - SUKISU_KPM_LOAD, - path_c.as_ptr() as c_ulong, - args_c.as_ref().map_or(ptr::null(), |s| s.as_ptr()) as c_ulong, - &mut rc as *mut c_int as c_ulong, - ); - } - check_out(rc)?; + 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, + }; + + ksucalls::kpm_ioctl(&mut cmd)?; + check_out(result)?; println!("Success"); Ok(()) } @@ -54,33 +49,32 @@ pub fn kpm_load(path: &str, args: Option<&str>) -> Result<()> { /// Unload by module name. pub fn kpm_unload(name: &str) -> Result<()> { let name_c = CString::new(name)?; - let mut rc = -1; - unsafe { - prctl( - KSU_OPTIONS, - SUKISU_KPM_UNLOAD, - name_c.as_ptr() as c_ulong, - 0, - &mut rc as *mut _ as c_ulong, - ); - } - check_out(rc)?; + + 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, + }; + + ksucalls::kpm_ioctl(&mut cmd)?; + check_out(result)?; Ok(()) } /// Return loaded module count. pub fn kpm_num() -> Result { - let mut rc = -1; - unsafe { - prctl( - KSU_OPTIONS, - SUKISU_KPM_NUM, - 0, - 0, - &mut rc as *mut _ as c_ulong, - ) + 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, }; - let n = check_out(rc)?; + + ksucalls::kpm_ioctl(&mut cmd)?; + let n = check_out(result)?; println!("{n}"); Ok(n) } @@ -88,17 +82,17 @@ pub fn kpm_num() -> Result { /// Print name list of loaded modules. pub fn kpm_list() -> Result<()> { let mut buf = vec![0u8; 1024]; - let mut rc = -1; - unsafe { - prctl( - KSU_OPTIONS, - SUKISU_KPM_LIST, - buf.as_mut_ptr() as c_ulong, - buf.len() as c_ulong, - &mut rc as *mut _ as c_ulong, - ); - } - check_out(rc)?; + + 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, + }; + + ksucalls::kpm_ioctl(&mut cmd)?; + check_out(result)?; print!("{}", buf2str(&buf)); Ok(()) } @@ -107,17 +101,17 @@ pub fn kpm_list() -> Result<()> { pub fn kpm_info(name: &str) -> Result<()> { let name_c = CString::new(name)?; let mut buf = vec![0u8; 256]; - let mut rc = -1; - unsafe { - prctl( - KSU_OPTIONS, - SUKISU_KPM_INFO, - name_c.as_ptr() as c_ulong, - buf.as_mut_ptr() as c_ulong, - &mut rc as *mut _ as c_ulong, - ); - } - check_out(rc)?; + + 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, + }; + + ksucalls::kpm_ioctl(&mut cmd)?; + check_out(result)?; println!("{}", buf2str(&buf)); Ok(()) } @@ -126,33 +120,33 @@ pub fn kpm_info(name: &str) -> Result<()> { pub fn kpm_control(name: &str, args: &str) -> Result { let name_c = CString::new(name)?; let args_c = CString::new(args)?; - let mut rc = -1; - unsafe { - prctl( - KSU_OPTIONS, - SUKISU_KPM_CONTROL, - name_c.as_ptr() as c_ulong, - args_c.as_ptr() as c_ulong, - &mut rc as *mut _ as c_ulong, - ); - } - check_out(rc) + + 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, + }; + + ksucalls::kpm_ioctl(&mut cmd)?; + check_out(result) } /// Print loader version string. pub fn kpm_version_loader() -> Result<()> { let mut buf = vec![0u8; 1024]; - let mut rc = -1; - unsafe { - prctl( - KSU_OPTIONS, - SUKISU_KPM_VERSION, - buf.as_mut_ptr() as c_ulong, - buf.len() as c_ulong, - &mut rc as *mut _ as c_ulong, - ); - } - check_out(rc)?; + + 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, + }; + + ksucalls::kpm_ioctl(&mut cmd)?; + check_out(result)?; print!("{}", buf2str(&buf)); Ok(()) } @@ -160,19 +154,19 @@ pub fn kpm_version_loader() -> Result<()> { /// Validate loader version; empty or "Error*" => fail. pub fn check_kpm_version() -> Result { let mut buf = vec![0u8; 1024]; - let mut rc = -1; - unsafe { - prctl( - KSU_OPTIONS, - SUKISU_KPM_VERSION, - buf.as_mut_ptr() as c_ulong, - buf.len() as c_ulong, - &mut rc as *mut _ as c_ulong, - ); - } - check_out(rc)?; + + 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, + }; + + ksucalls::kpm_ioctl(&mut cmd)?; + check_out(result)?; let ver = buf2str(&buf); - if ver.is_empty() || ver.starts_with("Error") { + if ver.is_empty() { bail!("KPM: invalid version response: {ver}"); } log::info!("KPM: version check ok: {ver}"); diff --git a/userspace/ksud/src/ksucalls.rs b/userspace/ksud/src/ksucalls.rs index 8ca1eb93..8948352e 100644 --- a/userspace/ksud/src/ksucalls.rs +++ b/userspace/ksud/src/ksucalls.rs @@ -15,6 +15,8 @@ const KSU_IOCTL_SET_SEPOLICY: u32 = 0xc0004b04; // _IOC(_IOC_READ|_IOC_WRITE, 'K const KSU_IOCTL_CHECK_SAFEMODE: u32 = 0x80004b05; // _IOC(_IOC_READ, 'K', 5, 0) const KSU_IOCTL_GET_FEATURE: u32 = 0xc0004b0d; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 13, 0) const KSU_IOCTL_SET_FEATURE: u32 = 0x40004b0e; // _IOC(_IOC_WRITE, 'K', 14, 0) +#[allow(dead_code)] +const KSU_IOCTL_KPM: u32 = 0xc0004bc8; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 200, 0) #[repr(C)] #[derive(Clone, Copy, Default)] @@ -220,3 +222,19 @@ pub fn set_feature(feature_id: u32, value: u64) -> std::io::Result<()> { ksuctl(KSU_IOCTL_SET_FEATURE, &mut cmd as *mut _)?; Ok(()) } + +#[repr(C)] +#[derive(Clone, Copy, Default)] +#[allow(dead_code)] +pub struct KsuKpmCmd { + pub arg2: u64, + pub arg3: u64, + pub arg4: u64, + pub arg5: u64, +} + +#[allow(dead_code)] +pub fn kpm_ioctl(cmd: &mut KsuKpmCmd) -> std::io::Result<()> { + ksuctl(KSU_IOCTL_KPM, cmd as *mut _)?; + Ok(()) +}