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",
"cxx-gen", "cxx-gen",
"magiskpolicy", "magiskpolicy",
"num-traits",
] ]
[[package]] [[package]]

View File

@@ -23,4 +23,4 @@ bytemuck = { workspace = true }
num-traits = { workspace = true } num-traits = { workspace = true }
num-derive = { workspace = true } num-derive = { workspace = true }
const_format = { 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) } unsafe { CStr::from_bytes_with_nul_unchecked(&self.0) }
} }
#[inline(always)]
pub fn as_utf8_cstr(&self) -> &Utf8CStr {
self
}
#[inline(always)] #[inline(always)]
pub fn as_str(&self) -> &str { pub fn as_str(&self) -> &str {
// SAFETY: Already UTF-8 validated during construction // SAFETY: Already UTF-8 validated during construction

View File

@@ -1,91 +1,84 @@
use crate::{LibcReturn, OsResult, Utf8CStr}; use crate::{LibcReturn, OsResult, Utf8CStr};
use libc::c_ulong; use nix::mount::{MntFlags, MsFlags, mount, umount2};
use std::ptr;
impl Utf8CStr { impl Utf8CStr {
pub fn bind_mount_to<'a>(&'a self, path: &'a Utf8CStr, rec: bool) -> OsResult<'a, ()> { pub fn bind_mount_to<'a>(&'a self, path: &'a Utf8CStr, rec: bool) -> OsResult<'a, ()> {
let flag = if rec { libc::MS_REC } else { 0 }; let flag = if rec {
unsafe { MsFlags::MS_REC
libc::mount( } else {
self.as_ptr(), MsFlags::empty()
path.as_ptr(), };
ptr::null(), mount(
libc::MS_BIND | flag, Some(self),
ptr::null(), path,
) None::<&Utf8CStr>,
.check_os_err("bind_mount", Some(self), Some(path)) 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<'_, ()> { pub fn remount_mount_point_flags(&self, flags: MsFlags) -> OsResult<'_, ()> {
unsafe { mount(
libc::mount( None::<&Utf8CStr>,
ptr::null(), self,
self.as_ptr(), None::<&Utf8CStr>,
ptr::null(), MsFlags::MS_BIND | MsFlags::MS_REMOUNT | flags,
libc::MS_BIND | libc::MS_REMOUNT | flags, None::<&Utf8CStr>,
ptr::null(), )
) .check_os_err("remount", Some(self), None)
.check_os_err("remount", Some(self), None)
}
} }
pub fn remount_mount_flags(&self, flags: c_ulong) -> OsResult<'_, ()> { pub fn remount_mount_flags(&self, flags: MsFlags) -> OsResult<'_, ()> {
unsafe { mount(
libc::mount( None::<&Utf8CStr>,
ptr::null(), self,
self.as_ptr(), None::<&Utf8CStr>,
ptr::null(), MsFlags::MS_REMOUNT | flags,
libc::MS_REMOUNT | flags, None::<&Utf8CStr>,
ptr::null(), )
) .check_os_err("remount", Some(self), None)
.check_os_err("remount", Some(self), None)
}
} }
pub fn remount_with_data(&self, data: &Utf8CStr) -> OsResult<'_, ()> { pub fn remount_with_data(&self, data: &Utf8CStr) -> OsResult<'_, ()> {
unsafe { mount(
libc::mount( None::<&Utf8CStr>,
ptr::null(), self,
self.as_ptr(), None::<&Utf8CStr>,
ptr::null(), MsFlags::MS_REMOUNT,
libc::MS_REMOUNT, Some(data),
data.as_ptr().cast(), )
) .check_os_err("remount", Some(self), None)
.check_os_err("remount", Some(self), None)
}
} }
pub fn move_mount_to<'a>(&'a self, path: &'a Utf8CStr) -> OsResult<'a, ()> { pub fn move_mount_to<'a>(&'a self, path: &'a Utf8CStr) -> OsResult<'a, ()> {
unsafe { mount(
libc::mount( Some(self),
self.as_ptr(), path,
path.as_ptr(), None::<&Utf8CStr>,
ptr::null(), MsFlags::MS_MOVE,
libc::MS_MOVE, None::<&Utf8CStr>,
ptr::null(), )
) .check_os_err("move_mount", Some(self), Some(path))
.check_os_err("move_mount", Some(self), Some(path))
}
} }
pub fn unmount(&self) -> OsResult<'_, ()> { pub fn unmount(&self) -> OsResult<'_, ()> {
unsafe { umount2(self, MntFlags::MNT_DETACH).check_os_err("unmount", Some(self), None)
libc::umount2(self.as_ptr(), libc::MNT_DETACH).check_os_err("unmount", Some(self), None)
}
} }
pub fn set_mount_private(&self, recursive: bool) -> OsResult<'_, ()> { pub fn set_mount_private(&self, rec: bool) -> OsResult<'_, ()> {
let flag = if recursive { libc::MS_REC } else { 0 }; let flag = if rec {
unsafe { MsFlags::MS_REC
libc::mount( } else {
ptr::null(), MsFlags::empty()
self.as_ptr(), };
ptr::null(), mount(
libc::MS_PRIVATE | flag, None::<&Utf8CStr>,
ptr::null(), self,
) None::<&Utf8CStr>,
.check_os_err("set_mount_private", Some(self), None) 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 } thiserror = { workspace = true }
bit-set = { workspace = true } bit-set = { workspace = true }
argh = { 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, cstr, error, info, libc,
}; };
use nix::fcntl::OFlag; use nix::fcntl::OFlag;
use nix::mount::MsFlags;
use std::fmt::Write as FmtWrite; use std::fmt::Write as FmtWrite;
use std::fs::File; use std::fs::File;
use std::io::{BufReader, Write}; use std::io::{BufReader, Write};
@@ -384,7 +385,7 @@ pub fn daemon_entry() {
// Remount rootfs as read-only if requested // Remount rootfs as read-only if requested
if std::env::var_os("REMOUNT_ROOT").is_some() { 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") }; 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, Utf8CStrBuf, Utf8CString, WalkResult, clone_attr, cstr, debug, error, info, libc, raw_cstr,
warn, warn,
}; };
use libc::MS_RDONLY; use nix::{fcntl::OFlag, mount::MsFlags, unistd::UnlinkatFlags};
use nix::{fcntl::OFlag, unistd::UnlinkatFlags};
use std::collections::BTreeMap; use std::collections::BTreeMap;
use std::os::fd::IntoRawFd; use std::os::fd::IntoRawFd;
use std::path::{Component, Path}; 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 // 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. // kernel limitations, don't let it break module mount entirely.
src.bind_mount_to(dest, rec).log_ok(); 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>( fn mount_dummy<'a>(

View File

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

View File

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

View File

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