Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 22 additions & 20 deletions native/src/base/files.rs
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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() {
Expand All @@ -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() }
}
}

Expand Down
1 change: 1 addition & 0 deletions native/src/base/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ mod dir;
mod files;
mod logging;
mod misc;
mod mount;
mod result;
mod xwrap;

Expand Down
62 changes: 62 additions & 0 deletions native/src/base/mount.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crate::{FsPath, LibcReturn};
use libc::c_ulong;
use std::ptr;

impl FsPath {
pub fn bind_mount_to(&self, path: &FsPath) -> std::io::Result<()> {
unsafe {
libc::mount(
self.as_ptr(),
path.as_ptr(),
ptr::null(),
libc::MS_BIND,
ptr::null(),
)
.as_os_err()
}
}

pub fn remount_with_flags(&self, flags: c_ulong) -> std::io::Result<()> {
unsafe {
libc::mount(
ptr::null(),
self.as_ptr(),
ptr::null(),
libc::MS_BIND | libc::MS_REMOUNT | flags,
ptr::null(),
)
.as_os_err()
}
}

pub fn move_mount_to(&self, path: &FsPath) -> std::io::Result<()> {
unsafe {
libc::mount(
self.as_ptr(),
path.as_ptr(),
ptr::null(),
libc::MS_MOVE,
ptr::null(),
)
.as_os_err()
}
}

pub fn unmount(&self) -> std::io::Result<()> {
unsafe { libc::umount2(self.as_ptr(), libc::MNT_DETACH).as_os_err() }
}

pub fn set_mount_private(&self, recursive: bool) -> std::io::Result<()> {
let flag = if recursive { libc::MS_REC } else { 0 };
unsafe {
libc::mount(
ptr::null(),
self.as_ptr(),
ptr::null(),
libc::MS_PRIVATE | flag,
ptr::null(),
)
.as_os_err()
}
}
}
14 changes: 7 additions & 7 deletions native/src/boot/cpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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()?);
Expand Down
44 changes: 7 additions & 37 deletions native/src/core/mount.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
use std::{
cmp::Ordering::{Greater, Less},
path::{Path, PathBuf},
ptr,
};

use num_traits::AsPrimitive;

use base::libc::{c_uint, dev_t};
use base::{
cstr, cstr_buf, debug, info, libc, parse_mount_info, raw_cstr, warn, FsPath, FsPathBuf,
LibcReturn, LoggedResult, MountInfo, ResultExt, Utf8CStr,
FsPath, FsPathBuf, LibcReturn, LoggedResult, MountInfo, ResultExt, Utf8CStr, cstr, cstr_buf,
debug, info, libc, parse_mount_info, path, warn,
};

use crate::consts::{MODULEMNT, MODULEROOT, PREINITDEV, PREINITMIRR, WORKERDIR};
Expand Down Expand Up @@ -73,51 +72,22 @@ pub fn setup_mounts() {
let module_mnt = FsPathBuf::default().join(magisk_tmp).join(MODULEMNT);
let _: LoggedResult<()> = try {
module_mnt.mkdir(0o755)?;
unsafe {
libc::mount(
raw_cstr!(MODULEROOT),
module_mnt.as_ptr(),
ptr::null(),
libc::MS_BIND,
ptr::null(),
)
.as_os_err()?;
libc::mount(
ptr::null(),
module_mnt.as_ptr(),
ptr::null(),
libc::MS_REMOUNT | libc::MS_BIND | libc::MS_RDONLY,
ptr::null(),
)
.as_os_err()?;
}
path!(MODULEROOT).bind_mount_to(&module_mnt)?;
module_mnt.remount_with_flags(libc::MS_RDONLY)?;
};
}

pub fn clean_mounts() {
let magisk_tmp = get_magisk_tmp();

let mut module_mnt = FsPathBuf::default().join(magisk_tmp).join(MODULEMNT);
let _: LoggedResult<()> = try {
unsafe {
libc::umount2(module_mnt.as_ptr(), libc::MNT_DETACH).as_os_err()?;
}
};
module_mnt.unmount().log_ok();

module_mnt.clear();
let worker_dir = module_mnt.join(magisk_tmp).join(WORKERDIR);
let _: LoggedResult<()> = try {
unsafe {
libc::mount(
ptr::null(),
worker_dir.as_ptr(),
ptr::null(),
libc::MS_PRIVATE | libc::MS_REC,
ptr::null(),
)
.as_os_err()?;
libc::umount2(worker_dir.as_ptr(), libc::MNT_DETACH).as_os_err()?;
}
worker_dir.set_mount_private(true)?;
worker_dir.unmount()?;
};
}

Expand Down
70 changes: 56 additions & 14 deletions native/src/init/init.rs
Original file line number Diff line number Diff line change
@@ -1,15 +1,17 @@
use crate::ffi::backup_init;
use crate::mount::is_rootfs;
use crate::twostage::hexpatch_init_for_second_stage;
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, 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,
};

Expand All @@ -35,31 +37,71 @@ impl MagiskInit {
}
}

pub(crate) fn legacy_system_as_root(&mut self) {
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
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();
}
}

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 {
hexpatch_init_for_second_stage(false);
} else {
self.patch_ro_root();
}
}

pub(crate) fn rootfs(&mut self) {
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());
Expand All @@ -70,8 +112,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();
}
}
Expand Down
Loading