From 1a7079633931832041a7ab1b6579adb055fa9058 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 27 Feb 2024 03:14:26 -0800 Subject: [PATCH] Replace all parse_mount_info usage with Rust --- native/src/Cargo.lock | 181 +++++++++++++++++++++++++++++++------ native/src/Cargo.toml | 1 + native/src/base/cstr.rs | 20 +++- native/src/external/crt0 | 2 +- native/src/init/Cargo.toml | 1 + native/src/init/lib.rs | 4 + native/src/init/mount.cpp | 37 ++------ native/src/init/mount.rs | 93 +++++++++++++++++++ 8 files changed, 278 insertions(+), 61 deletions(-) create mode 100644 native/src/init/mount.rs diff --git a/native/src/Cargo.lock b/native/src/Cargo.lock index d92e310f4..3d935bce9 100644 --- a/native/src/Cargo.lock +++ b/native/src/Cargo.lock @@ -98,6 +98,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed570934406eb16438a4e976b1b4500774099c13b8cb96eec99f620f05090ddf" + [[package]] name = "block-buffer" version = "0.10.4" @@ -109,9 +115,9 @@ dependencies = [ [[package]] name = "bytemuck" -version = "1.14.1" +version = "1.14.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ed2490600f404f2b94c167e31d3ed1d5f3c225a0f3b80230053b3e0b7b962bd9" +checksum = "a2ef034f05691a48569bd920a96c81b9d91bbad1ab5ac7c4616c1f6ef36cb79f" dependencies = [ "bytemuck_derive", ] @@ -135,12 +141,9 @@ checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" [[package]] name = "cc" -version = "1.0.83" +version = "1.0.88" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" -dependencies = [ - "libc", -] +checksum = "02f341c093d19155a6e41631ce5971aac4e9a868262212153124c15fa22d1cdc" [[package]] name = "cfg-if" @@ -156,7 +159,7 @@ checksum = "a0610544180c38b88101fecf2dd634b174a62eef6946f84dfc6a7127512b381c" dependencies = [ "ansi_term", "atty", - "bitflags", + "bitflags 1.3.2", "strsim", "textwrap", "unicode-width", @@ -326,6 +329,16 @@ dependencies = [ "termcolor", ] +[[package]] +name = "errno" +version = "0.3.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a258e46cdc063eb8519c00b9fc845fc47bcfca4130e2f08e88665ceda8474245" +dependencies = [ + "libc", + "windows-sys", +] + [[package]] name = "fdt" version = "0.1.5" @@ -390,6 +403,12 @@ dependencies = [ "libc", ] +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + [[package]] name = "hkdf" version = "0.12.4" @@ -438,6 +457,12 @@ version = "0.2.8" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" +[[package]] +name = "linux-raw-sys" +version = "0.4.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "01cda141df6706de531b6c46c3a33ecca755538219bd484262fa09410c13539c" + [[package]] name = "log" version = "0.4.20" @@ -491,6 +516,7 @@ dependencies = [ "cxx", "cxx-gen", "magiskpolicy", + "procfs", ] [[package]] @@ -543,9 +569,9 @@ dependencies = [ [[package]] name = "num-derive" -version = "0.4.1" +version = "0.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "cfb77679af88f8b125209d354a202862602672222e7f2313fdd6dc349bad4712" +checksum = "ed3955f1a9c7c0c15e092f9c887db08b1fc683305fdf6eb6684f22555355e202" dependencies = [ "proc-macro2", "quote", @@ -554,19 +580,18 @@ dependencies = [ [[package]] name = "num-integer" -version = "0.1.45" +version = "0.1.46" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +checksum = "7969661fd2958a5cb096e56c8e1ad0444ac2bbcd0061bd28660485a44879858f" dependencies = [ - "autocfg", "num-traits", ] [[package]] name = "num-iter" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +checksum = "d869c01cc0c455284163fd0092f1f93835385ccab5a98a0dcc497b2f8bf055a9" dependencies = [ "autocfg", "num-integer", @@ -575,9 +600,9 @@ dependencies = [ [[package]] name = "num-traits" -version = "0.2.17" +version = "0.2.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +checksum = "da0df0e5185db44f69b44f26786fe401b6c293d1907744beaa7fa62b2e5a517a" dependencies = [ "autocfg", "libm", @@ -672,6 +697,29 @@ dependencies = [ "unicode-ident", ] +[[package]] +name = "procfs" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "731e0d9356b0c25f16f33b5be79b1c57b562f141ebfcdb0ad8ac2c13a24293b4" +dependencies = [ + "bitflags 2.4.2", + "hex", + "lazy_static", + "procfs-core", + "rustix", +] + +[[package]] +name = "procfs-core" +version = "0.16.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2d3554923a69f4ce04c4a754260c338f505ce22642d3830e049a399fc2059a29" +dependencies = [ + "bitflags 2.4.2", + "hex", +] + [[package]] name = "quick-error" version = "1.2.3" @@ -784,6 +832,19 @@ dependencies = [ "zeroize", ] +[[package]] +name = "rustix" +version = "0.38.31" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ea3e1a662af26cd7a3ba09c0297a31af215563ecf42817c98df621387f4e949" +dependencies = [ + "bitflags 2.4.2", + "errno", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "sec1" version = "0.7.3" @@ -800,18 +861,18 @@ dependencies = [ [[package]] name = "serde" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "870026e60fa08c69f064aa766c10f10b1d62db9ccd4d0abb206472bee0ce3b32" +checksum = "3fb1c873e1b9b056a4dc4c0c198b24c3ffa059243875552b2bd0933b1aee4ce2" dependencies = [ "serde_derive", ] [[package]] name = "serde_derive" -version = "1.0.196" +version = "1.0.197" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33c85360c95e7d137454dc81d9a4ed2b8efd8fbe19cee57357b32b9771fccb67" +checksum = "7eb0b34b42edc17f6b7cac84a52a1c5f0e1bb2227e997ca9011ea3dd34e8610b" dependencies = [ "proc-macro2", "quote", @@ -892,9 +953,9 @@ checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" [[package]] name = "syn" -version = "2.0.48" +version = "2.0.51" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f3531638e407dfc0814761abb7c00a5b54992b849452a0646b7f65c9f770f3f" +checksum = "6ab617d94515e94ae53b8406c628598680aa0c9587474ecbe58188f7b345d66c" dependencies = [ "proc-macro2", "quote", @@ -921,18 +982,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d54378c645627613241d077a3a79db965db602882668f9136ac42af9ecb730ad" +checksum = "1e45bcbe8ed29775f228095caf2cd67af7a4ccf756ebff23a306bf3e8b47b24b" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa0faa943b50f3db30a20aa7e265dbc66076993efed8463e8de414e5d06d3471" +checksum = "a953cb265bef375dae3de6663da4d3804eee9682ea80d8e2542529b73c531c81" dependencies = [ "proc-macro2", "quote", @@ -1027,6 +1088,72 @@ version = "0.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +[[package]] +name = "windows-sys" +version = "0.52.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "282be5f36a8ce781fad8c8ae18fa3f9beff57ec1b52cb3de0789201425d9a33d" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d380ba1dc7187569a8a9e91ed34b8ccfc33123bbacb8c0aed2d1ad7f3ef2dc5f" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "68e5dcfb9413f53afd9c8f86e56a7b4d86d9a2fa26090ea2dc9e40fba56c6ec6" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8dab469ebbc45798319e69eebf92308e541ce46760b49b18c6b3fe5e8965b30f" + +[[package]] +name = "windows_i686_gnu" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a4e9b6a7cac734a8b4138a4e1044eac3404d8326b6c0f939276560687a033fb" + +[[package]] +name = "windows_i686_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28b0ec9c422ca95ff34a78755cfa6ad4a51371da2a5ace67500cf7ca5f232c58" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "704131571ba93e89d7cd43482277d6632589b18ecf4468f591fbae0a8b101614" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42079295511643151e98d61c38c0acc444e52dd42ab456f7ccfd5152e8ecf21c" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.52.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0770833d60a970638e989b3fa9fd2bb1aaadcf88963d1659fd7d9990196ed2d6" + [[package]] name = "x509-cert" version = "0.2.5" diff --git a/native/src/Cargo.toml b/native/src/Cargo.toml index 8e38aaf4d..a333ba927 100644 --- a/native/src/Cargo.toml +++ b/native/src/Cargo.toml @@ -23,6 +23,7 @@ x509-cert = "0.2" der = "0.7" bytemuck = "1.14" fdt = "0.1" +procfs = { version = "0.16", default-features = false } [workspace.dependencies.argh] git = "https://github.com/google/argh.git" diff --git a/native/src/base/cstr.rs b/native/src/base/cstr.rs index ede577876..c408c794f 100644 --- a/native/src/base/cstr.rs +++ b/native/src/base/cstr.rs @@ -2,9 +2,10 @@ use std::cmp::min; use std::ffi::{CStr, FromBytesWithNulError, OsStr}; use std::fmt::{Arguments, Debug, Display, Formatter, Write}; use std::ops::{Deref, DerefMut}; -use std::path::Path; +use std::path::{Path, PathBuf}; use std::str::{Utf8Chunks, Utf8Error}; use std::{fmt, mem, slice, str}; +use std::os::unix::ffi::OsStrExt; use cxx::{type_id, ExternType}; use libc::c_char; @@ -105,7 +106,7 @@ trait AsUtf8CStr { // Implementation for Utf8CString -trait StringExt { +pub trait StringExt { fn nul_terminate(&mut self) -> &mut [u8]; } @@ -122,6 +123,21 @@ impl StringExt for String { } } +impl StringExt for PathBuf { + #[allow(mutable_transmutes)] + fn nul_terminate(&mut self) -> &mut [u8] { + self.reserve(1); + // SAFETY: the PathBuf is reserved to have enough capacity to fit in the null byte + // SAFETY: the null byte is explicitly added outside of the PathBuf's length + unsafe { + let bytes: &mut [u8] = mem::transmute(self.as_mut_os_str().as_bytes()); + let buf = slice::from_raw_parts_mut(bytes.as_mut_ptr(), bytes.len() + 1); + *buf.get_unchecked_mut(bytes.len()) = b'\0'; + buf + } + } +} + #[derive(Default)] pub struct Utf8CString(String); diff --git a/native/src/external/crt0 b/native/src/external/crt0 index ba8166a48..9790b7ee4 160000 --- a/native/src/external/crt0 +++ b/native/src/external/crt0 @@ -1 +1 @@ -Subproject commit ba8166a48cf9424d0fb46691c64467c20da7cdfe +Subproject commit 9790b7ee48d3c396c94ef69e164004f50a1f5587 diff --git a/native/src/init/Cargo.toml b/native/src/init/Cargo.toml index c1b541faa..12dc3700d 100644 --- a/native/src/init/Cargo.toml +++ b/native/src/init/Cargo.toml @@ -14,3 +14,4 @@ cxx-gen = { workspace = true } base = { path = "../base" } magiskpolicy = { path = "../sepolicy" } cxx = { workspace = true } +procfs = { workspace = true } diff --git a/native/src/init/lib.rs b/native/src/init/lib.rs index 77a8ee3df..d2ab22711 100644 --- a/native/src/init/lib.rs +++ b/native/src/init/lib.rs @@ -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) -> bool; } unsafe extern "C++" { diff --git a/native/src/init/mount.cpp b/native/src/init/mount.cpp index 15538cd26..69ab19363 100644 --- a/native/src/init/mount.cpp +++ b/native/src/init/mount.cpp @@ -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> 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 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"); diff --git a/native/src/init/mount.rs b/native/src/init/mount.rs new file mode 100644 index 000000000..0c804bd7d --- /dev/null +++ b/native/src/init/mount.rs @@ -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 = 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::((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) -> bool { + fn inner(dev: u64, mount_point: &mut Vec) -> 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::()); + 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() +}