diff --git a/userspace/ksud/Cargo.lock b/userspace/ksud/Cargo.lock index 69bc91178168..f3236670a508 100644 --- a/userspace/ksud/Cargo.lock +++ b/userspace/ksud/Cargo.lock @@ -121,25 +121,6 @@ version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" -[[package]] -name = "bindgen" -version = "0.60.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "062dddbc1ba4aca46de6338e2bf87771414c335f7b2f2036e8f3e9befebf88e6" -dependencies = [ - "bitflags 1.3.2", - "cexpr", - "clang-sys", - "lazy_static", - "lazycell", - "peeking_take_while", - "proc-macro2", - "quote", - "regex", - "rustc-hash", - "shlex", -] - [[package]] name = "bitflags" version = "1.3.2" @@ -209,15 +190,6 @@ dependencies = [ "jobserver", ] -[[package]] -name = "cexpr" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6fac387a98bb7c37292057cffc56d62ecb629900026402633ae9160df93a8766" -dependencies = [ - "nom", -] - [[package]] name = "cfg-if" version = "0.1.10" @@ -254,17 +226,6 @@ dependencies = [ "generic-array", ] -[[package]] -name = "clang-sys" -version = "1.7.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "67523a3b4be3ce1989d607a828d036249522dd9c1c8de7f4dd2dae43a37369d1" -dependencies = [ - "glob", - "libc", - "libloading", -] - [[package]] name = "clap" version = "4.1.4" @@ -618,12 +579,6 @@ version = "0.27.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b6c80984affa11d98d1b88b66ac8853f143217b399d3c74116778ff8fdb4ed2e" -[[package]] -name = "glob" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d2fabcfbdc87f4758337ca535fb41a6d701b65693ce38287d856d1674551ec9b" - [[package]] name = "heck" version = "0.4.1" @@ -862,7 +817,6 @@ dependencies = [ "serde", "serde_json", "sha256", - "sys-mount", "tempdir", "which", "zip 0.6.4", @@ -875,12 +829,6 @@ version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -[[package]] -name = "lazycell" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" - [[package]] name = "libc" version = "0.2.152" @@ -907,16 +855,6 @@ dependencies = [ "rle-decode-fast", ] -[[package]] -name = "libloading" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c571b676ddfc9a8c12f1f3d3085a7b163966a8fd8098a90640953ce5f6170161" -dependencies = [ - "cfg-if 1.0.0", - "windows-sys 0.48.0", -] - [[package]] name = "libm" version = "0.2.6" @@ -950,16 +888,6 @@ version = "0.4.20" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" -[[package]] -name = "loopdev" -version = "0.5.0" -source = "git+https://github.com/tiann/loopdev?branch=loopfix#b6ca5e3ea163f66239f6a835874fe231b2a9286f" -dependencies = [ - "bindgen", - "errno 0.2.8", - "libc", -] - [[package]] name = "memchr" version = "2.7.1" @@ -1080,12 +1008,6 @@ dependencies = [ "sha2", ] -[[package]] -name = "peeking_take_while" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "19b17cddbe7ec3f8bc800887bab5e717348c95ea2ca0b1bf0837fb964dc67099" - [[package]] name = "pin-project-lite" version = "0.2.9" @@ -1349,12 +1271,6 @@ version = "0.1.23" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d626bb9dae77e28219937af045c257c28bfd3f69333c512553507f5f9798cb76" -[[package]] -name = "rustc-hash" -version = "1.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" - [[package]] name = "rustix" version = "0.36.7" @@ -1457,23 +1373,6 @@ dependencies = [ "tokio", ] -[[package]] -name = "shlex" -version = "1.3.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64" - -[[package]] -name = "smart-default" -version = "0.6.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "133659a15339456eeeb07572eb02a91c91e9815e9cbc89566944d2c8d3efdbf6" -dependencies = [ - "proc-macro2", - "quote", - "syn 1.0.107", -] - [[package]] name = "strsim" version = "0.10.0" @@ -1508,19 +1407,6 @@ dependencies = [ "unicode-ident", ] -[[package]] -name = "sys-mount" -version = "2.0.2" -source = "git+https://github.com/tiann/sys-mount?branch=loopfix#c7c4048e4a4ffdf8b108a85956363a75f2c554f0" -dependencies = [ - "bitflags 1.3.2", - "libc", - "loopdev", - "smart-default", - "thiserror", - "tracing", -] - [[package]] name = "tempdir" version = "0.3.7" @@ -1599,37 +1485,6 @@ dependencies = [ "pin-project-lite", ] -[[package]] -name = "tracing" -version = "0.1.40" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" -dependencies = [ - "pin-project-lite", - "tracing-attributes", - "tracing-core", -] - -[[package]] -name = "tracing-attributes" -version = "0.1.27" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "34704c8d6ebcbc939824180af020566b01a7c01f80641264eba0999f6c2b6be7" -dependencies = [ - "proc-macro2", - "quote", - "syn 2.0.48", -] - -[[package]] -name = "tracing-core" -version = "0.1.32" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" -dependencies = [ - "once_cell", -] - [[package]] name = "typenum" version = "1.16.0" diff --git a/userspace/ksud/Cargo.toml b/userspace/ksud/Cargo.toml index 3a38b43b751e..0adf08e4793c 100644 --- a/userspace/ksud/Cargo.toml +++ b/userspace/ksud/Cargo.toml @@ -39,7 +39,6 @@ chrono = "0.4" hole-punch = { git = "https://github.com/tiann/hole-punch" } [target.'cfg(any(target_os = "android", target_os = "linux"))'.dependencies] -sys-mount = { git = "https://github.com/tiann/sys-mount", branch = "loopfix" } rustix = { version = "0.38", features = ["all-apis"] } # some android specific dependencies which compiles under unix are also listed here for convenience of coding android-properties = { version = "0.2.2", features = ["bionic-deprecated"] } diff --git a/userspace/ksud/src/event.rs b/userspace/ksud/src/event.rs index 6b1ddb3cfeb0..c50fb7e9f17c 100644 --- a/userspace/ksud/src/event.rs +++ b/userspace/ksud/src/event.rs @@ -1,5 +1,7 @@ use anyhow::{bail, Context, Result}; use log::{info, warn}; +#[cfg(target_os = "android")] +use std::path::PathBuf; use std::{collections::HashMap, path::Path}; use crate::module::prune_modules; diff --git a/userspace/ksud/src/mount.rs b/userspace/ksud/src/mount.rs index 3a93eac7867e..3a4ff18662d7 100644 --- a/userspace/ksud/src/mount.rs +++ b/userspace/ksud/src/mount.rs @@ -1,11 +1,15 @@ -use anyhow::{bail, Ok, Result}; +use anyhow::{anyhow, bail, Ok, Result}; #[cfg(any(target_os = "linux", target_os = "android"))] use anyhow::Context; #[cfg(any(target_os = "linux", target_os = "android"))] use retry::delay::NoDelay; #[cfg(any(target_os = "linux", target_os = "android"))] -use sys_mount::{unmount, FilesystemType, Mount, MountFlags, Unmount, UnmountFlags}; +use rustix::{ + fd::{AsFd, AsRawFd}, + fs::{access, makedev, mknodat, Access, FileType, Mode, CWD}, + mount::*, +}; use crate::defs::KSU_OVERLAY_SOURCE; use log::{info, warn}; @@ -14,49 +18,90 @@ use procfs::process::Process; use std::path::Path; pub struct AutoMountExt4 { - mnt: String, - #[cfg(any(target_os = "linux", target_os = "android"))] - mount: Option, + target: String, auto_umount: bool, } +#[repr(C)] +struct LoopInfo { + lo_number: core::ffi::c_int, + lo_device: libc::dev_t, + lo_inode: core::ffi::c_ulong, + lo_rdevice: libc::dev_t, + lo_offset: core::ffi::c_int, + lo_encrypt_type: core::ffi::c_int, + lo_encrypt_key_size: core::ffi::c_int, + lo_flags: core::ffi::c_int, + lo_file_name: [libc::c_uchar; 32], + lo_encrypt_key: [libc::c_uchar; 32], + lo_init: [core::ffi::c_ulong; 2], + reserved: [libc::c_char; 4], +} impl AutoMountExt4 { #[cfg(any(target_os = "linux", target_os = "android"))] - pub fn try_new(src: &str, mnt: &str, auto_umount: bool) -> Result { - let result = Mount::builder() - .fstype(FilesystemType::from("ext4")) - .flags(MountFlags::empty()) - .create_loop(true) - .mount(src, mnt) - .map(|mount| { - Ok(Self { - mnt: mnt.to_string(), - mount: Some(mount), - auto_umount, - }) - }); - if let Err(e) = result { - println!("- Mount failed: {e}, retry with system mount"); - let result = std::process::Command::new("mount") - .arg("-t") - .arg("ext4") - .arg(src) - .arg(mnt) - .status(); - if let Err(e) = result { - Err(anyhow::anyhow!( - "mount partition: {src} -> {mnt} failed: {e}" - )) - } else { - Ok(Self { - mnt: mnt.to_string(), - mount: None, - auto_umount, - }) - } - } else { - result.unwrap() - } + pub fn try_new(source: &str, target: &str, auto_umount: bool) -> Result { + use libc::ENXIO; + use rustix::{ + fs::open, + fs::{unlink, OFlags}, + }; + + let lo = (0..=0xfffff) + .find_map(|i| { + let path = format!("/dev/block/loop{i}"); + let mut created = false; + if access(&path, Access::EXISTS).is_err() { + if mknodat( + CWD, + &path, + FileType::BlockDevice, + Mode::from_raw_mode(0o644), + makedev(7, i), + ) + .is_err() + { + return None; + } + created = true; + } + let res = open(&path, OFlags::RDONLY, Mode::from_raw_mode(0)) + .ok() + .and_then(|fd| unsafe { + let loop_info: LoopInfo = std::mem::zeroed(); + if libc::ioctl(fd.as_raw_fd(), 0x4C03, &loop_info as *const _) < 0 + && libc::__errno_location().read() == ENXIO + { + Some(path.clone()) + } else { + None + } + }); + if res.is_none() && created { + unlink(&path).ok(); + } + res + }) + .ok_or(anyhow!("failed to find a free loop device"))?; + let lfd = open(&lo, OFlags::RDWR, Mode::from_raw_mode(0))?; + unsafe { libc::ioctl(lfd.as_raw_fd(), 0x4C00, source.as_ptr()) }; + let loop_info: LoopInfo = unsafe { std::mem::zeroed() }; + unsafe { libc::ioctl(lfd.as_raw_fd(), 0x4C02, &loop_info as *const _) }; + 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, + MoveMountFlags::MOVE_MOUNT_F_EMPTY_PATH, + )?; + Ok(Self { + target: target.to_string(), + auto_umount, + }) } #[cfg(not(any(target_os = "linux", target_os = "android")))] @@ -66,18 +111,8 @@ impl AutoMountExt4 { #[cfg(any(target_os = "linux", target_os = "android"))] pub fn umount(&self) -> Result<()> { - if let Some(ref mount) = self.mount { - mount - .unmount(UnmountFlags::empty()) - .map_err(|e| anyhow::anyhow!(e)) - } else { - let result = std::process::Command::new("umount").arg(&self.mnt).status(); - if let Err(e) = result { - Err(anyhow::anyhow!("umount: {} failed: {e}", self.mnt)) - } else { - Ok(()) - } - } + unmount(self.target.as_str(), UnmountFlags::DETACH)?; + Ok(()) } } @@ -86,7 +121,7 @@ impl Drop for AutoMountExt4 { fn drop(&mut self) { log::info!( "AutoMountExt4 drop: {}, auto_umount: {}", - self.mnt, + self.target, self.auto_umount ); if self.auto_umount { @@ -98,18 +133,7 @@ impl Drop for AutoMountExt4 { #[allow(dead_code)] #[cfg(any(target_os = "linux", target_os = "android"))] fn mount_image(src: &str, target: &str, autodrop: bool) -> Result<()> { - if autodrop { - Mount::builder() - .fstype(FilesystemType::from("ext4")) - .create_loop(true) - .mount_autodrop(src, target, UnmountFlags::empty()) - .with_context(|| format!("Failed to do mount: {src} -> {target}"))?; - } else { - Mount::builder() - .fstype(FilesystemType::from("ext4")) - .mount(src, target) - .with_context(|| format!("Failed to do mount: {src} -> {target}"))?; - } + AutoMountExt4::try_new(src, target, autodrop)?; Ok(()) } @@ -146,28 +170,37 @@ fn mount_overlayfs( dest.as_ref().display(), options ); - Mount::builder() - .fstype(FilesystemType::from("overlay")) - .data(&options) - .flags(MountFlags::RDONLY) - .mount(KSU_OVERLAY_SOURCE, dest.as_ref()) - .with_context(|| { - format!( - "mount overlayfs on {} options {} failed", - dest.as_ref().display(), - options - ) - })?; + let fs = fsopen("overlay", FsOpenFlags::FSOPEN_CLOEXEC)?; + let fs = fs.as_fd(); + fsconfig_set_string(fs, "lowerdir", lower_dirs.join(":"))?; + 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, + )?; Ok(()) } #[cfg(any(target_os = "linux", target_os = "android"))] pub fn mount_tmpfs(dest: impl AsRef) -> Result<()> { info!("mount tmpfs on {}", dest.as_ref().display()); - Mount::builder() - .fstype(FilesystemType::from("tmpfs")) - .mount(KSU_OVERLAY_SOURCE, dest.as_ref()) - .with_context(|| format!("mount tmpfs on {} failed", 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, + )?; Ok(()) } @@ -178,16 +211,12 @@ fn bind_mount(from: impl AsRef, to: impl AsRef) -> Result<()> { from.as_ref().display(), to.as_ref().display() ); - Mount::builder() - .flags(MountFlags::BIND) - .mount(from.as_ref(), to.as_ref()) - .with_context(|| { - format!( - "bind mount failed: {} -> {}", - from.as_ref().display(), - to.as_ref().display() - ) - })?; + let tree = open_tree( + CWD, + from.as_ref(), + OpenTreeFlags::OPEN_TREE_CLOEXEC | OpenTreeFlags::OPEN_TREE_CLONE, + )?; + move_mount(tree.as_fd(), "", CWD, to.as_ref(), MoveMountFlags::empty())?; Ok(()) }