mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-05-29 04:50:13 +02:00
Reorganize magiskinit code
This commit is contained in:
parent
0bbfe7f44d
commit
c09a792958
@ -1,11 +1,11 @@
|
||||
use crate::{
|
||||
cstr_buf, errno, error, Directory, FsPath, FsPathBuf, FsPathFollow, LibcReturn, Utf8CStr,
|
||||
Utf8CStrBuf,
|
||||
Directory, FsPath, FsPathBuf, FsPathFollow, LibcReturn, Utf8CStr, Utf8CStrBuf, cstr_buf, errno,
|
||||
error,
|
||||
};
|
||||
use bytemuck::{bytes_of, bytes_of_mut, Pod};
|
||||
use bytemuck::{Pod, bytes_of, bytes_of_mut};
|
||||
use libc::{
|
||||
c_uint, makedev, mode_t, stat, EEXIST, ENOENT, F_OK, O_CLOEXEC, O_CREAT, O_PATH, O_RDONLY,
|
||||
O_RDWR, O_TRUNC, O_WRONLY,
|
||||
EEXIST, ENOENT, F_OK, O_CLOEXEC, O_CREAT, O_PATH, O_RDONLY, O_RDWR, O_TRUNC, O_WRONLY, c_uint,
|
||||
makedev, mode_t, stat,
|
||||
};
|
||||
use mem::MaybeUninit;
|
||||
use num_traits::AsPrimitive;
|
||||
@ -400,6 +400,20 @@ impl FsPath {
|
||||
self.rename_to(path)
|
||||
}
|
||||
|
||||
pub fn parent(&self, buf: &mut dyn Utf8CStrBuf) -> bool {
|
||||
buf.clear();
|
||||
if let Some(parent) = Path::new(self.as_str()).parent() {
|
||||
let bytes = parent.as_os_str().as_bytes();
|
||||
// SAFETY: all substring of self is valid UTF-8
|
||||
let parent = unsafe { std::str::from_utf8_unchecked(bytes) };
|
||||
buf.push_str(parent);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
// ln self path
|
||||
pub fn link_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
let attr = self.get_attr()?;
|
||||
if attr.is_dir() {
|
||||
@ -413,21 +427,9 @@ impl FsPath {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn symlink_to(&self, path: &FsPath) -> io::Result<()> {
|
||||
unsafe { libc::symlink(self.as_ptr(), path.as_ptr()).as_os_err() }
|
||||
}
|
||||
|
||||
pub fn parent(&self, buf: &mut dyn Utf8CStrBuf) -> bool {
|
||||
buf.clear();
|
||||
if let Some(parent) = Path::new(self.as_str()).parent() {
|
||||
let bytes = parent.as_os_str().as_bytes();
|
||||
// SAFETY: all substring of self is valid UTF-8
|
||||
let parent = unsafe { std::str::from_utf8_unchecked(bytes) };
|
||||
buf.push_str(parent);
|
||||
true
|
||||
} else {
|
||||
false
|
||||
}
|
||||
// ln -s target self
|
||||
pub fn create_symlink_to(&self, target: &FsPath) -> io::Result<()> {
|
||||
unsafe { libc::symlink(target.as_ptr(), self.as_ptr()).as_os_err() }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -10,18 +10,18 @@ use std::process::exit;
|
||||
use std::str;
|
||||
|
||||
use argh::FromArgs;
|
||||
use bytemuck::{from_bytes, Pod, Zeroable};
|
||||
use bytemuck::{Pod, Zeroable, from_bytes};
|
||||
use num_traits::cast::AsPrimitive;
|
||||
use size::{Base, Size, Style};
|
||||
|
||||
use base::libc::{
|
||||
c_char, dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t, O_CLOEXEC, O_CREAT,
|
||||
O_RDONLY, O_TRUNC, O_WRONLY, S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFMT, S_IFREG, S_IRGRP,
|
||||
S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR,
|
||||
O_CLOEXEC, O_CREAT, O_RDONLY, O_TRUNC, O_WRONLY, S_IFBLK, S_IFCHR, S_IFDIR, S_IFLNK, S_IFMT,
|
||||
S_IFREG, S_IRGRP, S_IROTH, S_IRUSR, S_IWGRP, S_IWOTH, S_IWUSR, S_IXGRP, S_IXOTH, S_IXUSR,
|
||||
c_char, dev_t, gid_t, major, makedev, minor, mknod, mode_t, uid_t,
|
||||
};
|
||||
use base::{
|
||||
cstr_buf, log_err, map_args, BytesExt, EarlyExitExt, FsPath, LoggedResult, MappedFile,
|
||||
ResultExt, Utf8CStr, Utf8CStrBuf, WriteExt,
|
||||
BytesExt, EarlyExitExt, FsPath, LoggedResult, MappedFile, ResultExt, Utf8CStr, Utf8CStrBuf,
|
||||
WriteExt, cstr_buf, log_err, map_args,
|
||||
};
|
||||
|
||||
use crate::check_env;
|
||||
@ -362,7 +362,7 @@ impl Cpio {
|
||||
S_IFLNK => {
|
||||
buf.clear();
|
||||
buf.push_str(str::from_utf8(entry.data.as_slice())?);
|
||||
FsPath::from(&buf).symlink_to(out)?;
|
||||
out.create_symlink_to(FsPath::from(&buf))?;
|
||||
}
|
||||
S_IFBLK | S_IFCHR => {
|
||||
let dev = makedev(entry.rdevmajor.try_into()?, entry.rdevminor.try_into()?);
|
||||
|
@ -1,15 +1,15 @@
|
||||
use crate::ffi::backup_init;
|
||||
use crate::{
|
||||
ffi::{magisk_proxy_main, BootConfig, MagiskInit},
|
||||
ffi::{BootConfig, MagiskInit, magisk_proxy_main},
|
||||
logging::setup_klog,
|
||||
};
|
||||
use base::{
|
||||
debug, info,
|
||||
FsPath, LibcReturn, LoggedResult, ResultExt, debug, info,
|
||||
libc::{basename, getpid, mount, umask},
|
||||
path, raw_cstr, FsPath, LibcReturn, LoggedResult, ResultExt,
|
||||
path, raw_cstr,
|
||||
};
|
||||
use std::{
|
||||
ffi::{c_char, CStr},
|
||||
ffi::{CStr, c_char},
|
||||
ptr::null,
|
||||
};
|
||||
|
||||
@ -38,8 +38,9 @@ impl MagiskInit {
|
||||
pub(crate) fn legacy_system_as_root(&mut self) {
|
||||
info!("Legacy SAR Init");
|
||||
self.prepare_data();
|
||||
if self.mount_system_root() {
|
||||
self.redirect_second_stage();
|
||||
let is_two_stage = self.mount_system_root();
|
||||
if is_two_stage {
|
||||
self.patch_init_for_second_stage();
|
||||
} else {
|
||||
self.patch_ro_root();
|
||||
}
|
||||
@ -70,8 +71,8 @@ impl MagiskInit {
|
||||
// If the backup init is missing, this means that the boot ramdisk
|
||||
// was created from scratch, and the real init is in a separate CPIO,
|
||||
// which is guaranteed to be placed at /system/bin/init.
|
||||
path!("/system/bin/init")
|
||||
.symlink_to(path!("/init"))
|
||||
path!("/init")
|
||||
.create_symlink_to(path!("/system/bin/init"))
|
||||
.log_ok();
|
||||
}
|
||||
}
|
||||
|
@ -9,75 +9,106 @@ use base::{
|
||||
};
|
||||
use std::{ffi::c_long, io::Write, ptr::null};
|
||||
|
||||
impl MagiskInit {
|
||||
pub(crate) fn first_stage(&self) {
|
||||
info!("First Stage Init");
|
||||
self.prepare_data();
|
||||
const RAMFS_MAGIC: u64 = 0x858458f6;
|
||||
|
||||
if !path!("/sdcard").exists() && !path!("/first_stage_ramdisk/sdcard").exists() {
|
||||
if self.config.force_normal_boot {
|
||||
path!("/first_stage_ramdisk/storage/self")
|
||||
.mkdirs(0o755)
|
||||
.log_ok();
|
||||
path!("/system/system/bin/init")
|
||||
.symlink_to(path!("/first_stage_ramdisk/storage/self/primary"))
|
||||
.log_ok();
|
||||
debug!(
|
||||
"Symlink /first_stage_ramdisk/storage/self/primary -> /system/system/bin/init"
|
||||
);
|
||||
path!("/first_stage_ramdisk/sdcard")
|
||||
.create(O_RDONLY | O_CREAT | O_CLOEXEC, 0)
|
||||
.log_ok();
|
||||
} else {
|
||||
path!("/storage/self").mkdirs(0o755).log_ok();
|
||||
path!("/system/system/bin/init")
|
||||
.symlink_to(path!("/storage/self/primary"))
|
||||
.log_ok();
|
||||
debug!("Symlink /storage/self/primary -> /system/system/bin/init");
|
||||
}
|
||||
path!("/init").rename_to(path!("/sdcard")).log_ok();
|
||||
// Try to keep magiskinit in rootfs for samsung RKP
|
||||
if unsafe {
|
||||
fn patch_init_path(init: &mut MappedFile) {
|
||||
let from = "/system/bin/init";
|
||||
let to = "/data/magiskinit";
|
||||
|
||||
// Redirect original init to magiskinit
|
||||
let v = init.patch(from.as_bytes(), to.as_bytes());
|
||||
#[allow(unused_variables)]
|
||||
for off in &v {
|
||||
debug!("Patch @ {:#010X} [{}] -> [{}]", off, from, to);
|
||||
}
|
||||
}
|
||||
|
||||
impl MagiskInit {
|
||||
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.
|
||||
//
|
||||
// Two important assumption about 2SI:
|
||||
// - The second stage init is always /system/bin/init
|
||||
// - After `SwitchRoot`, /sdcard is always a symlink to `/storage/self/primary`.
|
||||
//
|
||||
// `SwitchRoot` will perform the following:
|
||||
// - Recursive move all mounts under `/` to `/system`
|
||||
// - chroot to `/system`
|
||||
//
|
||||
// The trick here is that in Magisk's first stage init, we can mount magiskinit to /sdcard,
|
||||
// and create a symlink at /storage/self/primary pointing to /system/system/bin/init.
|
||||
//
|
||||
// During init's `SwitchRoot`, it will mount move /sdcard (which is magiskinit)
|
||||
// to /system/sdcard, which is a symlink to /storage/self/primary, which is a
|
||||
// symlink to /system/system/bin/init, which will eventually become /system/bin/init after
|
||||
// chroot to /system. The effective result is that we coerce the original init into bind
|
||||
// mounting magiskinit to /system/bin/init, successfully hijacking the second stage init.
|
||||
//
|
||||
// An edge case is that some devices (like meizu) use 2SI but does not switch root.
|
||||
// In that case, they must already have a /sdcard in ramfs, thus we can check if
|
||||
// /sdcard exists and fallback to using hexpatch.
|
||||
|
||||
if self.config.force_normal_boot {
|
||||
path!("/first_stage_ramdisk/storage/self")
|
||||
.mkdirs(0o755)
|
||||
.log_ok();
|
||||
path!("/first_stage_ramdisk/storage/self/primary")
|
||||
.create_symlink_to(path!("/system/system/bin/init"))
|
||||
.log_ok();
|
||||
debug!("Symlink /first_stage_ramdisk/storage/self/primary -> /system/system/bin/init");
|
||||
path!("/first_stage_ramdisk/sdcard")
|
||||
.create(O_RDONLY | O_CREAT | O_CLOEXEC, 0)
|
||||
.log_ok();
|
||||
} else {
|
||||
path!("/storage/self").mkdirs(0o755).log_ok();
|
||||
path!("/storage/self/primary")
|
||||
.create_symlink_to(path!("/system/system/bin/init"))
|
||||
.log_ok();
|
||||
debug!("Symlink /storage/self/primary -> /system/system/bin/init");
|
||||
}
|
||||
path!("/init").rename_to(path!("/sdcard")).log_ok();
|
||||
|
||||
// First try to mount magiskinit from rootfs to workaround Samsung RKP
|
||||
if unsafe {
|
||||
mount(
|
||||
raw_cstr!("/sdcard"),
|
||||
raw_cstr!("/sdcard"),
|
||||
null(),
|
||||
MS_BIND,
|
||||
null(),
|
||||
)
|
||||
} == 0
|
||||
{
|
||||
debug!("Bind mount /sdcard -> /sdcard");
|
||||
} else {
|
||||
// Binding mounting from rootfs is not supported before Linux 3.12
|
||||
unsafe {
|
||||
mount(
|
||||
raw_cstr!("/sdcard"),
|
||||
raw_cstr!("/data/magiskinit"),
|
||||
raw_cstr!("/sdcard"),
|
||||
null(),
|
||||
MS_BIND,
|
||||
null(),
|
||||
)
|
||||
} == 0
|
||||
{
|
||||
debug!("Bind mount /sdcard -> /sdcard");
|
||||
} else {
|
||||
// rootfs before 3.12
|
||||
unsafe {
|
||||
mount(
|
||||
raw_cstr!("/data/magiskinit"),
|
||||
raw_cstr!("/sdcard"),
|
||||
null(),
|
||||
MS_BIND,
|
||||
null(),
|
||||
)
|
||||
};
|
||||
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) => {
|
||||
let from = "/system/bin/init";
|
||||
let to = "/data/magiskinit";
|
||||
|
||||
// Redirect original init to magiskinit
|
||||
let v = map.patch(from.as_bytes(), to.as_bytes());
|
||||
#[allow(unused_variables)]
|
||||
for off in &v {
|
||||
debug!("Patch @ {:#010X} [{}] -> [{}]", off, from, to);
|
||||
}
|
||||
}
|
||||
Ok(mut map) => patch_init_path(&mut map),
|
||||
_ => {
|
||||
error!("Failed to open /init for hexpatch");
|
||||
}
|
||||
@ -85,21 +116,13 @@ impl MagiskInit {
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn redirect_second_stage(&self) {
|
||||
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) => {
|
||||
let from = "/system/bin/init";
|
||||
let to = "/data/magiskinit";
|
||||
|
||||
// Redirect original init to magiskinit
|
||||
let v = map.patch(from.as_bytes(), to.as_bytes());
|
||||
#[allow(unused_variables)]
|
||||
for off in &v {
|
||||
debug!("Patch @ {:#010X} [{}] -> [{}]", off, from, to);
|
||||
}
|
||||
patch_init_path(&mut map);
|
||||
match dest.create(O_CREAT | O_WRONLY, 0) {
|
||||
Ok(mut dest) => {
|
||||
dest.write_all(map.as_ref()).log_ok();
|
||||
@ -135,11 +158,13 @@ impl MagiskInit {
|
||||
// Some weird devices like meizu, uses 2SI but still have legacy rootfs
|
||||
let mut sfs: statfs = std::mem::zeroed();
|
||||
statfs(raw_cstr!("/"), &mut sfs);
|
||||
if sfs.f_type == 0x858458f6 || sfs.f_type as c_long == TMPFS_MAGIC {
|
||||
if sfs.f_type as u64 == RAMFS_MAGIC || sfs.f_type as c_long == TMPFS_MAGIC {
|
||||
// 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();
|
||||
path!("/system/bin/init").symlink_to(init_path).log_ok();
|
||||
init_path
|
||||
.create_symlink_to(path!("/system/bin/init"))
|
||||
.log_ok();
|
||||
self.patch_rw_root();
|
||||
} else {
|
||||
self.patch_ro_root();
|
||||
|
Loading…
x
Reference in New Issue
Block a user