From 719b90f8da38f9710619d5c77610b5c4f841b104 Mon Sep 17 00:00:00 2001 From: tiann Date: Tue, 11 Apr 2023 20:32:08 +0800 Subject: [PATCH] ksud: use move mount instead of remount for stock mounts Because some stock mounts are difficult to remount it back, so we bind mount it to somewhere else before overlayfs mount. And then use move mount to mount it back. --- userspace/ksud/Cargo.lock | 18 +++--- userspace/ksud/src/defs.rs | 1 + userspace/ksud/src/mount.rs | 112 +++++++++++++++++++++++------------- 3 files changed, 82 insertions(+), 49 deletions(-) diff --git a/userspace/ksud/Cargo.lock b/userspace/ksud/Cargo.lock index 11c6b942..b5d1bae8 100644 --- a/userspace/ksud/Cargo.lock +++ b/userspace/ksud/Cargo.lock @@ -82,9 +82,9 @@ checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" [[package]] name = "base64ct" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b645a089122eccb6111b4f81cbc1a49f5900ac4666bb93ac027feaecf15607bf" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" [[package]] name = "bindgen" @@ -763,9 +763,9 @@ dependencies = [ [[package]] name = "jobserver" -version = "0.1.25" +version = "0.1.26" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "068b1ee6743e4d11fb9c6a1e6064b3693a1b600e7f5f5988047d98b3dc9fb90b" +checksum = "936cfd212a0155903bcbc060e316fb6cc7cbf2e1907329391ebadc1fe0ce77c2" dependencies = [ "libc", ] @@ -1426,9 +1426,9 @@ dependencies = [ [[package]] name = "time" -version = "0.3.17" +version = "0.3.20" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a561bf4617eebd33bca6434b988f39ed798e527f51a1e797d0ee4f61c0a38376" +checksum = "cd0cbfecb4d19b5ea75bb31ad904eb5b9fa13f21079c3b92017ebdf4999a5890" dependencies = [ "serde", "time-core", @@ -1732,7 +1732,7 @@ dependencies = [ "hmac", "pbkdf2", "sha1", - "time 0.3.17", + "time 0.3.20", "zstd", ] @@ -1766,9 +1766,9 @@ dependencies = [ [[package]] name = "zstd-sys" -version = "2.0.6+zstd.1.5.2" +version = "2.0.7+zstd.1.5.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "68a3f9792c0c3dc6c165840a75f47ae1f4da402c2d006881129579f6597e801b" +checksum = "94509c3ba2fe55294d752b79842c530ccfab760192521df74a081a78d2b3c7f5" dependencies = [ "cc", "libc", diff --git a/userspace/ksud/src/defs.rs b/userspace/ksud/src/defs.rs index 71ec132a..8de511df 100644 --- a/userspace/ksud/src/defs.rs +++ b/userspace/ksud/src/defs.rs @@ -5,6 +5,7 @@ pub const WORKING_DIR: &str = concatcp!(ADB_DIR, "ksu/"); pub const BINARY_DIR: &str = concatcp!(WORKING_DIR, "bin/"); pub const KSURC_PATH: &str = concatcp!(WORKING_DIR, ".ksurc"); +pub const STOCK_MNT_ROOT: &str = concatcp!(WORKING_DIR, ".mnt"); pub const DAEMON_PATH: &str = concatcp!(ADB_DIR, "ksud"); #[cfg(target_os = "android")] diff --git a/userspace/ksud/src/mount.rs b/userspace/ksud/src/mount.rs index 40efeab6..eca448d6 100644 --- a/userspace/ksud/src/mount.rs +++ b/userspace/ksud/src/mount.rs @@ -12,6 +12,8 @@ use procfs::process::{MountInfo, Process}; #[cfg(any(target_os = "linux", target_os = "android"))] use std::collections::HashSet; +use crate::utils; + pub struct AutoMountExt4 { mnt: String, #[cfg(any(target_os = "linux", target_os = "android"))] @@ -167,7 +169,6 @@ impl StockOverlay { pub fn mount_all(&self) { unimplemented!() } - } #[cfg(any(target_os = "linux", target_os = "android"))] @@ -245,61 +246,92 @@ impl StockOverlay { pub struct StockMount { mnt: String, #[cfg(any(target_os = "linux", target_os = "android"))] - mountlist: proc_mounts::MountList, + mountlist: Vec<(proc_mounts::MountInfo, std::path::PathBuf)>, + rootmount: sys_mount::Mount, } #[cfg(any(target_os = "linux", target_os = "android"))] impl StockMount { pub fn new(mnt: &str) -> Result { let mountlist = proc_mounts::MountList::new()?; - Ok(Self { - mnt: mnt.to_string(), - mountlist, - }) - } - - fn get_target_mounts(&self) -> Vec<&proc_mounts::MountInfo> { - let mut mounts = self - .mountlist - .destination_starts_with(std::path::Path::new(&self.mnt)) + let mut mounts = mountlist + .destination_starts_with(std::path::Path::new(mnt)) .filter(|m| m.fstype != "overlay" && m.fstype != "rootfs") .collect::>(); mounts.sort_by(|a, b| b.dest.cmp(&a.dest)); // inverse order - mounts + + let mntroot = std::path::Path::new(crate::defs::STOCK_MNT_ROOT); + utils::ensure_dir_exists(&mntroot)?; + log::info!("stock mount root: {}", mntroot.display()); + + let rootdir = mntroot.join( + mnt.strip_prefix("/") + .ok_or(anyhow::anyhow!("invalid mnt: {}!", mnt))?, + ); + utils::ensure_dir_exists(&rootdir)?; + let rootmount = Mount::builder().fstype("tmpfs").mount("tmpfs", &rootdir)?; + + let mut ms = vec![]; + for m in mounts { + let dest = &m.dest; + if dest == std::path::Path::new(mnt) { + continue; + } + + let path = rootdir.join(dest.strip_prefix("/")?); + log::info!("rootdir: {}, path: {}", rootdir.display(), path.display()); + if dest.is_dir() { + utils::ensure_dir_exists(&path)?; + } else if dest.is_file() { + utils::ensure_file_exists(&path)?; + } else { + log::warn!("unknown file type: {:?}", dest); + } + log::info!("bind stock mount: {} -> {}", dest.display(), path.display()); + Mount::builder() + .flags(MountFlags::BIND) + .mount(&dest, &path)?; + + ms.push((m.clone(), path)); + } + + Ok(Self { + mnt: mnt.to_string(), + mountlist: ms, + rootmount, + }) } - pub fn remount(&self) -> Result<()> { - let mut mounts = self.get_target_mounts(); - mounts.reverse(); // remount it in order - log::info!("remount stock for {} : {:?}", self.mnt, mounts); - for m in mounts { - let src = std::fs::canonicalize(&m.source)?; + // Yes, we move self here! + pub fn remount(self) -> Result<()> { + log::info!("remount stock for {} : {:?}", self.mnt, self.mountlist); + let mut result = Ok(()); + for (m, src) in self.mountlist { + let dst = m.dest; - let src = src.to_str().ok_or(anyhow::anyhow!("Failed to get src"))?; - let dst = m - .dest - .to_str() - .ok_or(anyhow::anyhow!("Failed to get dst"))?; - - let fstype = m.fstype.as_str(); - let options = m.options.join(","); - - log::info!("begin remount: {src} -> {dst}"); - let result = std::process::Command::new("mount") - .arg("-t") - .arg(fstype) - .arg("-o") - .arg(options) - .arg(src) - .arg(dst) - .status(); - if let Err(e) = result { + log::info!("begin remount: {} -> {}", src.display(), dst.display()); + let mount_result = Mount::builder() + .flags(MountFlags::BIND | MountFlags::MOVE) + .mount(&src, &dst); + if let Err(e) = mount_result { log::error!("remount failed: {}", e); + result = Err(e); } else { - log::info!("remount {src} -> {dst} succeed!"); + log::info!( + "remount {}({}) -> {} succeed!", + m.source.display(), + src.display(), + dst.display() + ); } } - Ok(()) + + // umount the root tmpfs mount + if let Err(e) = self.rootmount.unmount(UnmountFlags::DETACH) { + log::warn!("umount root mount failed: {}", e); + } + + result } }