From 7961be5cfa66bdcddf08b43421c882fe3baca614 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 2 Aug 2025 13:53:35 -0700 Subject: [PATCH] Migrate prepare_modules to Rust --- native/src/base/dir.rs | 2 +- native/src/base/files.rs | 2 +- native/src/core/daemon.rs | 7 ++-- native/src/core/module.cpp | 27 --------------- native/src/core/module.rs | 64 ++++++++++++++++++++++++++++++++---- native/src/include/consts.rs | 1 + native/src/init/mount.rs | 2 +- 7 files changed, 63 insertions(+), 42 deletions(-) diff --git a/native/src/base/dir.rs b/native/src/base/dir.rs index deda93f6a..1c4cb72db 100644 --- a/native/src/base/dir.rs +++ b/native/src/base/dir.rs @@ -309,7 +309,7 @@ impl Directory { self.pre_order_walk_impl(&mut f) } - pub fn remove_all(&mut self) -> OsResultStatic<()> { + pub fn remove_all(mut self) -> OsResultStatic<()> { self.post_order_walk(|e| { e.unlink()?; Ok(WalkResult::Continue) diff --git a/native/src/base/files.rs b/native/src/base/files.rs index 6c8b721b3..c1dbf0bee 100644 --- a/native/src/base/files.rs +++ b/native/src/base/files.rs @@ -227,7 +227,7 @@ impl Utf8CStr { pub fn remove_all(&self) -> OsResultStatic<()> { let attr = self.get_attr()?; if attr.is_dir() { - let mut dir = Directory::try_from(open_fd(self, O_RDONLY | O_CLOEXEC, 0)?)?; + let dir = Directory::try_from(open_fd(self, O_RDONLY | O_CLOEXEC, 0)?)?; dir.remove_all()?; } Ok(self.remove()?) diff --git a/native/src/core/daemon.rs b/native/src/core/daemon.rs index f121e9b12..e8643a58b 100644 --- a/native/src/core/daemon.rs +++ b/native/src/core/daemon.rs @@ -5,7 +5,7 @@ use crate::ffi::{ exec_module_scripts, get_magisk_tmp, initialize_denylist, setup_magisk_env, }; use crate::logging::{magisk_logging, setup_logfile, start_log_daemon}; -use crate::mount::{clean_mounts, setup_module_mount, setup_preinit_dir}; +use crate::mount::{clean_mounts, setup_preinit_dir}; use crate::package::ManagerInfo; use crate::selinux::restore_tmpcon; use crate::su::SuInfo; @@ -144,10 +144,7 @@ impl MagiskD { Ordering::Release, ); initialize_denylist(); - setup_module_mount(); - let modules = self.load_modules(); - self.module_list.set(modules).ok(); - self.apply_modules(); + self.handle_modules(); clean_mounts(); false diff --git a/native/src/core/module.cpp b/native/src/core/module.cpp index b4bf10761..c54b82ae8 100644 --- a/native/src/core/module.cpp +++ b/native/src/core/module.cpp @@ -11,32 +11,6 @@ using namespace std; * Filesystem operations ************************/ -static void prepare_modules() { - // Upgrade modules - if (auto dir = open_dir(MODULEUPGRADE); dir) { - int ufd = dirfd(dir.get()); - int mfd = xopen(MODULEROOT, O_RDONLY | O_CLOEXEC); - for (dirent *entry; (entry = xreaddir(dir.get()));) { - if (entry->d_type == DT_DIR) { - // Cleanup old module if exists - if (faccessat(mfd, entry->d_name, F_OK, 0) == 0) { - int modfd = xopenat(mfd, entry->d_name, O_RDONLY | O_CLOEXEC); - if (faccessat(modfd, "disable", F_OK, 0) == 0) { - auto disable = entry->d_name + "/disable"s; - close(xopenat(ufd, disable.data(), O_RDONLY | O_CREAT | O_CLOEXEC, 0)); - } - frm_rf(modfd); - unlinkat(mfd, entry->d_name, AT_REMOVEDIR); - } - LOGI("Upgrade / New module: %s\n", entry->d_name); - renameat(ufd, entry->d_name, mfd, entry->d_name); - } - } - close(mfd); - rm_rf(MODULEUPGRADE); - } -} - template static void foreach_module(Func fn) { auto dir = open_dir(MODULEROOT); @@ -135,7 +109,6 @@ static rust::Vec collect_modules(bool zygisk_enabled, bool open_zygi rust::Vec MagiskD::load_modules() const noexcept { bool zygisk = zygisk_enabled(); - prepare_modules(); exec_module_scripts("post-fs-data", collect_modules(zygisk, false)); // Recollect modules (module scripts could remove itself) auto list = collect_modules(zygisk, true); diff --git a/native/src/core/module.rs b/native/src/core/module.rs index 41e0f0250..f340b7a05 100644 --- a/native/src/core/module.rs +++ b/native/src/core/module.rs @@ -1,13 +1,15 @@ -use crate::consts::{MODULEMNT, MODULEROOT, WORKERDIR}; +use crate::consts::{MODULEMNT, MODULEROOT, MODULEUPGRADE, WORKERDIR}; use crate::daemon::MagiskD; -use crate::ffi::{get_magisk_tmp, get_zygisk_lib_name}; +use crate::ffi::{ModuleInfo, get_magisk_tmp, get_zygisk_lib_name}; use crate::load_prop_file; +use crate::mount::setup_module_mount; use base::{ - Directory, FsPathBuilder, LoggedResult, OsResultStatic, ResultExt, Utf8CStr, Utf8CStrBuf, - Utf8CString, WalkResult, clone_attr, cstr, debug, error, info, libc, warn, + Directory, FsPathBuilder, LibcReturn, LoggedResult, OsResultStatic, ResultExt, Utf8CStr, + Utf8CStrBuf, Utf8CString, WalkResult, clone_attr, cstr, debug, error, info, libc, warn, }; -use libc::{MS_RDONLY, O_CLOEXEC, O_CREAT, O_RDONLY}; +use libc::{AT_REMOVEDIR, MS_RDONLY, O_CLOEXEC, O_CREAT, O_RDONLY}; use std::collections::BTreeMap; +use std::os::fd::AsRawFd; use std::path::{Component, Path}; const MAGISK_BIN_INJECT_PARTITIONS: [&Utf8CStr; 4] = [ @@ -548,8 +550,48 @@ fn inject_zygisk_bins(system: &mut FsNode) { } } +fn prepare_modules() -> LoggedResult<()> { + let mut upgrade = Directory::open(cstr!(MODULEUPGRADE))?; + let ufd = upgrade.as_raw_fd(); + let root = Directory::open(cstr!(MODULEROOT))?; + while let Some(ref e) = upgrade.read()? { + if !e.is_dir() { + continue; + } + let module_name = e.name(); + let mut disable = false; + // Cleanup old module if exists + if root.contains_path(module_name) { + let module = root.open_as_dir_at(module_name)?; + // If the old module is disabled, we need to also disable the new one + disable = module.contains_path(cstr!("disable")); + module.remove_all()?; + root.unlink_at(module_name, AT_REMOVEDIR)?; + } + info!("Upgrade / New module: {module_name}"); + unsafe { + libc::renameat( + ufd, + module_name.as_ptr(), + root.as_raw_fd(), + module_name.as_ptr(), + ) + .check_os_err("renameat", Some(module_name), None)?; + } + if disable { + let path = cstr::buf::default() + .join_path(module_name) + .join_path("disable"); + let _ = root.open_as_file_at(&path, O_RDONLY | O_CREAT | O_CLOEXEC, 0)?; + } + } + upgrade.remove_all()?; + cstr!(MODULEUPGRADE).remove()?; + Ok(()) +} + impl MagiskD { - pub fn apply_modules(&self) { + fn apply_modules(&self, module_list: &[ModuleInfo]) { let mut system = FsNode::new_dir(); // Build all the base "prefix" paths @@ -578,7 +620,7 @@ impl MagiskD { // In this step, there is zero logic applied during tree construction; we simply collect and // record the union of all module filesystem trees under each of their /system directory. - for info in self.module_list.get().iter().flat_map(|v| v.iter()) { + for info in module_list { let mut module_paths = root_paths.append(&info.name); { // Read props @@ -656,4 +698,12 @@ impl MagiskD { root.commit(path, true).log_ok(); } } + + pub fn handle_modules(&self) { + setup_module_mount(); + prepare_modules().ok(); + let modules = self.load_modules(); + self.apply_modules(&modules); + self.module_list.set(modules).ok(); + } } diff --git a/native/src/include/consts.rs b/native/src/include/consts.rs index 789f909f5..690d25e76 100644 --- a/native/src/include/consts.rs +++ b/native/src/include/consts.rs @@ -15,6 +15,7 @@ pub const LOGFILE: &str = "/cache/magisk.log"; // data paths pub const SECURE_DIR: &str = "/data/adb"; pub const MODULEROOT: &str = concatcp!(SECURE_DIR, "/modules"); +pub const MODULEUPGRADE: &str = concatcp!(SECURE_DIR, "/modules_update"); pub const DATABIN: &str = concatcp!(SECURE_DIR, "/magisk"); pub const MAGISKDB: &str = concatcp!(SECURE_DIR, "/magisk.db"); diff --git a/native/src/init/mount.rs b/native/src/init/mount.rs index f26224d71..be422986c 100644 --- a/native/src/init/mount.rs +++ b/native/src/init/mount.rs @@ -21,7 +21,7 @@ pub(crate) fn switch_root(path: &Utf8CStr) { let res: LoggedResult<()> = try { debug!("Switch root to {}", path); let mut mounts = BTreeSet::new(); - let mut rootfs = Directory::open(cstr!("/"))?; + let rootfs = Directory::open(cstr!("/"))?; for info in parse_mount_info("self") { if info.target == "/" || info.target.as_str() == path.as_str() { continue;