diff --git a/native/src/base/lib.rs b/native/src/base/lib.rs index e6e3bedbd..e042e3d6f 100644 --- a/native/src/base/lib.rs +++ b/native/src/base/lib.rs @@ -21,6 +21,7 @@ mod dir; mod files; mod logging; mod misc; +mod mount; mod result; mod xwrap; diff --git a/native/src/base/mount.rs b/native/src/base/mount.rs new file mode 100644 index 000000000..a1076d15c --- /dev/null +++ b/native/src/base/mount.rs @@ -0,0 +1,62 @@ +use crate::{FsPath, LibcReturn}; +use libc::c_ulong; +use std::ptr; + +impl FsPath { + pub fn bind_mount_to(&self, path: &FsPath) -> std::io::Result<()> { + unsafe { + libc::mount( + self.as_ptr(), + path.as_ptr(), + ptr::null(), + libc::MS_BIND, + ptr::null(), + ) + .as_os_err() + } + } + + pub fn remount_with_flags(&self, flags: c_ulong) -> std::io::Result<()> { + unsafe { + libc::mount( + ptr::null(), + self.as_ptr(), + ptr::null(), + libc::MS_BIND | libc::MS_REMOUNT | flags, + ptr::null(), + ) + .as_os_err() + } + } + + pub fn move_mount_to(&self, path: &FsPath) -> std::io::Result<()> { + unsafe { + libc::mount( + self.as_ptr(), + path.as_ptr(), + ptr::null(), + libc::MS_MOVE, + ptr::null(), + ) + .as_os_err() + } + } + + pub fn unmount(&self) -> std::io::Result<()> { + unsafe { libc::umount2(self.as_ptr(), libc::MNT_DETACH).as_os_err() } + } + + pub fn set_mount_private(&self, recursive: bool) -> std::io::Result<()> { + let flag = if recursive { libc::MS_REC } else { 0 }; + unsafe { + libc::mount( + ptr::null(), + self.as_ptr(), + ptr::null(), + libc::MS_PRIVATE | flag, + ptr::null(), + ) + .as_os_err() + } + } +} diff --git a/native/src/core/mount.rs b/native/src/core/mount.rs index 0276648f5..084c11fe0 100644 --- a/native/src/core/mount.rs +++ b/native/src/core/mount.rs @@ -1,15 +1,14 @@ use std::{ cmp::Ordering::{Greater, Less}, path::{Path, PathBuf}, - ptr, }; use num_traits::AsPrimitive; use base::libc::{c_uint, dev_t}; use base::{ - cstr, cstr_buf, debug, info, libc, parse_mount_info, raw_cstr, warn, FsPath, FsPathBuf, - LibcReturn, LoggedResult, MountInfo, ResultExt, Utf8CStr, + FsPath, FsPathBuf, LibcReturn, LoggedResult, MountInfo, ResultExt, Utf8CStr, cstr, cstr_buf, + debug, info, libc, parse_mount_info, path, warn, }; use crate::consts::{MODULEMNT, MODULEROOT, PREINITDEV, PREINITMIRR, WORKERDIR}; @@ -73,24 +72,8 @@ pub fn setup_mounts() { let module_mnt = FsPathBuf::default().join(magisk_tmp).join(MODULEMNT); let _: LoggedResult<()> = try { module_mnt.mkdir(0o755)?; - unsafe { - libc::mount( - raw_cstr!(MODULEROOT), - module_mnt.as_ptr(), - ptr::null(), - libc::MS_BIND, - ptr::null(), - ) - .as_os_err()?; - libc::mount( - ptr::null(), - module_mnt.as_ptr(), - ptr::null(), - libc::MS_REMOUNT | libc::MS_BIND | libc::MS_RDONLY, - ptr::null(), - ) - .as_os_err()?; - } + path!(MODULEROOT).bind_mount_to(&module_mnt)?; + module_mnt.remount_with_flags(libc::MS_RDONLY)?; }; } @@ -98,26 +81,13 @@ pub fn clean_mounts() { let magisk_tmp = get_magisk_tmp(); let mut module_mnt = FsPathBuf::default().join(magisk_tmp).join(MODULEMNT); - let _: LoggedResult<()> = try { - unsafe { - libc::umount2(module_mnt.as_ptr(), libc::MNT_DETACH).as_os_err()?; - } - }; + module_mnt.unmount().log_ok(); module_mnt.clear(); let worker_dir = module_mnt.join(magisk_tmp).join(WORKERDIR); let _: LoggedResult<()> = try { - unsafe { - libc::mount( - ptr::null(), - worker_dir.as_ptr(), - ptr::null(), - libc::MS_PRIVATE | libc::MS_REC, - ptr::null(), - ) - .as_os_err()?; - libc::umount2(worker_dir.as_ptr(), libc::MNT_DETACH).as_os_err()?; - } + worker_dir.set_mount_private(true)?; + worker_dir.unmount()?; }; } diff --git a/native/src/init/mount.rs b/native/src/init/mount.rs index 957bb52c8..c38388e74 100644 --- a/native/src/init/mount.rs +++ b/native/src/init/mount.rs @@ -1,23 +1,23 @@ use crate::ffi::MagiskInit; +use base::libc::{TMPFS_MAGIC, statfs}; use base::{ - cstr, debug, libc, - libc::{chdir, chroot, execve, exit, mount, umount2, MNT_DETACH, MS_MOVE}, - parse_mount_info, path, raw_cstr, Directory, LibcReturn, LoggedResult, ResultExt, StringExt, - Utf8CStr, + Directory, FsPath, FsPathBuf, LibcReturn, LoggedResult, ResultExt, Utf8CStr, cstr, debug, libc, + libc::{chdir, chroot, execve, exit, mount}, + parse_mount_info, path, raw_cstr, }; use cxx::CxxString; +use std::ffi::c_long; use std::{ collections::BTreeSet, ops::Bound::{Excluded, Unbounded}, pin::Pin, - ptr::null as nullptr, }; unsafe extern "C" { static environ: *const *mut libc::c_char; } -pub fn switch_root(path: &Utf8CStr) { +pub(crate) fn switch_root(path: &Utf8CStr) { let res: LoggedResult<()> = try { debug!("Switch root to {}", path); let mut mounts = BTreeSet::new(); @@ -34,26 +34,19 @@ pub fn switch_root(path: &Utf8CStr) { continue; } } - let mut new_path = format!("{}/{}", path.as_str(), &info.target); - std::fs::create_dir(&new_path).ok(); - - unsafe { - let mut target = info.target.clone(); - mount( - target.nul_terminate().as_ptr().cast(), - new_path.nul_terminate().as_ptr().cast(), - nullptr(), - MS_MOVE, - nullptr(), - ) - .as_os_err()?; - } + let mut target = info.target.clone(); + let target = FsPath::from(Utf8CStr::from_string(&mut target)); + let new_path = FsPathBuf::default() + .join(path) + .join(info.target.trim_start_matches('/')); + new_path.mkdirs(0o755).ok(); + target.move_mount_to(&new_path)?; mounts.insert(info.target); } unsafe { chdir(path.as_ptr()).as_os_err()?; - mount(path.as_ptr(), raw_cstr!("/"), nullptr(), MS_MOVE, nullptr()).as_os_err()?; + FsPath::from(path).move_mount_to(path!("/"))?; chroot(raw_cstr!(".")); } @@ -63,7 +56,7 @@ pub fn switch_root(path: &Utf8CStr) { res.ok(); } -pub fn is_device_mounted(dev: u64, target: Pin<&mut CxxString>) -> bool { +pub(crate) fn is_device_mounted(dev: u64, target: Pin<&mut CxxString>) -> bool { for mount in parse_mount_info("self") { if mount.root == "/" && mount.device == dev { target.push_str(&mount.target); @@ -73,6 +66,16 @@ pub fn is_device_mounted(dev: u64, target: Pin<&mut CxxString>) -> bool { false } +const RAMFS_MAGIC: u64 = 0x858458f6; + +pub(crate) fn is_rootfs() -> bool { + unsafe { + let mut sfs: statfs = std::mem::zeroed(); + statfs(raw_cstr!("/"), &mut sfs); + sfs.f_type as u64 == RAMFS_MAGIC || sfs.f_type as c_long == TMPFS_MAGIC + } +} + impl MagiskInit { pub(crate) fn prepare_data(&self) { debug!("Setup data tmp"); @@ -96,21 +99,17 @@ impl MagiskInit { .log_ok(); } - pub(crate) fn exec_init(&self) { - unsafe { - for p in self.mount_list.iter().rev() { - if umount2(p.as_ptr().cast(), MNT_DETACH) - .as_os_err() - .log() - .is_ok() - { - debug!("Unmount [{}]", p); - } + pub(crate) fn exec_init(&mut self) { + for path in self.mount_list.iter_mut().rev() { + let path = FsPath::from(Utf8CStr::from_string(path)); + if path.unmount().log().is_ok() { + debug!("Unmount [{}]", path); } + } + unsafe { execve(raw_cstr!("/init"), self.argv.cast(), environ.cast()) .as_os_err() - .log() - .ok(); + .log_ok(); exit(1); } } diff --git a/native/src/init/rootdir.rs b/native/src/init/rootdir.rs index 92244d56a..ef6b0e323 100644 --- a/native/src/init/rootdir.rs +++ b/native/src/init/rootdir.rs @@ -2,8 +2,8 @@ use crate::consts::{ROOTMNT, ROOTOVL}; use crate::ffi::MagiskInit; use base::libc::{O_CREAT, O_RDONLY, O_WRONLY}; use base::{ - clone_attr, cstr, cstr_buf, debug, libc, path, BufReadExt, Directory, FsPath, FsPathBuf, - LibcReturn, LoggedResult, ResultExt, Utf8CStr, Utf8CString, + BufReadExt, Directory, FsPath, FsPathBuf, LoggedResult, ResultExt, Utf8CStr, Utf8CString, + clone_attr, cstr, cstr_buf, debug, path, }; use std::io::BufReader; use std::{ @@ -11,7 +11,6 @@ use std::{ io::Write, mem, os::fd::{FromRawFd, RawFd}, - ptr, }; pub fn inject_magisk_rc(fd: RawFd, tmp_dir: &Utf8CStr) { @@ -83,16 +82,7 @@ impl MagiskInit { debug!("Mount [{}] -> [{}]", src, dest); clone_attr(&dest, &src)?; dest.get_secontext(&mut con)?; - unsafe { - libc::mount( - src.as_ptr(), - dest.as_ptr(), - ptr::null(), - libc::MS_BIND, - ptr::null(), - ) - .as_os_err()?; - }; + src.bind_mount_to(&dest)?; self.overlay_con .push(OverlayAttr(dest.to_owned(), con.to_owned())); mount_list.push_str(dest.as_str()); diff --git a/native/src/init/twostage.rs b/native/src/init/twostage.rs index 2ea9db6d2..5df52e909 100644 --- a/native/src/init/twostage.rs +++ b/native/src/init/twostage.rs @@ -1,15 +1,11 @@ use crate::ffi::MagiskInit; +use crate::mount::is_rootfs; use base::{ - LibcReturn, LoggedResult, MappedFile, MutBytesExt, ResultExt, cstr, debug, error, info, - libc::{ - MNT_DETACH, MS_BIND, O_CLOEXEC, O_CREAT, O_RDONLY, O_WRONLY, TMPFS_MAGIC, mount, statfs, - umount2, - }, + LoggedResult, MappedFile, MutBytesExt, ResultExt, cstr, debug, error, info, + libc::{O_CLOEXEC, O_CREAT, O_RDONLY, O_WRONLY}, path, raw_cstr, }; -use std::{ffi::c_long, io::Write, ptr::null}; - -const RAMFS_MAGIC: u64 = 0x858458f6; +use std::io::Write; fn patch_init_path(init: &mut MappedFile) { let from = "/system/bin/init"; @@ -70,28 +66,13 @@ impl MagiskInit { path!("/init").rename_to(path!("/sdcard")).log_ok(); // First try to mount magiskinit from rootfs to workaround Samsung RKP - if unsafe { - mount( - raw_cstr!("/sdcard"), - raw_cstr!("/sdcard"), - null(), - MS_BIND, - null(), - ) - } == 0 - { + if path!("/sdcard").bind_mount_to(path!("/sdcard")).is_ok() { debug!("Bind mount /sdcard -> /sdcard"); } else { // Binding mounting from rootfs is not supported before Linux 3.12 - unsafe { - mount( - raw_cstr!("/data/magiskinit"), - raw_cstr!("/sdcard"), - null(), - MS_BIND, - null(), - ) - }; + path!("/data/magiskinit") + .bind_mount_to(path!("/sdcard")) + .log_ok(); debug!("Bind mount /data/magiskinit -> /sdcard"); } } @@ -139,36 +120,33 @@ impl MagiskInit { let _: LoggedResult<()> = try { let attr = src.follow_link().get_attr()?; dest.set_attr(&attr)?; - unsafe { - mount(dest.as_ptr(), src.as_ptr(), null(), MS_BIND, null()).as_os_err()?; - } + dest.bind_mount_to(src)?; }; } pub(crate) fn second_stage(&mut self) { info!("Second Stage Init"); - unsafe { - umount2(raw_cstr!("/init"), MNT_DETACH); - umount2(raw_cstr!("/system/bin/init"), MNT_DETACH); // just in case - path!("/data/init").remove().ok(); + path!("/init").unmount().ok(); + path!("/system/bin/init").unmount().ok(); // just in case + path!("/data/init").remove().ok(); + + unsafe { // Make sure init dmesg logs won't get messed up *self.argv = raw_cstr!("/system/bin/init") as *mut _; + } - // Some weird devices like meizu, uses 2SI but still have legacy rootfs - let mut sfs: statfs = std::mem::zeroed(); - statfs(raw_cstr!("/"), &mut sfs); - if sfs.f_type as u64 == RAMFS_MAGIC || sfs.f_type as c_long == TMPFS_MAGIC { - // We are still on rootfs, so make sure we will execute the init of the 2nd stage - let init_path = path!("/init"); - init_path.remove().ok(); - init_path - .create_symlink_to(path!("/system/bin/init")) - .log_ok(); - self.patch_rw_root(); - } else { - self.patch_ro_root(); - } + // Some weird devices like meizu, uses 2SI but still have legacy rootfs + if is_rootfs() { + // We are still on rootfs, so make sure we will execute the init of the 2nd stage + let init_path = path!("/init"); + init_path.remove().ok(); + init_path + .create_symlink_to(path!("/system/bin/init")) + .log_ok(); + self.patch_rw_root(); + } else { + self.patch_ro_root(); } } }