diff --git a/userspace/ksud/src/defs.rs b/userspace/ksud/src/defs.rs index dd71a0f63e82..c4b9fc3f989b 100644 --- a/userspace/ksud/src/defs.rs +++ b/userspace/ksud/src/defs.rs @@ -29,6 +29,8 @@ pub const MODULE_UPDATE_TMP_DIR: &str = concatcp!(ADB_DIR, "modules_update/"); pub const SYSTEM_RW_DIR: &str = concatcp!(MODULE_DIR, ".rw/"); pub const TEMP_DIR: &str = "/debug_ramdisk"; +pub const TEMP_DIR_LEGACY: &str = "/sbin"; + pub const MODULE_WEB_DIR: &str = "webroot"; pub const DISABLE_FILE_NAME: &str = "disable"; pub const UPDATE_FILE_NAME: &str = "update"; diff --git a/userspace/ksud/src/init_event.rs b/userspace/ksud/src/init_event.rs index 5839c1957fa4..7107ff74225d 100644 --- a/userspace/ksud/src/init_event.rs +++ b/userspace/ksud/src/init_event.rs @@ -191,7 +191,7 @@ pub fn on_post_data_fs() -> Result<()> { } // mount temp dir - if let Err(e) = mount::mount_tmpfs(defs::TEMP_DIR) { + if let Err(e) = mount::mount_tmpfs(utils::get_tmp_path()) { warn!("do temp dir mount failed: {}", e); } diff --git a/userspace/ksud/src/mount.rs b/userspace/ksud/src/mount.rs index a15deb976092..11be898bbeb7 100644 --- a/userspace/ksud/src/mount.rs +++ b/userspace/ksud/src/mount.rs @@ -63,18 +63,21 @@ pub fn mount_ext4(source: impl AsRef<Path>, target: impl AsRef<Path>) -> Result< .attach(source) .with_context(|| "Failed to attach loop")?; let lo = new_loopback.path().ok_or(anyhow!("no loop"))?; - let fs = fsopen("ext4", FsOpenFlags::FSOPEN_CLOEXEC)?; - let fs = fs.as_fd(); - fsconfig_set_string(fs, "source", lo)?; - fsconfig_create(fs)?; - let mount = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?; - move_mount( - mount.as_fd(), - "", - CWD, - target.as_ref(), - MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH, - )?; + if let Result::Ok(fs) = fsopen("ext4", FsOpenFlags::FSOPEN_CLOEXEC) { + let fs = fs.as_fd(); + fsconfig_set_string(fs, "source", lo)?; + fsconfig_create(fs)?; + let mount = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?; + move_mount( + mount.as_fd(), + "", + CWD, + target.as_ref(), + MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH, + )?; + } else { + mount(lo, target.as_ref(), "ext4", MountFlags::empty(), "")?; + } Ok(()) } @@ -154,18 +157,27 @@ pub fn mount_overlayfs( #[cfg(any(target_os = "linux", target_os = "android"))] pub fn mount_tmpfs(dest: impl AsRef<Path>) -> Result<()> { info!("mount tmpfs on {}", dest.as_ref().display()); - let fs = fsopen("tmpfs", FsOpenFlags::FSOPEN_CLOEXEC)?; - let fs = fs.as_fd(); - fsconfig_set_string(fs, "source", KSU_OVERLAY_SOURCE)?; - fsconfig_create(fs)?; - let mount = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?; - move_mount( - mount.as_fd(), - "", - CWD, - dest.as_ref(), - MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH, - )?; + if let Result::Ok(fs) = fsopen("tmpfs", FsOpenFlags::FSOPEN_CLOEXEC) { + let fs = fs.as_fd(); + fsconfig_set_string(fs, "source", KSU_OVERLAY_SOURCE)?; + fsconfig_create(fs)?; + let mount = fsmount(fs, FsMountFlags::FSMOUNT_CLOEXEC, MountAttrFlags::empty())?; + move_mount( + mount.as_fd(), + "", + CWD, + dest.as_ref(), + MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH, + )?; + } else { + mount( + KSU_OVERLAY_SOURCE, + dest.as_ref(), + "tmpfs", + MountFlags::empty(), + "", + )?; + } Ok(()) } @@ -176,20 +188,29 @@ pub fn bind_mount(from: impl AsRef<Path>, to: impl AsRef<Path>) -> Result<()> { from.as_ref().display(), to.as_ref().display() ); - let tree = open_tree( + if let Result::Ok(tree) = open_tree( CWD, from.as_ref(), OpenTreeFlags::OPEN_TREE_CLOEXEC | OpenTreeFlags::OPEN_TREE_CLONE | OpenTreeFlags::AT_RECURSIVE, - )?; - move_mount( - tree.as_fd(), - "", - CWD, - to.as_ref(), - MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH, - )?; + ) { + move_mount( + tree.as_fd(), + "", + CWD, + to.as_ref(), + MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH, + )?; + } else { + mount( + from.as_ref(), + to.as_ref(), + "", + MountFlags::BIND | MountFlags::REC, + "", + )?; + } Ok(()) } diff --git a/userspace/ksud/src/utils.rs b/userspace/ksud/src/utils.rs index c08fdeee26c4..f7e695507be1 100644 --- a/userspace/ksud/src/utils.rs +++ b/userspace/ksud/src/utils.rs @@ -1,15 +1,17 @@ use anyhow::{bail, Context, Error, Ok, Result}; use std::{ - fs::{create_dir_all, remove_file, write, File, OpenOptions}, + fs::{self, create_dir_all, remove_file, write, File, OpenOptions}, io::{ ErrorKind::{AlreadyExists, NotFound}, Write, }, path::Path, process::Command, + sync::OnceLock, }; use crate::{assets, boot_patch, defs, ksucalls, module, restorecon}; +use std::fs::metadata; #[allow(unused_imports)] use std::fs::{set_permissions, Permissions}; #[cfg(unix)] @@ -187,6 +189,68 @@ pub fn has_magisk() -> bool { which::which("magisk").is_ok() } +fn is_ok_empty(dir: &str) -> bool { + use std::result::Result::Ok; + + match fs::read_dir(dir) { + Ok(mut entries) => entries.next().is_none(), + Err(_) => false, + } +} + +fn find_temp_path() -> String { + use std::result::Result::Ok; + + if is_ok_empty(defs::TEMP_DIR) { + return defs::TEMP_DIR.to_string(); + } + + // Try to create a random directory in /dev/ + let r = tempfile::tempdir_in("/dev/"); + match r { + Ok(tmp_dir) => { + if let Some(path) = tmp_dir.into_path().to_str() { + return path.to_string(); + } + } + Err(_e) => {} + } + + let dirs = [ + defs::TEMP_DIR, + "/patch_hw", + "/oem", + "/root", + defs::TEMP_DIR_LEGACY, + ]; + + // find empty directory + for dir in dirs { + if is_ok_empty(dir) { + return dir.to_string(); + } + } + + // Fallback to non-empty directory + for dir in dirs { + if metadata(dir).is_ok() { + return dir.to_string(); + } + } + + "".to_string() +} + +pub fn get_tmp_path() -> &'static str { + static CHOSEN_TMP_PATH: OnceLock<String> = OnceLock::new(); + + CHOSEN_TMP_PATH.get_or_init(|| { + let r = find_temp_path(); + log::info!("Chosen temp_path: {}", r); + r + }) +} + #[cfg(target_os = "android")] fn link_ksud_to_bin() -> Result<()> { let ksu_bin = PathBuf::from(defs::DAEMON_PATH);