Migrate disable/remove modules to Rust

This commit is contained in:
topjohnwu
2025-08-03 20:08:34 -07:00
committed by John Wu
parent 7961be5cfa
commit 589a270b8d
9 changed files with 184 additions and 198 deletions

View File

@@ -1,15 +1,15 @@
use crate::consts::{MAGISK_FULL_VER, MAGISK_PROC_CON, MAIN_CONFIG, ROOTMNT, ROOTOVL, SECURE_DIR}; use crate::consts::{MAGISK_FULL_VER, MAGISK_PROC_CON, MAIN_CONFIG, ROOTMNT, ROOTOVL, SECURE_DIR};
use crate::db::Sqlite3; use crate::db::Sqlite3;
use crate::ffi::{ use crate::ffi::{
DbEntryKey, ModuleInfo, RequestCode, check_key_combo, disable_modules, exec_common_scripts, DbEntryKey, ModuleInfo, RequestCode, check_key_combo, exec_common_scripts, exec_module_scripts,
exec_module_scripts, get_magisk_tmp, initialize_denylist, setup_magisk_env, get_magisk_tmp, get_prop, initialize_denylist, set_prop, setup_magisk_env,
}; };
use crate::logging::{magisk_logging, setup_logfile, start_log_daemon}; use crate::logging::{magisk_logging, setup_logfile, start_log_daemon};
use crate::module::disable_modules;
use crate::mount::{clean_mounts, setup_preinit_dir}; use crate::mount::{clean_mounts, setup_preinit_dir};
use crate::package::ManagerInfo; use crate::package::ManagerInfo;
use crate::selinux::restore_tmpcon; use crate::selinux::restore_tmpcon;
use crate::su::SuInfo; use crate::su::SuInfo;
use crate::{get_prop, set_prop};
use base::libc::{O_APPEND, O_CLOEXEC, O_RDONLY, O_WRONLY}; use base::libc::{O_APPEND, O_CLOEXEC, O_RDONLY, O_WRONLY};
use base::{ use base::{
AtomicArc, BufReadExt, FsPathBuilder, ResultExt, Utf8CStr, Utf8CStrBuf, cstr, error, info, libc, AtomicArc, BufReadExt, FsPathBuilder, ResultExt, Utf8CStr, Utf8CStrBuf, cstr, error, info, libc,

View File

@@ -92,10 +92,6 @@ void exec_task(std::function<void()> &&task);
// Daemon handlers // Daemon handlers
void denylist_handler(int client, const sock_cred *cred); void denylist_handler(int client, const sock_cred *cred);
// Module stuffs
void disable_modules();
void remove_modules();
// Scripting // Scripting
void install_apk(rust::Utf8CStr apk); void install_apk(rust::Utf8CStr apk);
void uninstall_pkg(rust::Utf8CStr pkg); void uninstall_pkg(rust::Utf8CStr pkg);
@@ -125,3 +121,4 @@ static inline rust::Utf8CStr get_magisk_tmp_rs() { return get_magisk_tmp(); }
static inline rust::String resolve_preinit_dir_rs(rust::Utf8CStr base_dir) { static inline rust::String resolve_preinit_dir_rs(rust::Utf8CStr base_dir) {
return resolve_preinit_dir(base_dir.c_str()); return resolve_preinit_dir(base_dir.c_str());
} }
static inline void exec_script_rs(rust::Utf8CStr script) { exec_script(script.data()); }

View File

@@ -20,12 +20,19 @@ private:
}; };
// System properties // System properties
rust::String get_prop_rs(const char *name, bool persist);
std::string get_prop(const char *name, bool persist = false); std::string get_prop(const char *name, bool persist = false);
int delete_prop(const char *name, bool persist = false); int delete_prop(const char *name, bool persist = false);
int set_prop(const char *name, const char *value, bool skip_svc = false); int set_prop(const char *name, const char *value, bool skip_svc = false);
void load_prop_file(const char *filename, bool skip_svc = false); void load_prop_file(const char *filename, bool skip_svc = false);
static inline void prop_cb_exec(prop_cb &cb, const char *name, const char *value, uint32_t serial) { // Rust bindings
cb.exec(name, value, serial); rust::String get_prop_rs(rust::Utf8CStr name, bool persist);
static inline int set_prop_rs(rust::Utf8CStr name, rust::Utf8CStr value, bool skip_svc) {
return set_prop(name.data(), value.data(), skip_svc);
}
static inline void load_prop_file_rs(rust::Utf8CStr filename, bool skip_svc) {
load_prop_file(filename.data(), skip_svc);
}
static inline void prop_cb_exec(prop_cb &cb, rust::Utf8CStr name, rust::Utf8CStr value, uint32_t serial) {
cb.exec(name.data(), value.data(), serial);
} }

