Enable mount for nix

This commit is contained in:
topjohnwu
2025-09-09 20:17:09 -07:00
parent 8d28f10a3f
commit c8caaa98f5
11 changed files with 126 additions and 134 deletions

1
native/src/Cargo.lock generated
View File

@@ -694,6 +694,7 @@ dependencies = [
"cxx",
"cxx-gen",
"magiskpolicy",
"num-traits",
]
[[package]]

View File

@@ -23,4 +23,4 @@ bytemuck = { workspace = true }
num-traits = { workspace = true }
num-derive = { workspace = true }
const_format = { workspace = true }
nix = { workspace = true, features = ["fs"] }
nix = { workspace = true, features = ["fs", "mount"] }

View File

@@ -335,6 +335,11 @@ impl Utf8CStr {
unsafe { CStr::from_bytes_with_nul_unchecked(&self.0) }
}
#[inline(always)]
pub fn as_utf8_cstr(&self) -> &Utf8CStr {
self
}
#[inline(always)]
pub fn as_str(&self) -> &str {
// SAFETY: Already UTF-8 validated during construction

View File

@@ -1,91 +1,84 @@
use crate::{LibcReturn, OsResult, Utf8CStr};
use libc::c_ulong;
use std::ptr;
use nix::mount::{MntFlags, MsFlags, mount, umount2};
impl Utf8CStr {
pub fn bind_mount_to<'a>(&'a self, path: &'a Utf8CStr, rec: bool) -> OsResult<'a, ()> {
let flag = if rec { libc::MS_REC } else { 0 };
unsafe {
libc::mount(
self.as_ptr(),
path.as_ptr(),
ptr::null(),
libc::MS_BIND | flag,
ptr::null(),
)
.check_os_err("bind_mount", Some(self), Some(path))
}
let flag = if rec {
MsFlags::MS_REC
} else {
MsFlags::empty()
};
mount(
Some(self),
path,
None::<&Utf8CStr>,
flag | MsFlags::MS_BIND,
None::<&Utf8CStr>,
)
.check_os_err("bind_mount", Some(self), Some(path))
}
pub fn remount_mount_point_flags(&self, flags: c_ulong) -> OsResult<'_, ()> {
unsafe {
libc::mount(
ptr::null(),
self.as_ptr(),
ptr::null(),
libc::MS_BIND | libc::MS_REMOUNT | flags,
ptr::null(),
)
.check_os_err("remount", Some(self), None)
}
pub fn remount_mount_point_flags(&self, flags: MsFlags) -> OsResult<'_, ()> {
mount(
None::<&Utf8CStr>,
self,
None::<&Utf8CStr>,
MsFlags::MS_BIND | MsFlags::MS_REMOUNT | flags,
None::<&Utf8CStr>,
)
.check_os_err("remount", Some(self), None)
}
pub fn remount_mount_flags(&self, flags: c_ulong) -> OsResult<'_, ()> {
unsafe {
libc::mount(
ptr::null(),
self.as_ptr(),
ptr::null(),
libc::MS_REMOUNT | flags,
ptr::null(),
)
.check_os_err("remount", Some(self), None)
}
pub fn remount_mount_flags(&self, flags: MsFlags) -> OsResult<'_, ()> {
mount(
None::<&Utf8CStr>,
self,
None::<&Utf8CStr>,
MsFlags::MS_REMOUNT | flags,
None::<&Utf8CStr>,
)
.check_os_err("remount", Some(self), None)
}
pub fn remount_with_data(&self, data: &Utf8CStr) -> OsResult<'_, ()> {
unsafe {
libc::mount(
ptr::null(),
self.as_ptr(),
ptr::null(),
libc::MS_REMOUNT,
data.as_ptr().cast(),
)
.check_os_err("remount", Some(self), None)
}
mount(
None::<&Utf8CStr>,
self,
None::<&Utf8CStr>,
MsFlags::MS_REMOUNT,
Some(data),
)
.check_os_err("remount", Some(self), None)
}
pub fn move_mount_to<'a>(&'a self, path: &'a Utf8CStr) -> OsResult<'a, ()> {
unsafe {
libc::mount(
self.as_ptr(),
path.as_ptr(),
ptr::null(),
libc::MS_MOVE,
ptr::null(),
)
.check_os_err("move_mount", Some(self), Some(path))
}
mount(
Some(self),
path,
None::<&Utf8CStr>,
MsFlags::MS_MOVE,
None::<&Utf8CStr>,
)
.check_os_err("move_mount", Some(self), Some(path))
}
pub fn unmount(&self) -> OsResult<'_, ()> {
unsafe {
libc::umount2(self.as_ptr(), libc::MNT_DETACH).check_os_err("unmount", Some(self), None)
}
umount2(self, MntFlags::MNT_DETACH).check_os_err("unmount", Some(self), None)
}
pub fn set_mount_private(&self, recursive: bool) -> OsResult<'_, ()> {
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(),
)
.check_os_err("set_mount_private", Some(self), None)
}
pub fn set_mount_private(&self, rec: bool) -> OsResult<'_, ()> {
let flag = if rec {
MsFlags::MS_REC
} else {
MsFlags::empty()
};
mount(
None::<&Utf8CStr>,
self,
None::<&Utf8CStr>,
flag | MsFlags::MS_PRIVATE,
None::<&Utf8CStr>,
)
.check_os_err("set_mount_private", Some(self), None)
}
}

