You've already forked Magisk
mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-09-06 06:36:58 +00:00
Replace all parse_mount_info usage with Rust
This commit is contained in:
@@ -14,3 +14,4 @@ cxx-gen = { workspace = true }
|
||||
base = { path = "../base" }
|
||||
magiskpolicy = { path = "../sepolicy" }
|
||||
cxx = { workspace = true }
|
||||
procfs = { workspace = true }
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
#![feature(format_args_nl)]
|
||||
|
||||
use logging::setup_klog;
|
||||
use mount::{is_device_mounted, switch_root};
|
||||
use rootdir::inject_magisk_rc;
|
||||
// Has to be pub so all symbols in that crate is included
|
||||
pub use magiskpolicy;
|
||||
|
||||
mod logging;
|
||||
mod mount;
|
||||
mod rootdir;
|
||||
|
||||
#[cxx::bridge]
|
||||
@@ -14,6 +16,8 @@ pub mod ffi {
|
||||
extern "Rust" {
|
||||
fn setup_klog();
|
||||
fn inject_magisk_rc(fd: i32, tmp_dir: Utf8CStrRef);
|
||||
fn switch_root(path: Utf8CStrRef);
|
||||
fn is_device_mounted(dev: u64, mnt_point: &mut Vec<u8>) -> bool;
|
||||
}
|
||||
|
||||
unsafe extern "C++" {
|
||||
|
||||
@@ -100,29 +100,6 @@ static dev_t setup_block() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void switch_root(const string &path) {
|
||||
LOGD("Switch root to %s\n", path.data());
|
||||
int root = xopen("/", O_RDONLY);
|
||||
for (set<string, greater<>> mounts; auto &info : parse_mount_info("self")) {
|
||||
if (info.target == "/" || info.target == path)
|
||||
continue;
|
||||
if (auto last_mount = mounts.upper_bound(info.target);
|
||||
last_mount != mounts.end() && info.target.starts_with(*last_mount + '/')) {
|
||||
continue;
|
||||
}
|
||||
mounts.emplace(info.target);
|
||||
auto new_path = path + info.target;
|
||||
xmkdir(new_path.data(), 0755);
|
||||
xmount(info.target.data(), new_path.data(), nullptr, MS_MOVE, nullptr);
|
||||
}
|
||||
chdir(path.data());
|
||||
xmount(path.data(), "/", nullptr, MS_MOVE, nullptr);
|
||||
chroot(".");
|
||||
|
||||
LOGD("Cleaning rootfs\n");
|
||||
frm_rf(root);
|
||||
}
|
||||
|
||||
#define PREINITMNT MIRRDIR "/preinit"
|
||||
|
||||
static void mount_preinit_dir(string preinit_dev) {
|
||||
@@ -137,13 +114,11 @@ static void mount_preinit_dir(string preinit_dev) {
|
||||
xmkdir(PREINITMNT, 0);
|
||||
bool mounted = false;
|
||||
// First, find if it is already mounted
|
||||
for (auto &info : parse_mount_info("self")) {
|
||||
if (info.root == "/" && info.device == dev) {
|
||||
// Already mounted, just bind mount
|
||||
xmount(info.target.data(), PREINITMNT, nullptr, MS_BIND, nullptr);
|
||||
mounted = true;
|
||||
break;
|
||||
}
|
||||
rust::Vec<uint8_t> mnt_point;
|
||||
if (rust::is_device_mounted(dev, mnt_point)) {
|
||||
// Already mounted, just bind mount
|
||||
xmount((const char *) mnt_point.data(), PREINITMNT, nullptr, MS_BIND, nullptr);
|
||||
mounted = true;
|
||||
}
|
||||
|
||||
// Since we are mounting the block device directly, make sure to ONLY mount the partitions
|
||||
@@ -212,7 +187,7 @@ mount_root:
|
||||
}
|
||||
}
|
||||
|
||||
switch_root("/system_root");
|
||||
rust::switch_root("/system_root");
|
||||
|
||||
// Make dev writable
|
||||
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
|
||||
|
||||
@@ -0,0 +1,93 @@
|
||||
use std::collections::BTreeSet;
|
||||
use std::ops::Bound::{Excluded, Unbounded};
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::{fs, ptr};
|
||||
|
||||
use procfs::process::Process;
|
||||
|
||||
use base::{
|
||||
cstr, debug, libc, raw_cstr, Directory, LibcReturn, LoggedError, LoggedResult, StringExt,
|
||||
Utf8CStr,
|
||||
};
|
||||
|
||||
pub fn switch_root(path: &Utf8CStr) {
|
||||
fn inner(path: &Utf8CStr) -> LoggedResult<()> {
|
||||
debug!("Switching root to {}", path);
|
||||
let mut rootfs = Directory::open(cstr!("/"))?;
|
||||
|
||||
let procfs = Process::myself()?;
|
||||
let mut mounts: BTreeSet<PathBuf> = BTreeSet::new();
|
||||
for info in procfs.mountinfo()?.0.into_iter() {
|
||||
let mut target = info.mount_point;
|
||||
if target == Path::new("/") || target == Path::new(path) {
|
||||
continue;
|
||||
}
|
||||
let iter = mounts.range::<Path, _>((Unbounded, Excluded(target.as_path())));
|
||||
if let Some(last_mount) = iter.last() {
|
||||
if Path::new(path).starts_with(last_mount) {
|
||||
continue;
|
||||
}
|
||||
}
|
||||
let mut new_path = PathBuf::from(path);
|
||||
new_path.push(target.strip_prefix("/").unwrap());
|
||||
fs::create_dir(&new_path).ok(); /* Error is OK */
|
||||
unsafe {
|
||||
libc::mount(
|
||||
target.nul_terminate().as_ptr().cast(),
|
||||
new_path.nul_terminate().as_ptr().cast(),
|
||||
ptr::null(),
|
||||
libc::MS_MOVE,
|
||||
ptr::null(),
|
||||
)
|
||||
.as_os_err()?;
|
||||
}
|
||||
|
||||
// Record all moved paths
|
||||
mounts.insert(target);
|
||||
}
|
||||
|
||||
unsafe {
|
||||
libc::chdir(path.as_ptr()).as_os_err()?;
|
||||
libc::mount(
|
||||
path.as_ptr(),
|
||||
raw_cstr!("/"),
|
||||
ptr::null(),
|
||||
libc::MS_MOVE,
|
||||
ptr::null(),
|
||||
)
|
||||
.as_os_err()?;
|
||||
libc::chroot(raw_cstr!(".")).as_os_err()?;
|
||||
}
|
||||
|
||||
debug!("Cleaning rootfs");
|
||||
rootfs.remove_all()?;
|
||||
Ok(())
|
||||
}
|
||||
inner(path).ok();
|
||||
}
|
||||
|
||||
pub fn is_device_mounted(dev: u64, mnt_point: &mut Vec<u8>) -> bool {
|
||||
fn inner(dev: u64, mount_point: &mut Vec<u8>) -> LoggedResult<()> {
|
||||
let procfs = Process::myself()?;
|
||||
for mut info in procfs.mountinfo()?.0 {
|
||||
if info.root != "/" {
|
||||
continue;
|
||||
}
|
||||
let mut iter = info.majmin.split(':').map(|s| s.parse::<u32>());
|
||||
let maj = match iter.next() {
|
||||
Some(Ok(s)) => s,
|
||||
_ => continue,
|
||||
};
|
||||
let min = match iter.next() {
|
||||
Some(Ok(s)) => s,
|
||||
_ => continue,
|
||||
};
|
||||
if dev == libc::makedev(maj, min).into() {
|
||||
*mount_point = info.mount_point.nul_terminate().to_vec();
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Err(LoggedError::default())
|
||||
}
|
||||
inner(dev, mnt_point).is_ok()
|
||||
}
|
||||
Reference in New Issue
Block a user