View File

@@ -7,11 +7,12 @@
use crate::ffi::SuRequest; use crate::ffi::SuRequest;
use crate::socket::Encodable; use crate::socket::Encodable;
use base::{Utf8CStr, libc}; use base::libc;
use cxx::{ExternType, type_id}; use cxx::{ExternType, type_id};
use daemon::{MagiskD, daemon_entry}; use daemon::{MagiskD, daemon_entry};
use derive::Decodable; use derive::Decodable;
use logging::{android_logging, setup_logfile, zygisk_close_logd, zygisk_get_logd, zygisk_logging}; use logging::{android_logging, setup_logfile, zygisk_close_logd, zygisk_get_logd, zygisk_logging};
use module::remove_modules;
use mount::{find_preinit_device, revert_unmount}; use mount::{find_preinit_device, revert_unmount};
use resetprop::{persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop}; use resetprop::{persist_delete_prop, persist_get_prop, persist_get_props, persist_set_prop};
use selinux::{lgetfilecon, lsetfilecon, restorecon, setfilecon}; use selinux::{lgetfilecon, lsetfilecon, restorecon, setfilecon};
@@ -133,23 +134,6 @@ pub mod ffi {
request: &'a SuRequest, request: &'a SuRequest,
} }
extern "C++" {
include!("include/resetprop.hpp");
#[cxx_name = "prop_cb"]
type PropCb;
unsafe fn get_prop_rs(name: *const c_char, persist: bool) -> String;
#[cxx_name = "set_prop"]
unsafe fn set_prop_rs(name: *const c_char, value: *const c_char, skip_svc: bool) -> i32;
unsafe fn prop_cb_exec(
cb: Pin<&mut PropCb>,
name: *const c_char,
value: *const c_char,
serial: u32,
);
unsafe fn load_prop_file(filename: *const c_char, skip_svc: bool);
}
unsafe extern "C++" { unsafe extern "C++" {
#[namespace = "rust"] #[namespace = "rust"]
#[cxx_name = "Utf8CStr"] #[cxx_name = "Utf8CStr"]
@@ -165,7 +149,8 @@ pub mod ffi {
fn resolve_preinit_dir(base_dir: Utf8CStrRef) -> String; fn resolve_preinit_dir(base_dir: Utf8CStrRef) -> String;
fn setup_magisk_env() -> bool; fn setup_magisk_env() -> bool;
fn check_key_combo() -> bool; fn check_key_combo() -> bool;
fn disable_modules(); #[cxx_name = "exec_script_rs"]
fn exec_script(script: Utf8CStrRef);
fn exec_common_scripts(stage: Utf8CStrRef); fn exec_common_scripts(stage: Utf8CStrRef);
fn exec_module_scripts(state: Utf8CStrRef, modules: &Vec<ModuleInfo>); fn exec_module_scripts(state: Utf8CStrRef, modules: &Vec<ModuleInfo>);
fn install_apk(apk: Utf8CStrRef); fn install_apk(apk: Utf8CStrRef);
@@ -193,6 +178,18 @@ pub mod ffi {
fn get_text(self: &DbValues, index: i32) -> &str; fn get_text(self: &DbValues, index: i32) -> &str;
fn bind_text(self: Pin<&mut DbStatement>, index: i32, val: &str) -> i32; fn bind_text(self: Pin<&mut DbStatement>, index: i32, val: &str) -> i32;
fn bind_int64(self: Pin<&mut DbStatement>, index: i32, val: i64) -> i32; fn bind_int64(self: Pin<&mut DbStatement>, index: i32, val: i64) -> i32;
include!("include/resetprop.hpp");
#[cxx_name = "prop_cb"]
type PropCb;
#[cxx_name = "get_prop_rs"]
fn get_prop(name: Utf8CStrRef, persist: bool) -> String;
#[cxx_name = "set_prop_rs"]
fn set_prop(name: Utf8CStrRef, value: Utf8CStrRef, skip_svc: bool) -> i32;
#[cxx_name = "load_prop_file_rs"]
fn load_prop_file(filename: Utf8CStrRef, skip_svc: bool);
fn prop_cb_exec(cb: Pin<&mut PropCb>, name: Utf8CStrRef, value: Utf8CStrRef, serial: u32);
} }
extern "Rust" { extern "Rust" {
@@ -203,6 +200,7 @@ pub mod ffi {
fn setup_logfile(); fn setup_logfile();
fn find_preinit_device() -> String; fn find_preinit_device() -> String;
fn revert_unmount(pid: i32); fn revert_unmount(pid: i32);
fn remove_modules();
fn zygisk_should_load_module(flags: u32) -> bool; fn zygisk_should_load_module(flags: u32) -> bool;
unsafe fn persist_get_prop(name: Utf8CStrRef, prop_cb: Pin<&mut PropCb>); unsafe fn persist_get_prop(name: Utf8CStrRef, prop_cb: Pin<&mut PropCb>);
unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>); unsafe fn persist_get_props(prop_cb: Pin<&mut PropCb>);
@@ -277,15 +275,3 @@ impl SuRequest {
} }
} }
} }
pub fn get_prop(name: &Utf8CStr, persist: bool) -> String {
unsafe { ffi::get_prop_rs(name.as_ptr(), persist) }
}
pub fn set_prop(name: &Utf8CStr, value: &Utf8CStr, skip_svc: bool) -> bool {
unsafe { ffi::set_prop_rs(name.as_ptr(), value.as_ptr(), skip_svc) == 0 }
}
pub fn load_prop_file(filename: &Utf8CStr, skip_svc: bool) {
unsafe { ffi::load_prop_file(filename.as_ptr(), skip_svc) };
}

