kernel: expose umount list to ioctl interface (#2950)
This idea is borrowed from simonpunk's susfs4ksu. What we see here is that, yeah well, lets just have userspace send us what it wants unmounted, this is better than hardcoding everything. This also solves that issue where MNT_DETACH fails, as long as we send unmountables in proper order. A small anti-duplicate mechanism is also added. While in-kernel umount is a bit worse than zygisk-provider-based ones, this can still serve as a healthy alternative. --------- - Remove duplicate checks Signed-off-by: backslashxx <118538522+backslashxx@users.noreply.github.com> Co-authored-by: weishu <twsxtd@gmail.com> Co-authored-by: ShirkNeko <109797057+ShirkNeko@users.noreply.github.com>
This commit is contained in:
@@ -390,6 +390,32 @@ enum Kernel {
|
||||
/// mount point
|
||||
mnt: String,
|
||||
},
|
||||
/// Manage umount list
|
||||
Umount {
|
||||
#[command(subcommand)]
|
||||
command: UmountOp,
|
||||
},
|
||||
/// Notify that module is mounted
|
||||
NotifyModuleMounted,
|
||||
}
|
||||
|
||||
#[derive(clap::Subcommand, Debug)]
|
||||
enum UmountOp {
|
||||
/// Add mount point to umount list
|
||||
Add {
|
||||
/// mount point path
|
||||
mnt: String,
|
||||
/// umount flags (default: 0, MNT_DETACH: 2)
|
||||
#[arg(short, long, default_value = "0")]
|
||||
flags: u32,
|
||||
},
|
||||
/// Delete mount point from umount list
|
||||
Del {
|
||||
/// mount point path
|
||||
mnt: String,
|
||||
},
|
||||
/// Wipe all entries from umount list
|
||||
Wipe,
|
||||
}
|
||||
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
@@ -425,7 +451,6 @@ enum Umount {
|
||||
|
||||
/// Check mount type (overlay)
|
||||
#[arg(long, default_value = "false")]
|
||||
check_mnt: bool,
|
||||
|
||||
/// Umount flags (0 or 8 for MNT_DETACH)
|
||||
#[arg(long, default_value = "-1")]
|
||||
@@ -606,6 +631,15 @@ pub fn run() -> Result<()> {
|
||||
} => crate::boot_patch::restore(boot, magiskboot, flash),
|
||||
Commands::Kernel { command } => match command {
|
||||
Kernel::NukeExt4Sysfs { mnt } => ksucalls::nuke_ext4_sysfs(&mnt),
|
||||
Kernel::Umount { command } => match command {
|
||||
UmountOp::Add { mnt, flags } => ksucalls::umount_list_add(&mnt, flags),
|
||||
UmountOp::Del { mnt } => ksucalls::umount_list_del(&mnt),
|
||||
UmountOp::Wipe => ksucalls::umount_list_wipe().map_err(Into::into),
|
||||
},
|
||||
Kernel::NotifyModuleMounted => {
|
||||
ksucalls::report_module_mounted();
|
||||
Ok(())
|
||||
}
|
||||
},
|
||||
#[cfg(target_arch = "aarch64")]
|
||||
Commands::Kpm { command } => {
|
||||
@@ -629,9 +663,8 @@ pub fn run() -> Result<()> {
|
||||
Commands::Umount { command } => match command {
|
||||
Umount::Add {
|
||||
path,
|
||||
check_mnt,
|
||||
flags,
|
||||
} => crate::umount_manager::add_umount_path(&path, check_mnt, flags),
|
||||
} => crate::umount_manager::add_umount_path(&path, flags),
|
||||
Umount::Remove { path } => crate::umount_manager::remove_umount_path(&path),
|
||||
Umount::List => crate::umount_manager::list_umount_paths(),
|
||||
Umount::ClearCustom => crate::umount_manager::clear_custom_paths(),
|
||||
|
||||
@@ -18,6 +18,7 @@ const KSU_IOCTL_SET_FEATURE: u32 = 0x40004b0e; // _IOC(_IOC_WRITE, 'K', 14, 0)
|
||||
const KSU_IOCTL_GET_WRAPPER_FD: u32 = 0x40004b0f; // _IOC(_IOC_WRITE, 'K', 15, 0)
|
||||
const KSU_IOCTL_MANAGE_MARK: u32 = 0xc0004b10; // _IOC(_IOC_READ|_IOC_WRITE, 'K', 16, 0)
|
||||
const KSU_IOCTL_NUKE_EXT4_SYSFS: u32 = 0x40004b11; // _IOC(_IOC_WRITE, 'K', 17, 0)
|
||||
const KSU_IOCTL_ADD_TRY_UMOUNT: u32 = 0x40004b12; // _IOC(_IOC_WRITE, 'K', 18, 0)
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
@@ -80,12 +81,25 @@ pub struct NukeExt4SysfsCmd {
|
||||
pub arg: u64,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Clone, Copy, Default)]
|
||||
struct AddTryUmountCmd {
|
||||
arg: u64, // char ptr, this is the mountpoint
|
||||
flags: u32, // this is the flag we use for it
|
||||
mode: u8, // denotes what to do with it 0:wipe_list 1:add_to_list 2:delete_entry
|
||||
}
|
||||
|
||||
// Mark operation constants
|
||||
const KSU_MARK_GET: u32 = 1;
|
||||
const KSU_MARK_MARK: u32 = 2;
|
||||
const KSU_MARK_UNMARK: u32 = 3;
|
||||
const KSU_MARK_REFRESH: u32 = 4;
|
||||
|
||||
// Umount operation constants
|
||||
const KSU_UMOUNT_WIPE: u8 = 0;
|
||||
const KSU_UMOUNT_ADD: u8 = 1;
|
||||
const KSU_UMOUNT_DEL: u8 = 2;
|
||||
|
||||
// Global driver fd cache
|
||||
#[cfg(any(target_os = "linux", target_os = "android"))]
|
||||
static DRIVER_FD: OnceLock<RawFd> = OnceLock::new();
|
||||
@@ -310,3 +324,38 @@ pub fn nuke_ext4_sysfs(mnt: &str) -> anyhow::Result<()> {
|
||||
ksuctl(KSU_IOCTL_NUKE_EXT4_SYSFS, &mut ioctl_cmd as *mut _)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Wipe all entries from umount list
|
||||
pub fn umount_list_wipe() -> std::io::Result<()> {
|
||||
let mut cmd = AddTryUmountCmd {
|
||||
arg: 0,
|
||||
flags: 0,
|
||||
mode: KSU_UMOUNT_WIPE,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_ADD_TRY_UMOUNT, &mut cmd as *mut _)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Add mount point to umount list
|
||||
pub fn umount_list_add(path: &str, flags: u32) -> anyhow::Result<()> {
|
||||
let c_path = std::ffi::CString::new(path)?;
|
||||
let mut cmd = AddTryUmountCmd {
|
||||
arg: c_path.as_ptr() as u64,
|
||||
flags,
|
||||
mode: KSU_UMOUNT_ADD,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_ADD_TRY_UMOUNT, &mut cmd as *mut _)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Delete mount point from umount list
|
||||
pub fn umount_list_del(path: &str) -> anyhow::Result<()> {
|
||||
let c_path = std::ffi::CString::new(path)?;
|
||||
let mut cmd = AddTryUmountCmd {
|
||||
arg: c_path.as_ptr() as u64,
|
||||
flags: 0,
|
||||
mode: KSU_UMOUNT_DEL,
|
||||
};
|
||||
ksuctl(KSU_IOCTL_ADD_TRY_UMOUNT, &mut cmd as *mut _)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -13,7 +13,6 @@ const KSU_IOCTL_UMOUNT_MANAGER: u32 = 0xc0004b6b; // _IOC(_IOC_READ|_IOC_WRITE,
|
||||
#[derive(Clone, Serialize, Deserialize, Debug)]
|
||||
pub struct UmountEntry {
|
||||
pub path: String,
|
||||
pub check_mnt: bool,
|
||||
pub flags: i32,
|
||||
pub is_default: bool,
|
||||
}
|
||||
@@ -34,7 +33,6 @@ pub struct UmountManager {
|
||||
struct UmountManagerCmd {
|
||||
pub operation: u32,
|
||||
pub path: [u8; 256],
|
||||
pub check_mnt: u8,
|
||||
pub flags: i32,
|
||||
pub count: u32,
|
||||
pub entries_ptr: u64,
|
||||
@@ -45,7 +43,6 @@ impl Default for UmountManagerCmd {
|
||||
UmountManagerCmd {
|
||||
operation: 0,
|
||||
path: [0; 256],
|
||||
check_mnt: 0,
|
||||
flags: 0,
|
||||
count: 0,
|
||||
entries_ptr: 0,
|
||||
@@ -112,7 +109,7 @@ impl UmountManager {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn add_entry(&mut self, path: &str, check_mnt: bool, flags: i32) -> Result<()> {
|
||||
pub fn add_entry(&mut self, path: &str, flags: i32) -> Result<()> {
|
||||
let exists = self
|
||||
.defaults
|
||||
.iter()
|
||||
@@ -126,7 +123,6 @@ impl UmountManager {
|
||||
|
||||
let entry = UmountEntry {
|
||||
path: path.to_string(),
|
||||
check_mnt,
|
||||
flags,
|
||||
is_default,
|
||||
};
|
||||
@@ -165,43 +161,36 @@ impl UmountManager {
|
||||
vec![
|
||||
UmountEntry {
|
||||
path: "/odm".to_string(),
|
||||
check_mnt: true,
|
||||
flags: 0,
|
||||
is_default: true,
|
||||
},
|
||||
UmountEntry {
|
||||
path: "/system".to_string(),
|
||||
check_mnt: true,
|
||||
flags: 0,
|
||||
is_default: true,
|
||||
},
|
||||
UmountEntry {
|
||||
path: "/vendor".to_string(),
|
||||
check_mnt: true,
|
||||
flags: 0,
|
||||
is_default: true,
|
||||
},
|
||||
UmountEntry {
|
||||
path: "/product".to_string(),
|
||||
check_mnt: true,
|
||||
flags: 0,
|
||||
is_default: true,
|
||||
},
|
||||
UmountEntry {
|
||||
path: "/system_ext".to_string(),
|
||||
check_mnt: true,
|
||||
flags: 0,
|
||||
is_default: true,
|
||||
},
|
||||
UmountEntry {
|
||||
path: "/data/adb/modules".to_string(),
|
||||
check_mnt: false,
|
||||
flags: -1, // MNT_DETACH
|
||||
is_default: true,
|
||||
},
|
||||
UmountEntry {
|
||||
path: "/debug_ramdisk".to_string(),
|
||||
check_mnt: false,
|
||||
flags: -1, // MNT_DETACH
|
||||
is_default: true,
|
||||
},
|
||||
@@ -226,7 +215,6 @@ impl UmountManager {
|
||||
fn kernel_add_entry(entry: &UmountEntry) -> Result<()> {
|
||||
let mut cmd = UmountManagerCmd {
|
||||
operation: 0,
|
||||
check_mnt: entry.check_mnt as u8,
|
||||
flags: entry.flags,
|
||||
..Default::default()
|
||||
};
|
||||
@@ -255,9 +243,9 @@ pub fn init_umount_manager() -> Result<UmountManager> {
|
||||
Ok(manager)
|
||||
}
|
||||
|
||||
pub fn add_umount_path(path: &str, check_mnt: bool, flags: i32) -> Result<()> {
|
||||
pub fn add_umount_path(path: &str, flags: i32) -> Result<()> {
|
||||
let mut manager = init_umount_manager()?;
|
||||
manager.add_entry(path, check_mnt, flags)?;
|
||||
manager.add_entry(path, flags)?;
|
||||
manager.save_config()?;
|
||||
println!("✓ Added umount path: {}", path);
|
||||
Ok(())
|
||||
@@ -290,7 +278,6 @@ pub fn list_umount_paths() -> Result<()> {
|
||||
println!(
|
||||
"{:<30} {:<12} {:<8} {:<10}",
|
||||
entry.path,
|
||||
entry.check_mnt,
|
||||
entry.flags,
|
||||
if entry.is_default { "Yes" } else { "No" }
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user