Migrate load_modules to Rust

This commit is contained in:
topjohnwu
2025-08-04 11:31:01 -07:00
committed by John Wu
parent 589a270b8d
commit e489b3b6dd
4 changed files with 150 additions and 134 deletions

View File

@@ -20,7 +20,6 @@ LOCAL_SRC_FILES := \
core/daemon.cpp \ core/daemon.cpp \
core/scripting.cpp \ core/scripting.cpp \
core/sqlite.cpp \ core/sqlite.cpp \
core/module.cpp \
core/thread.cpp \ core/thread.cpp \
core/core-rs.cpp \ core/core-rs.cpp \
core/resetprop/resetprop.cpp \ core/resetprop/resetprop.cpp \

View File

@@ -158,6 +158,7 @@ pub mod ffi {
fn update_deny_flags(uid: i32, process: &str, flags: &mut u32); fn update_deny_flags(uid: i32, process: &str, flags: &mut u32);
fn initialize_denylist(); fn initialize_denylist();
fn get_zygisk_lib_name() -> &'static str; fn get_zygisk_lib_name() -> &'static str;
fn set_zygisk_prop();
fn restore_zygisk_prop(); fn restore_zygisk_prop();
fn switch_mnt_ns(pid: i32) -> i32; fn switch_mnt_ns(pid: i32) -> i32;
fn app_request(req: &SuAppRequest) -> i32; fn app_request(req: &SuAppRequest) -> i32;
@@ -254,9 +255,6 @@ pub mod ffi {
#[cxx_name = "Get"] #[cxx_name = "Get"]
fn get() -> &'static MagiskD; fn get() -> &'static MagiskD;
} }
unsafe extern "C++" {
fn load_modules(self: &MagiskD) -> Vec<ModuleInfo>;
}
} }
#[repr(transparent)] #[repr(transparent)]

View File

@@ -1,119 +0,0 @@
#include <sys/mman.h>
#include <sys/syscall.h>
#include <base.hpp>
#include <consts.hpp>
#include <core.hpp>
using namespace std;
/************************
* Filesystem operations
************************/
template<typename Func>
static void foreach_module(Func fn) {
auto dir = open_dir(MODULEROOT);
if (!dir)
return;
int dfd = dirfd(dir.get());
for (dirent *entry; (entry = xreaddir(dir.get()));) {
if (entry->d_type == DT_DIR && entry->d_name != ".core"sv) {
int modfd = xopenat(dfd, entry->d_name, O_RDONLY | O_CLOEXEC);
fn(dfd, entry, modfd);
close(modfd);
}
}
}
static rust::Vec<ModuleInfo> collect_modules(bool zygisk_enabled, bool open_zygisk) {
rust::Vec<ModuleInfo> modules;
foreach_module([&](int dfd, dirent *entry, int modfd) {
if (faccessat(modfd, "remove", F_OK, 0) == 0) {
LOGI("%s: remove\n", entry->d_name);
auto uninstaller = MODULEROOT + "/"s + entry->d_name + "/uninstall.sh";
if (access(uninstaller.data(), F_OK) == 0)
exec_script(uninstaller.data());
frm_rf(xdup(modfd));
unlinkat(dfd, entry->d_name, AT_REMOVEDIR);
return;
}
unlinkat(modfd, "update", 0);
if (faccessat(modfd, "disable", F_OK, 0) == 0)
return;
ModuleInfo info{{}, -1, -1};
if (zygisk_enabled) {
// Riru and its modules are not compatible with zygisk
if (entry->d_name == "riru-core"sv || faccessat(modfd, "riru", F_OK, 0) == 0) {
LOGI("%s: ignore\n", entry->d_name);
return;
}
if (open_zygisk) {
#if defined(__arm__)
info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC);
info.z64 = -1;
#elif defined(__aarch64__)
info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC);
info.z64 = openat(modfd, "zygisk/arm64-v8a.so", O_RDONLY | O_CLOEXEC);
#elif defined(__i386__)
info.z32 = openat(modfd, "zygisk/x86.so", O_RDONLY | O_CLOEXEC);
info.z64 = -1;
#elif defined(__x86_64__)
info.z32 = openat(modfd, "zygisk/x86.so", O_RDONLY | O_CLOEXEC);
info.z64 = openat(modfd, "zygisk/x86_64.so", O_RDONLY | O_CLOEXEC);
#elif defined(__riscv)
info.z32 = -1;
info.z64 = openat(modfd, "zygisk/riscv64.so", O_RDONLY | O_CLOEXEC);
#else
#error Unsupported ABI
#endif
unlinkat(modfd, "zygisk/unloaded", 0);
}
} else {
// Ignore zygisk modules when zygisk is not enabled
if (faccessat(modfd, "zygisk", F_OK, 0) == 0) {
LOGI("%s: ignore\n", entry->d_name);
return;
}
}
info.name = entry->d_name;
modules.push_back(std::move(info));
});
if (zygisk_enabled) {
bool use_memfd = true;
auto convert_to_memfd = [&](int fd) -> int {
if (fd < 0)
return -1;
if (use_memfd) {
int memfd = syscall(__NR_memfd_create, "jit-cache", MFD_CLOEXEC);
if (memfd >= 0) {
xsendfile(memfd, fd, nullptr, INT_MAX);
close(fd);
return memfd;
} else {
// memfd_create failed, just use what we had
use_memfd = false;
}
}
return fd;
};
ranges::for_each(modules, [&](ModuleInfo &info) {
info.z32 = convert_to_memfd(info.z32);
info.z64 = convert_to_memfd(info.z64);
});
}
return modules;
}
rust::Vec<ModuleInfo> MagiskD::load_modules() const noexcept {
bool zygisk = zygisk_enabled();
exec_module_scripts("post-fs-data", collect_modules(zygisk, false));
// Recollect modules (module scripts could remove itself)
auto list = collect_modules(zygisk, true);
if (zygisk) {
set_zygisk_prop();
}
return list;
}