View File

@@ -117,41 +117,3 @@ rust::Vec<ModuleInfo> MagiskD::load_modules() const noexcept {
} }
return list; return list;
} }
static int check_rules_dir(char *buf, size_t sz) {
int off = ssprintf(buf, sz, "%s/" PREINITMIRR, get_magisk_tmp());
struct stat st1{};
struct stat st2{};
if (xstat(buf, &st1) < 0 || xstat(MODULEROOT, &st2) < 0)
return 0;
if (st1.st_dev == st2.st_dev && st1.st_ino == st2.st_ino)
return 0;
return off;
}
void disable_modules() {
char buf[4096];
int off = check_rules_dir(buf, sizeof(buf));
foreach_module([&](int, dirent *entry, int modfd) {
close(xopenat(modfd, "disable", O_RDONLY | O_CREAT | O_CLOEXEC, 0));
if (off) {
ssprintf(buf + off, sizeof(buf) - off, "/%s/sepolicy.rule", entry->d_name);
unlink(buf);
}
});
}
void remove_modules() {
char buf[4096];
int off = check_rules_dir(buf, sizeof(buf));
foreach_module([&](int, dirent *entry, int) {
auto uninstaller = MODULEROOT + "/"s + entry->d_name + "/uninstall.sh";
if (access(uninstaller.data(), F_OK) == 0)
exec_script(uninstaller.data());
if (off) {
ssprintf(buf + off, sizeof(buf) - off, "/%s/sepolicy.rule", entry->d_name);
unlink(buf);
}
});
rm_rf(MODULEROOT);
}

View File

