Move all MagiskInit entrypoints into init.rs

This commit is contained in:
topjohnwu 2025-03-24 16:44:32 -07:00 committed by John Wu
parent e0a356b319
commit 50af14f2a3
2 changed files with 83 additions and 91 deletions

View File

@ -1,10 +1,12 @@
use crate::ffi::backup_init; use crate::ffi::backup_init;
use crate::mount::is_rootfs;
use crate::twostage::hexpatch_init_for_second_stage;
use crate::{ use crate::{
ffi::{BootConfig, MagiskInit, magisk_proxy_main}, ffi::{BootConfig, MagiskInit, magisk_proxy_main},
logging::setup_klog, logging::setup_klog,
}; };
use base::{ use base::{
FsPath, LibcReturn, LoggedResult, ResultExt, debug, info, FsPath, LibcReturn, LoggedResult, ResultExt, info,
libc::{basename, getpid, mount, umask}, libc::{basename, getpid, mount, umask},
path, raw_cstr, path, raw_cstr,
}; };
@ -35,32 +37,71 @@ impl MagiskInit {
} }
} }
pub(crate) fn legacy_system_as_root(&mut self) { fn first_stage(&self) {
info!("Legacy SAR Init"); info!("First Stage Init");
self.prepare_data(); self.prepare_data();
let is_two_stage = self.mount_system_root();
if is_two_stage { if !path!("/sdcard").exists() && !path!("/first_stage_ramdisk/sdcard").exists() {
self.patch_init_for_second_stage(); 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 { } else {
self.patch_ro_root(); 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"); info!("RootFS Init");
self.prepare_data(); self.prepare_data();
debug!("Restoring /init\n"); self.restore_ramdisk_init();
path!("/.backup/init").rename_to(path!("/init")).log_ok();
self.patch_rw_root(); self.patch_rw_root();
} }
pub(crate) fn recovery(&self) { fn recovery(&self) {
info!("Ramdisk is recovery, abort"); info!("Ramdisk is recovery, abort");
self.restore_ramdisk_init(); self.restore_ramdisk_init();
path!("/.backup").remove_all().ok(); path!("/.backup").remove_all().ok();
} }
pub(crate) fn restore_ramdisk_init(&self) { fn restore_ramdisk_init(&self) {
path!("/init").remove().ok(); path!("/init").remove().ok();
let orig_init = FsPath::from(backup_init()); let orig_init = FsPath::from(backup_init());

View File

@ -1,26 +1,50 @@
use crate::ffi::MagiskInit; use crate::ffi::MagiskInit;
use crate::mount::is_rootfs;
use base::{ 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}, libc::{O_CLOEXEC, O_CREAT, O_RDONLY, O_WRONLY},
path, raw_cstr, path,
}; };
use std::io::Write; use std::io::Write;
fn patch_init_path(init: &mut MappedFile) { pub(crate) fn hexpatch_init_for_second_stage(writable: bool) {
let from = "/system/bin/init"; let init = if writable {
let to = "/data/magiskinit"; 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 // Redirect original init to magiskinit
let from = "/system/bin/init";
let to = "/data/magiskinit";
let v = init.patch(from.as_bytes(), to.as_bytes()); let v = init.patch(from.as_bytes(), to.as_bytes());
#[allow(unused_variables)] #[allow(unused_variables)]
for off in &v { for off in &v {
debug!("Patch @ {:#010X} [{}] -> [{}]", off, from, to); 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 { 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 // We make use of original init's `SwitchRoot` to help us bind mount
// magiskinit to /system/bin/init to hijack second stage init. // magiskinit to /system/bin/init to hijack second stage init.
// //
@ -76,77 +100,4 @@ impl MagiskInit {
debug!("Bind mount /data/magiskinit -> /sdcard"); 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();
}
}
} }