diff --git a/native/src/init/init.rs b/native/src/init/init.rs index 08df1169ea2c4..145108a08102c 100644 --- a/native/src/init/init.rs +++ b/native/src/init/init.rs @@ -20,6 +20,7 @@ impl MagiskInit { Self { preinit_dev: String::new(), mount_list: Vec::new(), + rc_list: Vec::new(), overlay_con: Vec::new(), argv, config: BootConfig { diff --git a/native/src/init/lib.rs b/native/src/init/lib.rs index a4c49b432621c..bff7b31434fd8 100644 --- a/native/src/init/lib.rs +++ b/native/src/init/lib.rs @@ -5,7 +5,7 @@ use logging::setup_klog; // Has to be pub so all symbols in that crate is included pub use magiskpolicy; use mount::{is_device_mounted, switch_root}; -use rootdir::{OverlayAttr, inject_magisk_rc}; +use rootdir::{OverlayAttr, inject_magisk_rc, inject_custom_rc}; #[path = "../include/consts.rs"] mod consts; @@ -41,6 +41,7 @@ pub mod ffi { struct MagiskInit { preinit_dev: String, mount_list: Vec, + rc_list: Vec, argv: *mut *mut c_char, config: BootConfig, overlay_con: Vec, @@ -66,6 +67,7 @@ pub mod ffi { #[namespace = "rust"] extern "Rust" { fn setup_klog(); + fn inject_custom_rc(mut rc_list: Vec, fd: i32, tmp_dir: Utf8CStrRef); fn inject_magisk_rc(fd: i32, tmp_dir: Utf8CStrRef); fn switch_root(path: Utf8CStrRef); fn is_device_mounted(dev: u64, target: Pin<&mut CxxString>) -> bool; @@ -88,6 +90,8 @@ pub mod ffi { fn mount_overlay(self: &mut MagiskInit, dest: Utf8CStrRef); fn handle_sepolicy(self: &mut MagiskInit); fn restore_overlay_contexts(self: &MagiskInit); + fn load_overlay_rc(self: &mut MagiskInit, overlay: &Utf8CStrRef, module_path: &Utf8CStrRef); + fn handle_modules_rc(self: &mut MagiskInit, root_dir: &Utf8CStrRef); } unsafe extern "C++" { // Used in Rust @@ -100,6 +104,7 @@ pub mod ffi { fn collect_devices(self: &MagiskInit); fn mount_preinit_dir(self: &mut MagiskInit); unsafe fn find_block(self: &MagiskInit, partname: *const c_char) -> u64; + unsafe fn patch_rc_scripts(self: &MagiskInit, src_path: *const c_char, tmp_path: *const c_char, writable: bool) -> bool; unsafe fn patch_fissiond(self: &mut MagiskInit, tmp_path: *const c_char); } } diff --git a/native/src/init/rootdir.cpp b/native/src/init/rootdir.cpp index cef17794ece9a..c5db790e3e6da 100644 --- a/native/src/init/rootdir.cpp +++ b/native/src/init/rootdir.cpp @@ -10,8 +10,6 @@ using namespace std; -static vector rc_list; - #define NEW_INITRC_DIR "/system/etc/init/hw" #define INIT_RC "init.rc" @@ -41,7 +39,7 @@ static bool unxz(int fd, rust::Slice bytes) { } // When return true, run patch_fissiond -static bool patch_rc_scripts(const char *src_path, const char *tmp_path, bool writable) { +bool MagiskInit::patch_rc_scripts(const char *src_path, const char *tmp_path, bool writable) const noexcept { auto src_dir = xopen_dir(src_path); if (!src_dir) return false; int src_fd = dirfd(src_dir.get()); @@ -93,12 +91,7 @@ static bool patch_rc_scripts(const char *src_path, const char *tmp_path, bool wr fprintf(dest.get(), "\n"); // Inject custom rc scripts - for (auto &script : rc_list) { - // Replace template arguments of rc scripts with dynamic paths - replace_all(script, "${MAGISKTMP}", tmp_path); - fprintf(dest.get(), "\n%s\n", script.data()); - } - rc_list.clear(); + rust::inject_custom_rc(rc_list, fileno(dest.get()), tmp_path); // Inject Magisk rc scripts rust::inject_magisk_rc(fileno(dest.get()), tmp_path); @@ -173,34 +166,6 @@ void MagiskInit::patch_fissiond(const char *tmp_path) noexcept { } } -static void load_overlay_rc(const char *overlay) { - auto dir = open_dir(overlay); - if (!dir) return; - - int dfd = dirfd(dir.get()); - // Do not allow overwrite init.rc - unlinkat(dfd, INIT_RC, 0); - - // '/' + name + '\0' - char buf[NAME_MAX + 2]; - buf[0] = '/'; - for (dirent *entry; (entry = xreaddir(dir.get()));) { - if (!str_ends(entry->d_name, ".rc")) { - continue; - } - strscpy(buf + 1, entry->d_name, sizeof(buf) - 1); - if (access(buf, F_OK) == 0) { - LOGD("Replace rc script [%s]\n", entry->d_name); - } else { - LOGD("Found rc script [%s]\n", entry->d_name); - int rc = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC); - rc_list.push_back(full_read(rc)); - close(rc); - unlinkat(dfd, entry->d_name, 0); - } - } -} - static void recreate_sbin(const char *mirror, bool use_bind_mount) { auto dp = xopen_dir(mirror); int src = dirfd(dp.get()); @@ -305,12 +270,14 @@ void MagiskInit::patch_ro_root() noexcept { close(dest); } - load_overlay_rc(ROOTOVL); + load_overlay_rc(ROOTOVL, ""); if (access(ROOTOVL "/sbin", F_OK) == 0) { // Move files in overlay.d/sbin into tmp_dir mv_path(ROOTOVL "/sbin", "."); } + handle_modules_rc(ROOTOVL); + // Patch init.rc bool p; if (access(NEW_INITRC_DIR "/" INIT_RC, F_OK) == 0) { @@ -346,11 +313,13 @@ void MagiskInit::patch_rw_root() noexcept { link_path("/sbin", "/root"); // Handle overlays - load_overlay_rc("/overlay.d"); + load_overlay_rc("/overlay.d", ""); mv_path("/overlay.d", "/"); rm_rf("/data/overlay.d"); rm_rf("/.backup"); + handle_modules_rc("/"); + // Patch init.rc if (patch_rc_scripts("/", "/sbin", true)) patch_fissiond("/sbin"); diff --git a/native/src/init/rootdir.rs b/native/src/init/rootdir.rs index 9f2c4a7f8a7e3..d5a2ff3287104 100644 --- a/native/src/init/rootdir.rs +++ b/native/src/init/rootdir.rs @@ -1,17 +1,13 @@ -use crate::consts::{ROOTMNT, ROOTOVL}; +use crate::consts::{PREINITMIRR, ROOTMNT, ROOTOVL}; use crate::ffi::MagiskInit; -use base::libc::{O_CREAT, O_RDONLY, O_WRONLY}; use base::{ BufReadExt, Directory, FsPathBuilder, LoggedResult, ResultExt, Utf8CStr, Utf8CString, - clone_attr, cstr, debug, -}; -use std::io::BufReader; -use std::{ - fs::File, - io::Write, - mem, - os::fd::{FromRawFd, RawFd}, + clone_attr, + const_format::concatcp, + cstr, debug, + libc::{O_CLOEXEC, O_CREAT, O_RDONLY, O_WRONLY}, }; +use std::{fs::File, io::BufReader, io::Read, io::Write, mem, os::fd::FromRawFd, os::fd::RawFd}; pub fn inject_magisk_rc(fd: RawFd, tmp_dir: &Utf8CStr) { debug!("Injecting magisk rc"); @@ -43,6 +39,17 @@ on property:init.svc.zygote=stopped mem::forget(file) } +pub fn inject_custom_rc(mut rc_list: Vec, fd: RawFd, tmp_dir: &Utf8CStr) { + let mut file = unsafe { File::from_raw_fd(fd) }; + rc_list.iter().for_each(|rc| { + // Replace template arguments of rc scripts with dynamic paths + let rc = rc.replace("${MAGISKTMP}", tmp_dir.as_str()); + write!(file, "\n{}\n", rc).ok(); + }); + mem::forget(file); + rc_list.clear(); +} + pub struct OverlayAttr(Utf8CString, Utf8CString); impl MagiskInit { @@ -59,6 +66,78 @@ impl MagiskInit { } } + pub(crate) fn load_overlay_rc(&mut self, overlay: &Utf8CStr, module_path: &Utf8CStr) { + if let Ok(mut dir) = Directory::open(overlay) { + let init_rc = cstr::buf::dynamic(256) + .join_path(overlay) + .join_path("init.rc"); + if init_rc.exists() { + // Do not allow overwrite init.rc + init_rc.remove().log_ok(); + } + loop { + match dir.read() { + Ok(None) => break, + Ok(Some(e)) => { + let recursive = cstr::buf::dynamic(256).join_path(module_path).exists(); + if (recursive && e.is_dir()) || e.is_file() { + let buf = &mut cstr::buf::dynamic(256); + e.resolve_path(buf).log_ok(); + if e.is_file() && buf.ends_with(".rc") { + let mut path; + if recursive { + path = cstr::buf::dynamic(256) + .join_path(buf.replace(module_path.as_str(), "")); + } else { + path = + cstr::buf::dynamic(256).join_path("/").join_path(e.name()); + } + if path.exists() { + debug!("Replace rc script [{}] -> [{}]", path, buf); + } else { + path = cstr::buf::dynamic(256).join_path(buf); + debug!("Found rc script [{}]", path); + let mut rc_content = String::new(); + if let Ok(mut file) = path.open(O_RDONLY | O_CLOEXEC) { + file.read_to_string(&mut rc_content).log_ok(); + self.rc_list.push(rc_content); + drop(file); + path.remove().log_ok(); + } + } + } else if e.is_dir() { + self.load_overlay_rc(buf, module_path); + } + } else { + continue; + } + } + Err(_) => break, + } + } + } + } + + pub(crate) fn handle_modules_rc(&mut self, root_dir: &Utf8CStr) { + if let Ok(mut dir) = Directory::open(cstr!(concatcp!("/data/", PREINITMIRR))) { + loop { + match dir.read() { + Ok(None) => break, + Ok(Some(e)) if e.is_dir() => { + let buf = &mut cstr::buf::dynamic(256); + e.resolve_path(buf).log_ok(); + let path = cstr::buf::dynamic(256).join_path(&mut *buf); + self.load_overlay_rc(&path, buf); + let desc_path = cstr::buf::dynamic(256).join_path(root_dir); + path.copy_to(&desc_path).log_ok(); + } + Ok(_) => continue, + Err(_) => break, + } + } + } + } + fn mount_impl( &mut self, src_dir: &Utf8CStr, diff --git a/scripts/util_functions.sh b/scripts/util_functions.sh index 1a80a1a64738f..651ddccf247d0 100644 --- a/scripts/util_functions.sh +++ b/scripts/util_functions.sh @@ -584,6 +584,21 @@ copy_preinit_files() { cat $r echo done > $PREINITDIR/sepolicy.rule + + # Copy all enabled rc + find "$PREINITDIR/" -mindepth 1 -maxdepth 1 -type d -exec rm -rf {} \; + find /data/adb/modules* -mindepth 1 -maxdepth 1 -type d 2>/dev/null | while read -r MODDIR; do + local MODID=$(basename "$MODDIR") + [ -f "$MODDIR"/disable ] && continue + [ -f "$MODDIR"/remove ] && continue + [ -f "$MODDIR"/update ] && continue + find "$MODDIR" -mindepth 1 -type f -name "*.rc" | while read -r file; do + local path="${file%/*}" + path="$PREINITDIR/$MODID${path/$MODDIR/}" + mkdir -p "$path" + cp "$file" "$path/" + done + done } ################# @@ -720,9 +735,17 @@ install_module() { cp -af $MODPATH/module.prop /data/adb/modules/$MODID/module.prop fi - # Copy over custom sepolicy rules - if [ -f $MODPATH/sepolicy.rule ]; then - ui_print "- Installing custom sepolicy rules" + find "$MODPATH" -mindepth 1 -type f -name "init.rc" -exec rm -f {} \; + find "$MODPATH" -mindepth 1 -type f -name "*.rc" | while read -r file; do + local path="${file/$MODPATH/}" + if [ ! -f "$path" ]; then + mv "$file" "$MODPATH" + fi + rc=true + done + # Copy over custom sepolicy rules and rc + if [ -f $MODPATH/sepolicy.rule ] || "$rc"; then + ui_print "- Installing custom sepolicy rules or rc script" copy_preinit_files fi