View File

@@ -1,16 +1,21 @@
use crate::consts::{MODULEMNT, MODULEROOT, MODULEUPGRADE, WORKERDIR}; use crate::consts::{MODULEMNT, MODULEROOT, MODULEUPGRADE, WORKERDIR};
use crate::daemon::MagiskD; use crate::daemon::MagiskD;
use crate::ffi::{ModuleInfo, exec_script, get_magisk_tmp, get_zygisk_lib_name, load_prop_file}; use crate::ffi::{
ModuleInfo, exec_module_scripts, exec_script, get_magisk_tmp, get_zygisk_lib_name,
load_prop_file, set_zygisk_prop,
};
use crate::mount::setup_module_mount; use crate::mount::setup_module_mount;
use base::{ use base::{
DirEntry, Directory, FsPathBuilder, LibcReturn, LoggedResult, OsResultStatic, ResultExt, DirEntry, Directory, FsPathBuilder, LibcReturn, LoggedResult, OsResultStatic, ResultExt,
Utf8CStr, Utf8CStrBuf, Utf8CString, WalkResult, clone_attr, cstr, debug, error, info, libc, Utf8CStr, Utf8CStrBuf, Utf8CString, WalkResult, clone_attr, cstr, debug, error, info, libc,
warn, raw_cstr, warn,
}; };
use libc::{AT_REMOVEDIR, 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::collections::BTreeMap;
use std::os::fd::AsRawFd; use std::os::fd::{AsRawFd, IntoRawFd};
use std::path::{Component, Path}; use std::path::{Component, Path};
use std::ptr;
use std::sync::atomic::Ordering;
const MAGISK_BIN_INJECT_PARTITIONS: [&Utf8CStr; 4] = [ const MAGISK_BIN_INJECT_PARTITIONS: [&Utf8CStr; 4] = [
cstr!("/system/"), cstr!("/system/"),
@@ -698,7 +703,7 @@ fn upgrade_modules() -> LoggedResult<()> {
Ok(()) Ok(())
} }
fn for_each_module(func: impl Fn(&DirEntry) -> LoggedResult<()>) -> LoggedResult<()> { fn for_each_module(mut func: impl FnMut(&DirEntry) -> LoggedResult<()>) -> LoggedResult<()> {
let mut root = Directory::open(cstr!(MODULEROOT))?; let mut root = Directory::open(cstr!(MODULEROOT))?;
while let Some(ref e) = root.read()? { while let Some(ref e) = root.read()? {
if e.is_dir() && e.name() != ".core" { if e.is_dir() && e.name() != ".core" {
@@ -717,15 +722,19 @@ pub fn disable_modules() {
.log_ok(); .log_ok();
} }
fn run_uninstall_script(module_name: &Utf8CStr) {
let script = cstr::buf::default()
.join_path(MODULEROOT)
.join_path(module_name)
.join_path("uninstall.sh");
exec_script(&script);
}
pub fn remove_modules() { pub fn remove_modules() {
for_each_module(|e| { for_each_module(|e| {
let dir = e.open_as_dir()?; let dir = e.open_as_dir()?;
if dir.contains_path(cstr!("uninstall.sh")) { if dir.contains_path(cstr!("uninstall.sh")) {
let script = cstr::buf::default() run_uninstall_script(e.name());
.join_path(MODULEROOT)
.join_path(e.name())
.join_path("uninstall.sh");
exec_script(&script);
} }
Ok(()) Ok(())
}) })
@@ -733,12 +742,141 @@ pub fn remove_modules() {
cstr!(MODULEROOT).remove_all().log_ok(); cstr!(MODULEROOT).remove_all().log_ok();
} }
fn collect_modules(zygisk_enabled: bool, open_zygisk: bool) -> Vec<ModuleInfo> {
let mut modules = Vec::new();
#[allow(unused_mut)] // It's possible that z32 and z64 are unused
for_each_module(|e| {
let name = e.name();
let dir = e.open_as_dir()?;
if dir.contains_path(cstr!("remove")) {
info!("{name}: remove");
if dir.contains_path(cstr!("uninstall.sh")) {
run_uninstall_script(name);
}
dir.remove_all()?;
e.unlink()?;
return Ok(());
}
dir.unlink_at(cstr!("update"), 0).ok();
if dir.contains_path(cstr!("disable")) {
return Ok(());
}
let mut z32 = -1;
let mut z64 = -1;
let is_zygisk = dir.contains_path(cstr!("zygisk"));
if zygisk_enabled {
// Riru and its modules are not compatible with zygisk
if name == "riru-core" || dir.contains_path(cstr!("riru")) {
return Ok(());
}
fn open_fd_safe(dir: &Directory, name: &Utf8CStr) -> i32 {
dir.open_as_file_at(name, O_RDONLY | O_CLOEXEC, 0)
.log()
.map(IntoRawFd::into_raw_fd)
.unwrap_or(-1)
}
if open_zygisk && is_zygisk {
#[cfg(target_arch = "arm")]
{
z32 = open_fd_safe(&dir, cstr!("zygisk/armeabi-v7a.so"));
}
#[cfg(target_arch = "aarch64")]
{
z32 = open_fd_safe(&dir, cstr!("zygisk/armeabi-v7a.so"));
z64 = open_fd_safe(&dir, cstr!("zygisk/arm64-v8a.so"));
}
#[cfg(target_arch = "x86")]
{
z32 = open_fd_safe(&dir, cstr!("zygisk/x86.so"));
}
#[cfg(target_arch = "x86_64")]
{
z32 = open_fd_safe(&dir, cstr!("zygisk/x86.so"));
z64 = open_fd_safe(&dir, cstr!("zygisk/x86_64.so"));
}
#[cfg(target_arch = "riscv64")]
{
z64 = open_fd_safe(&dir, cstr!("zygisk/riscv64.so"));
}
dir.unlink_at(cstr!("zygisk/unloaded"), 0).ok();
}
} else {
// Ignore zygisk modules when zygisk is not enabled
if is_zygisk {
info!("{name}: ignore");
return Ok(());
}
}
modules.push(ModuleInfo {
name: name.to_string(),
z32,
z64,
});
Ok(())
})
.log_ok();
if zygisk_enabled && open_zygisk {
let mut use_memfd = true;
let mut convert_to_memfd = |fd: i32| -> i32 {
if fd < 0 {
return fd;
}
if use_memfd {
let memfd = unsafe {
libc::syscall(
libc::SYS_memfd_create,
raw_cstr!("jit-cache"),
libc::MFD_CLOEXEC,
) as i32
};
if memfd >= 0 {
unsafe {
if libc::sendfile(memfd, fd, ptr::null_mut(), i32::MAX as usize) < 0 {
libc::close(memfd);
} else {
libc::close(fd);
return memfd;
}
}
}
// Some error occurred, don't try again
use_memfd = false;
}
fd
};
modules.iter_mut().for_each(|m| {
m.z32 = convert_to_memfd(m.z32);
m.z64 = convert_to_memfd(m.z64);
});
}
modules
}
impl MagiskD { impl MagiskD {
pub fn handle_modules(&self) { pub fn handle_modules(&self) {
setup_module_mount(); setup_module_mount();
upgrade_modules().ok(); upgrade_modules().ok();
let modules = self.load_modules();
apply_modules(self.zygisk_enabled(), &modules); let zygisk = self.zygisk_enabled.load(Ordering::Acquire);
let modules = collect_modules(zygisk, false);
exec_module_scripts(cstr!("post-fs-data"), &modules);
// Recollect modules (module scripts could remove itself)
let modules = collect_modules(zygisk, true);
if zygisk {
set_zygisk_prop();
}
apply_modules(zygisk, &modules);
self.module_list.set(modules).ok(); self.module_list.set(modules).ok();
} }
} }