diff --git a/native/src/init/init.cpp b/native/src/init/init.cpp index 055d178e6..d875046ba 100644 --- a/native/src/init/init.cpp +++ b/native/src/init/init.cpp @@ -60,7 +60,7 @@ void restore_ramdisk_init() { } } -MagiskInit::MagiskInit(char **argv) : argv(argv), config{} { +void MagiskInit::init() noexcept { // Get kernel data using procfs and sysfs if (access("/proc/cmdline", F_OK) != 0) { xmkdir("/proc", 0755); @@ -86,7 +86,7 @@ static void recovery() { rm_rf("/.backup"); } -void MagiskInit::legacy_system_as_root() { +void MagiskInit::legacy_system_as_root() noexcept { LOGI("Legacy SAR Init\n"); prepare_data(); bool is_two_stage = mount_system_root(); @@ -96,7 +96,7 @@ void MagiskInit::legacy_system_as_root() { patch_ro_root(); } -void MagiskInit::rootfs() { +void MagiskInit::rootfs() noexcept { LOGI("RootFS Init\n"); prepare_data(); LOGD("Restoring /init\n"); @@ -104,7 +104,7 @@ void MagiskInit::rootfs() { patch_rw_root(); } -void MagiskInit::start() { +void MagiskInit::start() noexcept { if (argv[1] != nullptr && argv[1] == "selinux_setup"sv) second_stage(); else if (config.skip_initramfs) @@ -132,6 +132,5 @@ int main(int argc, char *argv[]) { if (getpid() != 1) return 1; - MagiskInit init(argv); - init.start(); + rust::start_magisk_init(argv); } diff --git a/native/src/init/init.hpp b/native/src/init/init.hpp index dbf3a3caf..b8aa65f6b 100644 --- a/native/src/init/init.hpp +++ b/native/src/init/init.hpp @@ -12,40 +12,3 @@ bool unxz(out_stream &strm, rust::Slice bytes); bool check_two_stage(); const char *backup_init(); void restore_ramdisk_init(); - -class MagiskInit { -private: - std::string preinit_dev; - std::vector mount_list; - char **argv; - BootConfig config; - - // Setup mounts and environment - void setup_tmp(const char *path); - void collect_devices(); - void mount_preinit_dir(); - void prepare_data(); - dev_t find_block(const char *partname); - bool mount_system_root(); - - // Setup and patch root directory - void parse_config_file(); - void patch_rw_root(); - void patch_ro_root(); - - // Two stage init - void redirect_second_stage(); - void first_stage(); - void second_stage(); - - // SELinux - void patch_sepolicy(const char *in, const char *out); - bool hijack_sepolicy(); - - [[noreturn]] void exec_init(); - void legacy_system_as_root(); - void rootfs(); -public: - explicit MagiskInit(char *argv[]); - void start(); -}; diff --git a/native/src/init/lib.rs b/native/src/init/lib.rs index 00567bd8c..94ef77ebc 100644 --- a/native/src/init/lib.rs +++ b/native/src/init/lib.rs @@ -7,6 +7,7 @@ use mount::{is_device_mounted, switch_root}; use rootdir::{collect_overlay_contexts, inject_magisk_rc, reset_overlay_contexts}; // Has to be pub so all symbols in that crate is included pub use magiskpolicy; +use crate::ffi::{BootConfig, MagiskInit}; mod logging; mod mount; @@ -31,6 +32,13 @@ pub mod ffi { partition_map: Vec, } + struct MagiskInit { + preinit_dev: String, + mount_list: Vec, + argv: *mut *mut c_char, + config: BootConfig, + } + #[namespace = "rust"] extern "Rust" { fn setup_klog(); @@ -39,6 +47,7 @@ pub mod ffi { fn is_device_mounted(dev: u64, target: Pin<&mut CxxString>) -> bool; fn collect_overlay_contexts(src: Utf8CStrRef); fn reset_overlay_contexts(); + unsafe fn start_magisk_init(argv: *mut *mut c_char); } unsafe extern "C++" { @@ -51,5 +60,53 @@ pub mod ffi { fn print(self: &BootConfig); type kv_pairs; fn set(self: &mut BootConfig, config: &kv_pairs); + + unsafe fn setup_tmp(self: &MagiskInit, path: *const c_char); + fn collect_devices(self: &MagiskInit); + fn mount_preinit_dir(self: &MagiskInit); + fn prepare_data(self: &MagiskInit); + unsafe fn find_block(self: &MagiskInit, partname: *const c_char) -> u64; + fn mount_system_root(self: &mut MagiskInit) -> bool; + + // Setup and patch root directory + fn parse_config_file(self: &mut MagiskInit); + fn patch_rw_root(self: &mut MagiskInit); + fn patch_ro_root(self: &mut MagiskInit); + + // Two stage init + fn redirect_second_stage(self: &MagiskInit); + fn first_stage(self: &MagiskInit); + fn second_stage(self: &mut MagiskInit); + + // SELinux + unsafe fn patch_sepolicy(self: &MagiskInit, in_: *const c_char, out: *const c_char); + fn hijack_sepolicy(self: &mut MagiskInit) -> bool; + fn exec_init(self: &MagiskInit); + fn legacy_system_as_root(self: &mut MagiskInit); + fn rootfs(self: &mut MagiskInit); + fn start(self: &mut MagiskInit); + fn init(self: &mut MagiskInit); } } + +pub(crate) fn start_magisk_init(argv: *mut *mut std::ffi::c_char) { + let mut init = MagiskInit { + preinit_dev: String::new(), + mount_list: Vec::new(), + argv, + config: BootConfig { + skip_initramfs: false, + force_normal_boot: false, + rootwait: false, + emulator: false, + slot: [0; 3], + dt_dir: [0; 64], + fstab_suffix: [0; 32], + hardware: [0; 32], + hardware_plat: [0; 32], + partition_map: Vec::new(), + }, + }; + init.init(); + init.start(); +} diff --git a/native/src/init/mount.cpp b/native/src/init/mount.cpp index b40bba317..92e2ae8ba 100644 --- a/native/src/init/mount.cpp +++ b/native/src/init/mount.cpp @@ -45,7 +45,7 @@ static void parse_device(devinfo *dev, const char *uevent) { }); } -void MagiskInit::collect_devices() { +void MagiskInit::collect_devices() const noexcept { char path[PATH_MAX]; devinfo dev{}; if (auto dir = xopen_dir("/sys/dev/block"); dir) { @@ -72,7 +72,7 @@ void MagiskInit::collect_devices() { } } -dev_t MagiskInit::find_block(const char *partname) { +uint64_t MagiskInit::find_block(const char *partname) const noexcept { if (dev_list.empty()) collect_devices(); @@ -103,7 +103,7 @@ dev_t MagiskInit::find_block(const char *partname) { return 0; } -void MagiskInit::mount_preinit_dir() { +void MagiskInit::mount_preinit_dir() const noexcept { if (preinit_dev.empty()) return; auto dev = find_block(preinit_dev.data()); if (dev == 0) { @@ -143,7 +143,7 @@ void MagiskInit::mount_preinit_dir() { } } -bool MagiskInit::mount_system_root() { +bool MagiskInit::mount_system_root() noexcept { LOGD("Mounting system_root\n"); // there's no /dev in stub cpio @@ -210,9 +210,10 @@ mount_root: return is_two_stage; } -void MagiskInit::exec_init() { +void MagiskInit::exec_init() const noexcept { // Unmount in reverse order - for (auto &p : reversed(mount_list)) { + for (auto i = mount_list.size(); i > 0; --i) { + auto &p = mount_list[i - 1]; if (xumount2(p.data(), MNT_DETACH) == 0) LOGD("Unmount [%s]\n", p.data()); } @@ -220,7 +221,7 @@ void MagiskInit::exec_init() { exit(1); } -void MagiskInit::prepare_data() { +void MagiskInit::prepare_data() const noexcept { LOGD("Setup data tmp\n"); xmkdir("/data", 0755); xmount("magisk", "/data", "tmpfs", 0, "mode=755"); @@ -230,7 +231,7 @@ void MagiskInit::prepare_data() { cp_afc("/overlay.d", "/data/overlay.d"); } -void MagiskInit::setup_tmp(const char *path) { +void MagiskInit::setup_tmp(const char *path) const noexcept { LOGD("Setup Magisk tmp at %s\n", path); chdir("/data"); diff --git a/native/src/init/rootdir.cpp b/native/src/init/rootdir.cpp index af85ee13b..c8df11f3a 100644 --- a/native/src/init/rootdir.cpp +++ b/native/src/init/rootdir.cpp @@ -257,17 +257,17 @@ static void extract_files(bool sbin) { } } -void MagiskInit::parse_config_file() { +void MagiskInit::parse_config_file() noexcept { parse_prop_file("/data/.backup/.magisk", [&](auto key, auto value) -> bool { if (key == "PREINITDEVICE") { - preinit_dev = value; + preinit_dev = std::string(value); return false; } return true; }); } -void MagiskInit::patch_ro_root() { +void MagiskInit::patch_ro_root() noexcept { mount_list.emplace_back("/data"); parse_config_file(); @@ -356,7 +356,7 @@ void MagiskInit::patch_ro_root() { #define PRE_TMPSRC "/magisk" #define PRE_TMPDIR PRE_TMPSRC "/tmp" -void MagiskInit::patch_rw_root() { +void MagiskInit::patch_rw_root() noexcept { mount_list.emplace_back("/data"); parse_config_file(); diff --git a/native/src/init/selinux.cpp b/native/src/init/selinux.cpp index 57325a002..218a2d8d3 100644 --- a/native/src/init/selinux.cpp +++ b/native/src/init/selinux.cpp @@ -7,7 +7,7 @@ using namespace std; -void MagiskInit::patch_sepolicy(const char *in, const char *out) { +void MagiskInit::patch_sepolicy(const char *in, const char *out) const noexcept { LOGD("Patching monolithic policy\n"); auto sepol = SePolicy::from_file(in); @@ -34,7 +34,7 @@ void MagiskInit::patch_sepolicy(const char *in, const char *out) { #define MOCK_LOAD SELINUXMOCK "/load" #define MOCK_ENFORCE SELINUXMOCK "/enforce" -bool MagiskInit::hijack_sepolicy() { +bool MagiskInit::hijack_sepolicy() noexcept { xmkdir(SELINUXMOCK, 0); if (access("/system/bin/init", F_OK) == 0) { @@ -76,10 +76,12 @@ bool MagiskInit::hijack_sepolicy() { LOGD("Hijack [%s]\n", buf); + decltype(mount_list) new_mount_list; // Preserve sysfs and procfs for hijacking - mount_list.erase(std::remove_if( - mount_list.begin(), mount_list.end(), - [](const string &s) { return s == "/proc" || s == "/sys"; }), mount_list.end()); + for (const auto &s: mount_list) + if (s != "/proc" && s != "/sys") + new_mount_list.emplace_back(s); + new_mount_list.swap(mount_list); mkfifo(MOCK_COMPAT, 0444); xmount(MOCK_COMPAT, buf, nullptr, MS_BIND, nullptr); diff --git a/native/src/init/twostage.cpp b/native/src/init/twostage.cpp index c9076cd4e..1684544f4 100644 --- a/native/src/init/twostage.cpp +++ b/native/src/init/twostage.cpp @@ -8,7 +8,7 @@ using namespace std; -void MagiskInit::first_stage() { +void MagiskInit::first_stage() const noexcept { LOGI("First Stage Init\n"); prepare_data(); @@ -45,7 +45,7 @@ void MagiskInit::first_stage() { } } -void MagiskInit::redirect_second_stage() { +void MagiskInit::redirect_second_stage() const noexcept { // Patch init binary int src = xopen("/init", O_RDONLY); int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0); @@ -62,7 +62,7 @@ void MagiskInit::redirect_second_stage() { xmount("/data/init", "/init", nullptr, MS_BIND, nullptr); } -void MagiskInit::second_stage() { +void MagiskInit::second_stage() noexcept { LOGI("Second Stage Init\n"); umount2("/init", MNT_DETACH); umount2(INIT_PATH, MNT_DETACH); // just in case