@@ -1,11 +1,11 @@
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, get_magisk_tmp, get_zygisk_lib_name}; use crate::ffi::{ModuleInfo, exec_script, get_magisk_tmp, get_zygisk_lib_name, load_prop_file};
use crate::load_prop_file;
use crate::mount::setup_module_mount; use crate::mount::setup_module_mount;
use base::{ use base::{
Directory, FsPathBuilder, LibcReturn, LoggedResult, OsResultStatic, ResultExt, Utf8CStr, DirEntry, Directory, FsPathBuilder, LibcReturn, LoggedResult, OsResultStatic, ResultExt,
Utf8CStrBuf, Utf8CString, WalkResult, clone_attr, cstr, debug, error, info, libc, warn, Utf8CStr, Utf8CStrBuf, Utf8CString, WalkResult, clone_attr, cstr, debug, error, info, libc,
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;
@@ -550,48 +550,7 @@ fn inject_zygisk_bins(system: &mut FsNode) {
} }
} }
fn prepare_modules() -> LoggedResult<()> { fn apply_modules(zygisk: bool, module_list: &[ModuleInfo]) {
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 {
fn apply_modules(&self, module_list: &[ModuleInfo]) {
let mut system = FsNode::new_dir(); let mut system = FsNode::new_dir();
// Build all the base "prefix" paths // Build all the base "prefix" paths
@@ -658,7 +617,7 @@ impl MagiskD {
if get_magisk_tmp() != "/sbin" || get_path_env().split(":").all(|s| s != "/sbin") { if get_magisk_tmp() != "/sbin" || get_path_env().split(":").all(|s| s != "/sbin") {
inject_magisk_bins(&mut system); inject_magisk_bins(&mut system);
} }
if self.zygisk_enabled() { if zygisk {
inject_zygisk_bins(&mut system); inject_zygisk_bins(&mut system);
} }
@@ -699,11 +658,87 @@ impl MagiskD {
} }
} }
fn upgrade_modules() -> LoggedResult<()> {
let mut upgrade = Directory::open(cstr!(MODULEUPGRADE))?;
let ufd = upgrade.as_raw_fd();
let root = Directory::open(cstr!(MODULEROOT))?;
while let Some(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(())
}
fn for_each_module(func: impl Fn(&DirEntry) -> LoggedResult<()>) -> LoggedResult<()> {
let mut root = Directory::open(cstr!(MODULEROOT))?;
while let Some(ref e) = root.read()? {
if e.is_dir() && e.name() != ".core" {
func(e)?;
}
}
Ok(())
}
pub fn disable_modules() {
for_each_module(|e| {
let dir = e.open_as_dir()?;
dir.open_as_file_at(cstr!("disable"), O_RDONLY | O_CREAT | O_CLOEXEC, 0)?;
Ok(())
})
.log_ok();
}
pub fn remove_modules() {
for_each_module(|e| {
let dir = e.open_as_dir()?;
if dir.contains_path(cstr!("uninstall.sh")) {
let script = cstr::buf::default()
.join_path(MODULEROOT)
.join_path(e.name())
.join_path("uninstall.sh");
exec_script(&script);
}
Ok(())
})
.log_ok();
cstr!(MODULEROOT).remove_all().log_ok();
}
impl MagiskD {
pub fn handle_modules(&self) { pub fn handle_modules(&self) {
setup_module_mount(); setup_module_mount();
prepare_modules().ok(); upgrade_modules().ok();
let modules = self.load_modules(); let modules = self.load_modules();
self.apply_modules(&modules); apply_modules(self.zygisk_enabled(), &modules);
self.module_list.set(modules).ok(); self.module_list.set(modules).ok();
} }
} }

View File

@@ -12,8 +12,7 @@ use base::{
}; };
use crate::consts::{MODULEMNT, MODULEROOT, PREINITDEV, PREINITMIRR, WORKERDIR}; use crate::consts::{MODULEMNT, MODULEROOT, PREINITDEV, PREINITMIRR, WORKERDIR};
use crate::ffi::{get_magisk_tmp, resolve_preinit_dir, switch_mnt_ns}; use crate::ffi::{get_magisk_tmp, get_prop, resolve_preinit_dir, switch_mnt_ns};
use crate::get_prop;
pub fn setup_preinit_dir() { pub fn setup_preinit_dir() {
let magisk_tmp = get_magisk_tmp(); let magisk_tmp = get_magisk_tmp();

View File

@@ -29,7 +29,7 @@ trait PropCbExec {
impl PropCbExec for Pin<&mut PropCb> { impl PropCbExec for Pin<&mut PropCb> {
fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) { fn exec(&mut self, name: &Utf8CStr, value: &Utf8CStr) {
unsafe { prop_cb_exec(self.as_mut(), name.as_ptr(), value.as_ptr(), u32::MAX) } prop_cb_exec(self.as_mut(), name, value, u32::MAX)
} }
} }

View File

@@ -429,8 +429,8 @@ static StringType get_prop_impl(const char *name, bool persist) {
return get_prop<StringType>(name, flags); return get_prop<StringType>(name, flags);
} }
rust::String get_prop_rs(const char *name, bool persist) { rust::String get_prop_rs(rust::Utf8CStr name, bool persist) {
return get_prop_impl<rust::String>(name, persist); return get_prop_impl<rust::String>(name.data(), persist);
} }
string get_prop(const char *name, bool persist) { string get_prop(const char *name, bool persist) {