From 50af14f2a3f3d9380d04806a34a826dc8ad30388 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Mon, 24 Mar 2025 16:44:32 -0700 Subject: [PATCH] Move all MagiskInit entrypoints into init.rs --- native/src/init/init.rs | 63 ++++++++++++++++---- native/src/init/twostage.rs | 111 ++++++++++-------------------------- 2 files changed, 83 insertions(+), 91 deletions(-) diff --git a/native/src/init/init.rs b/native/src/init/init.rs index 482587d72..1299f5966 100644 --- a/native/src/init/init.rs +++ b/native/src/init/init.rs @@ -1,10 +1,12 @@ use crate::ffi::backup_init; +use crate::mount::is_rootfs; +use crate::twostage::hexpatch_init_for_second_stage; use crate::{ ffi::{BootConfig, MagiskInit, magisk_proxy_main}, logging::setup_klog, }; use base::{ - FsPath, LibcReturn, LoggedResult, ResultExt, debug, info, + FsPath, LibcReturn, LoggedResult, ResultExt, info, libc::{basename, getpid, mount, umask}, path, raw_cstr, }; @@ -35,32 +37,71 @@ impl MagiskInit { } } - pub(crate) fn legacy_system_as_root(&mut self) { - info!("Legacy SAR Init"); + fn first_stage(&self) { + info!("First Stage Init"); self.prepare_data(); - let is_two_stage = self.mount_system_root(); - if is_two_stage { - self.patch_init_for_second_stage(); + + if !path!("/sdcard").exists() && !path!("/first_stage_ramdisk/sdcard").exists() { + self.hijack_init_with_switch_root(); + self.restore_ramdisk_init(); + } else { + self.restore_ramdisk_init(); + // Fallback to hexpatch if /sdcard exists + hexpatch_init_for_second_stage(true); + } + } + + fn second_stage(&mut self) { + info!("Second Stage Init"); + + path!("/init").unmount().ok(); + path!("/system/bin/init").unmount().ok(); // just in case + path!("/data/init").remove().ok(); + + unsafe { + // Make sure init dmesg logs won't get messed up + *self.argv = raw_cstr!("/system/bin/init") as *mut _; + } + + // Some weird devices like meizu, uses 2SI but still have legacy rootfs + if is_rootfs() { + // We are still on rootfs, so make sure we will execute the init of the 2nd stage + let init_path = path!("/init"); + init_path.remove().ok(); + init_path + .create_symlink_to(path!("/system/bin/init")) + .log_ok(); + self.patch_rw_root(); } else { self.patch_ro_root(); } } - pub(crate) fn rootfs(&mut self) { + fn legacy_system_as_root(&mut self) { + info!("Legacy SAR Init"); + self.prepare_data(); + let is_two_stage = self.mount_system_root(); + if is_two_stage { + hexpatch_init_for_second_stage(false); + } else { + self.patch_ro_root(); + } + } + + fn rootfs(&mut self) { info!("RootFS Init"); self.prepare_data(); - debug!("Restoring /init\n"); - path!("/.backup/init").rename_to(path!("/init")).log_ok(); + self.restore_ramdisk_init(); self.patch_rw_root(); } - pub(crate) fn recovery(&self) { + fn recovery(&self) { info!("Ramdisk is recovery, abort"); self.restore_ramdisk_init(); path!("/.backup").remove_all().ok(); } - pub(crate) fn restore_ramdisk_init(&self) { + fn restore_ramdisk_init(&self) { path!("/init").remove().ok(); let orig_init = FsPath::from(backup_init()); diff --git a/native/src/init/twostage.rs b/native/src/init/twostage.rs index 5df52e909..44201c4b2 100644 --- a/native/src/init/twostage.rs +++ b/native/src/init/twostage.rs @@ -1,26 +1,50 @@ use crate::ffi::MagiskInit; -use crate::mount::is_rootfs; use base::{ - LoggedResult, MappedFile, MutBytesExt, ResultExt, cstr, debug, error, info, + LoggedResult, MappedFile, MutBytesExt, ResultExt, cstr, debug, error, libc::{O_CLOEXEC, O_CREAT, O_RDONLY, O_WRONLY}, - path, raw_cstr, + path, }; use std::io::Write; -fn patch_init_path(init: &mut MappedFile) { - let from = "/system/bin/init"; - let to = "/data/magiskinit"; +pub(crate) fn hexpatch_init_for_second_stage(writable: bool) { + let init = if writable { + MappedFile::open_rw(cstr!("/init")) + } else { + MappedFile::open(cstr!("/init")) + }; + + let Ok(mut init) = init else { + error!("Failed to open /init for hexpatch"); + return; + }; // Redirect original init to magiskinit + let from = "/system/bin/init"; + let to = "/data/magiskinit"; let v = init.patch(from.as_bytes(), to.as_bytes()); #[allow(unused_variables)] for off in &v { debug!("Patch @ {:#010X} [{}] -> [{}]", off, from, to); } + + if !writable { + // If we cannot directly modify /init, we need to bind mount a replacement on top of it + let src = path!("/init"); + let dest = path!("/data/init"); + let _: LoggedResult<()> = try { + { + let mut fd = dest.create(O_CREAT | O_WRONLY, 0)?; + fd.write_all(init.as_ref())?; + } + let attr = src.follow_link().get_attr()?; + dest.set_attr(&attr)?; + dest.bind_mount_to(src)?; + }; + } } impl MagiskInit { - fn hijack_init_with_switch_root(&self) { + pub(crate) fn hijack_init_with_switch_root(&self) { // We make use of original init's `SwitchRoot` to help us bind mount // magiskinit to /system/bin/init to hijack second stage init. // @@ -76,77 +100,4 @@ impl MagiskInit { debug!("Bind mount /data/magiskinit -> /sdcard"); } } - - pub(crate) fn first_stage(&self) { - info!("First Stage Init"); - self.prepare_data(); - - if !path!("/sdcard").exists() && !path!("/first_stage_ramdisk/sdcard").exists() { - self.hijack_init_with_switch_root(); - self.restore_ramdisk_init(); - } else { - self.restore_ramdisk_init(); - - // fallback to hexpatch if /sdcard exists - match MappedFile::open_rw(cstr!("/init")) { - Ok(mut map) => patch_init_path(&mut map), - _ => { - error!("Failed to open /init for hexpatch"); - } - } - } - } - - pub(crate) fn patch_init_for_second_stage(&self) { - let src = path!("/init"); - let dest = path!("/data/init"); - // Patch init binary - match MappedFile::open(src) { - Ok(mut map) => { - patch_init_path(&mut map); - match dest.create(O_CREAT | O_WRONLY, 0) { - Ok(mut dest) => { - dest.write_all(map.as_ref()).log_ok(); - } - _ => { - error!("Failed to create {}", dest); - } - } - } - _ => { - error!("Failed to open {} for hexpatch", src); - } - } - let _: LoggedResult<()> = try { - let attr = src.follow_link().get_attr()?; - dest.set_attr(&attr)?; - dest.bind_mount_to(src)?; - }; - } - - pub(crate) fn second_stage(&mut self) { - info!("Second Stage Init"); - - path!("/init").unmount().ok(); - path!("/system/bin/init").unmount().ok(); // just in case - path!("/data/init").remove().ok(); - - unsafe { - // Make sure init dmesg logs won't get messed up - *self.argv = raw_cstr!("/system/bin/init") as *mut _; - } - - // Some weird devices like meizu, uses 2SI but still have legacy rootfs - if is_rootfs() { - // We are still on rootfs, so make sure we will execute the init of the 2nd stage - let init_path = path!("/init"); - init_path.remove().ok(); - init_path - .create_symlink_to(path!("/system/bin/init")) - .log_ok(); - self.patch_rw_root(); - } else { - self.patch_ro_root(); - } - } }