View File

@@ -26,4 +26,4 @@ bytemuck = { workspace = true, features = ["derive"] }
thiserror = { workspace = true }
bit-set = { workspace = true }
argh = { workspace = true }
nix = { workspace = true, features = ["fs", "poll", "signal", "term", "zerocopy"] }
nix = { workspace = true, features = ["fs", "mount", "poll", "signal", "term", "zerocopy"] }

View File

@@ -23,6 +23,7 @@ use base::{
cstr, error, info, libc,
};
use nix::fcntl::OFlag;
use nix::mount::MsFlags;
use std::fmt::Write as FmtWrite;
use std::fs::File;
use std::io::{BufReader, Write};
@@ -384,7 +385,7 @@ pub fn daemon_entry() {
// Remount rootfs as read-only if requested
if std::env::var_os("REMOUNT_ROOT").is_some() {
cstr!("/").remount_mount_flags(libc::MS_RDONLY).log_ok();
cstr!("/").remount_mount_flags(MsFlags::MS_RDONLY).log_ok();
unsafe { std::env::remove_var("REMOUNT_ROOT") };
}

View File

@@ -8,8 +8,7 @@ use base::{
Utf8CStrBuf, Utf8CString, WalkResult, clone_attr, cstr, debug, error, info, libc, raw_cstr,
warn,
};
use libc::MS_RDONLY;
use nix::{fcntl::OFlag, unistd::UnlinkatFlags};
use nix::{fcntl::OFlag, mount::MsFlags, unistd::UnlinkatFlags};
use std::collections::BTreeMap;
use std::os::fd::IntoRawFd;
use std::path::{Component, Path};
@@ -40,7 +39,7 @@ fn bind_mount(reason: &str, src: &Utf8CStr, dest: &Utf8CStr, rec: bool) {
// Ignore any kind of error here. If a single bind mount fails due to selinux permissions or
// kernel limitations, don't let it break module mount entirely.
src.bind_mount_to(dest, rec).log_ok();
dest.remount_mount_point_flags(MS_RDONLY).log_ok();
dest.remount_mount_point_flags(MsFlags::MS_RDONLY).log_ok();
}
fn mount_dummy<'a>(

View File

@@ -1,19 +1,17 @@
use std::{
cmp::Ordering::{Greater, Less},
path::{Path, PathBuf},
};
use num_traits::AsPrimitive;
use base::libc::{c_uint, dev_t};
use crate::consts::{MODULEMNT, MODULEROOT, PREINITDEV, PREINITMIRR, WORKERDIR};
use crate::ffi::{get_magisk_tmp, resolve_preinit_dir, switch_mnt_ns};
use crate::resetprop::get_prop;
use base::{
FsPathBuilder, LibcReturn, LoggedResult, MountInfo, ResultExt, Utf8CStr, Utf8CStrBuf, cstr,
debug, info, libc, parse_mount_info, warn,
};
use crate::consts::{MODULEMNT, MODULEROOT, PREINITDEV, PREINITMIRR, WORKERDIR};
use crate::ffi::{get_magisk_tmp, resolve_preinit_dir, switch_mnt_ns};
use crate::resetprop::get_prop;
use libc::{c_uint, dev_t};
use nix::{
mount::MsFlags,
sys::stat::{Mode, SFlag, mknod},
};
use num_traits::AsPrimitive;
use std::{cmp::Ordering::Greater, cmp::Ordering::Less, path::Path, path::PathBuf};
pub fn setup_preinit_dir() {
let magisk_tmp = get_magisk_tmp();
@@ -69,7 +67,7 @@ pub fn setup_module_mount() {
let _: LoggedResult<()> = try {
module_mnt.mkdir(0o755)?;
cstr!(MODULEROOT).bind_mount_to(&module_mnt, false)?;
module_mnt.remount_mount_point_flags(libc::MS_RDONLY)?;
module_mnt.remount_mount_point_flags(MsFlags::MS_RDONLY)?;
};
}
@@ -194,15 +192,14 @@ pub fn find_preinit_device() -> String {
if std::env::var_os("MAKEDEV").is_some() {
buf.clear();
let dev_path = buf.append_path(&tmp).append_path(PREINITDEV);
unsafe {
libc::mknod(
dev_path.as_ptr(),
libc::S_IFBLK | 0o600,
info.device as dev_t,
)
.check_os_err("mknod", Some(dev_path), None)
.log_ok();
}
mknod(
dev_path.as_utf8_cstr(),
SFlag::S_IFBLK,
Mode::from_bits_truncate(0o600),
info.device as dev_t,
)
.check_os_err("mknod", Some(dev_path), None)
.log_ok();
}
}
Path::new(&info.source)
@@ -248,10 +245,8 @@ pub fn revert_unmount(pid: i32) {
for mut target in targets {
let target = Utf8CStr::from_string(&mut target);
unsafe {
if libc::umount2(target.as_ptr(), libc::MNT_DETACH) == 0 {
debug!("denylist: Unmounted ({})", target);
}
if target.unmount().is_ok() {
debug!("denylist: Unmounted ({})", target);
}
}
}

View File

@@ -14,3 +14,4 @@ cxx-gen = { workspace = true }
base = { path = "../base" }
magiskpolicy = { path = "../sepolicy", default-features = false }
cxx = { workspace = true }
num-traits = { workspace = true }

View File

@@ -1,12 +1,15 @@
use crate::ffi::MagiskInit;
use base::libc::{TMPFS_MAGIC, statfs};
use base::{
Directory, FsPathBuilder, LibcReturn, LoggedResult, ResultExt, Utf8CStr, cstr, debug, libc,
libc::{chdir, chroot, execve, exit, mount},
parse_mount_info, raw_cstr,
nix, parse_mount_info, raw_cstr,
};
use cxx::CxxString;
use std::ffi::c_long;
use nix::{
mount::MsFlags,
sys::statfs::{FsType, TMPFS_MAGIC, statfs},
unistd::{chdir, chroot},
};
use num_traits::AsPrimitive;
use std::{
collections::BTreeSet,
ops::Bound::{Excluded, Unbounded},
@@ -43,11 +46,9 @@ pub(crate) fn switch_root(path: &Utf8CStr) {
target.move_mount_to(&new_path)?;
mounts.insert(info.target);
}
unsafe {
chdir(path.as_ptr()).check_err()?;
path.move_mount_to(cstr!("/"))?;
chroot(raw_cstr!("."));
}
chdir(path)?;
path.move_mount_to(cstr!("/"))?;
chroot(cstr!("."))?;
debug!("Cleaning rootfs");
rootfs.remove_all()?;
@@ -65,13 +66,13 @@ pub(crate) fn is_device_mounted(dev: u64, target: Pin<&mut CxxString>) -> bool {
false
}
const RAMFS_MAGIC: u64 = 0x858458f6;
const RAMFS_MAGIC: u32 = 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
if let Ok(s) = statfs(cstr!("/")) {
s.filesystem_type() == FsType(RAMFS_MAGIC.as_()) || s.filesystem_type() == TMPFS_MAGIC
} else {
false
}
}
@@ -79,23 +80,19 @@ impl MagiskInit {
pub(crate) fn prepare_data(&self) {
debug!("Setup data tmp");
cstr!("/data").mkdir(0o755).log_ok();
unsafe {
mount(
raw_cstr!("magisk"),
raw_cstr!("/data"),
raw_cstr!("tmpfs"),
0,
raw_cstr!("mode=755").cast(),
)
}
.check_err()
nix::mount::mount(
Some(cstr!("magisk")),
cstr!("/data"),
Some(cstr!("tmpfs")),
MsFlags::empty(),
Some(cstr!("mode=755")),
)
.check_os_err("mount", Some("/data"), Some("tmpfs"))
.log_ok();
cstr!("/init").copy_to(cstr!("/data/magiskinit")).log_ok();
cstr!("/.backup").copy_to(cstr!("/data/.backup")).log_ok();
cstr!("/overlay.d")
.copy_to(cstr!("/data/overlay.d"))
.log_ok();
cstr!("/init").copy_to(cstr!("/data/magiskinit")).ok();
cstr!("/.backup").copy_to(cstr!("/data/.backup")).ok();
cstr!("/overlay.d").copy_to(cstr!("/data/overlay.d")).ok();
}
pub(crate) fn exec_init(&mut self) {
@@ -106,10 +103,10 @@ impl MagiskInit {
}
}
unsafe {
execve(raw_cstr!("/init"), self.argv.cast(), environ.cast())
libc::execve(raw_cstr!("/init"), self.argv.cast(), environ.cast())
.check_err()
.log_ok();
exit(1);
}
std::process::exit(1);
}
}