Introduce mount helper methods

This commit is contained in:
topjohnwu
2025-03-24 15:17:21 -07:00
committed by John Wu
parent c09a792958
commit e0a356b319
6 changed files with 132 additions and 132 deletions

View File

@@ -21,6 +21,7 @@ mod dir;
mod files;
mod logging;
mod misc;
mod mount;
mod result;
mod xwrap;

62
native/src/base/mount.rs Normal file
View File

@@ -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()
}
}
}

View File

@@ -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()?;
};
}

View File

@@ -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);
}
}

View File

@@ -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());

View File

@@ -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();
}
}
}