Move module list into MagiskD

This commit is contained in:
topjohnwu 2025-01-26 19:41:34 +08:00 committed by John Wu
parent 4dcd733ddd
commit 0d8d6290a3
9 changed files with 78 additions and 75 deletions

View File

@ -179,7 +179,6 @@ bool MagiskD::post_fs_data() const noexcept {
initialize_denylist(); initialize_denylist();
setup_mounts(); setup_mounts();
handle_modules(); handle_modules();
load_modules();
return false; return false;
} }
@ -189,7 +188,7 @@ void MagiskD::late_start() const noexcept {
LOGI("** late_start service mode running\n"); LOGI("** late_start service mode running\n");
exec_common_scripts("service"); exec_common_scripts("service");
exec_module_scripts("service"); exec_module_scripts("service", module_list());
} }
void MagiskD::boot_complete() const noexcept { void MagiskD::boot_complete() const noexcept {

View File

@ -378,7 +378,6 @@ static void daemon_entry() {
default_new(poll_map); default_new(poll_map);
default_new(poll_fds); default_new(poll_fds);
default_new(module_list);
// Register handler for main socket // Register handler for main socket
pollfd main_socket_pfd = { fd, POLLIN, 0 }; pollfd main_socket_pfd = { fd, POLLIN, 0 };

View File

@ -1,6 +1,6 @@
use crate::consts::{MAGISK_FULL_VER, MAIN_CONFIG}; use crate::consts::{MAGISK_FULL_VER, MAIN_CONFIG};
use crate::db::Sqlite3; use crate::db::Sqlite3;
use crate::ffi::{get_magisk_tmp, RequestCode}; use crate::ffi::{get_magisk_tmp, ModuleInfo, RequestCode};
use crate::get_prop; use crate::get_prop;
use crate::logging::{magisk_logging, start_log_daemon}; use crate::logging::{magisk_logging, start_log_daemon};
use crate::package::ManagerInfo; use crate::package::ManagerInfo;
@ -59,6 +59,7 @@ pub struct MagiskD {
pub sql_connection: Mutex<Option<Sqlite3>>, pub sql_connection: Mutex<Option<Sqlite3>>,
pub manager_info: Mutex<ManagerInfo>, pub manager_info: Mutex<ManagerInfo>,
boot_stage_lock: Mutex<BootStateFlags>, boot_stage_lock: Mutex<BootStateFlags>,
module_list: OnceLock<Vec<ModuleInfo>>,
sdk_int: i32, sdk_int: i32,
pub is_emulator: bool, pub is_emulator: bool,
is_recovery: bool, is_recovery: bool,
@ -73,6 +74,14 @@ impl MagiskD {
self.sdk_int self.sdk_int
} }
pub fn set_module_list(&self, module_list: Vec<ModuleInfo>) {
self.module_list.set(module_list).ok();
}
pub fn module_list(&self) -> &Vec<ModuleInfo> {
self.module_list.get().unwrap()
}
pub fn app_data_dir(&self) -> &'static Utf8CStr { pub fn app_data_dir(&self) -> &'static Utf8CStr {
if self.sdk_int >= 24 { if self.sdk_int >= 24 {
cstr!("/data/user_de") cstr!("/data/user_de")

View File

@ -26,16 +26,7 @@ enum class RespondCode : int {
END END
}; };
struct module_info {
std::string name;
int z32 = -1;
#if defined(__LP64__)
int z64 = -1;
#endif
};
extern bool zygisk_enabled; extern bool zygisk_enabled;
extern std::vector<module_info> *module_list;
extern std::string native_bridge; extern std::string native_bridge;
void reset_zygisk(bool restore); void reset_zygisk(bool restore);
@ -58,16 +49,13 @@ void su_daemon_handler(int client, const sock_cred *cred);
void zygisk_handler(int client, const sock_cred *cred); void zygisk_handler(int client, const sock_cred *cred);
// Module stuffs // Module stuffs
void handle_modules();
void load_modules();
void disable_modules(); void disable_modules();
void remove_modules(); void remove_modules();
void exec_module_scripts(const char *stage);
// Scripting // Scripting
void exec_script(const char *script); void exec_script(const char *script);
void exec_common_scripts(const char *stage); void exec_common_scripts(const char *stage);
void exec_module_scripts(const char *stage, const std::vector<std::string_view> &modules); void exec_module_scripts(const char *stage, const rust::Vec<ModuleInfo> &module_list);
void clear_pkg(const char *pkg, int user_id); void clear_pkg(const char *pkg, int user_id);
[[noreturn]] void install_module(const char *file); [[noreturn]] void install_module(const char *file);

View File

@ -135,6 +135,12 @@ pub mod ffi {
notify: bool, notify: bool,
} }
struct ModuleInfo {
name: String,
z32: i32,
z64: i32,
}
unsafe extern "C++" { unsafe extern "C++" {
include!("include/sqlite.hpp"); include!("include/sqlite.hpp");
@ -185,6 +191,8 @@ pub mod ffi {
fn uid_granted_root(&self, mut uid: i32) -> bool; fn uid_granted_root(&self, mut uid: i32) -> bool;
#[cxx_name = "get_manager"] #[cxx_name = "get_manager"]
unsafe fn get_manager_for_cxx(&self, user: i32, ptr: *mut CxxString, install: bool) -> i32; unsafe fn get_manager_for_cxx(&self, user: i32, ptr: *mut CxxString, install: bool) -> i32;
fn set_module_list(&self, module_list: Vec<ModuleInfo>);
fn module_list(&self) -> &Vec<ModuleInfo>;
#[cxx_name = "get_db_settings"] #[cxx_name = "get_db_settings"]
fn get_db_settings_for_cxx(&self, cfg: &mut DbSettings) -> bool; fn get_db_settings_for_cxx(&self, cfg: &mut DbSettings) -> bool;
@ -209,6 +217,8 @@ pub mod ffi {
fn post_fs_data(self: &MagiskD) -> bool; fn post_fs_data(self: &MagiskD) -> bool;
fn late_start(self: &MagiskD); fn late_start(self: &MagiskD);
fn boot_complete(self: &MagiskD); fn boot_complete(self: &MagiskD);
#[allow(dead_code)]
fn handle_modules(self: &MagiskD);
} }
} }

View File

@ -86,7 +86,7 @@ bool dir_node::prepare() {
return upgrade_to_tmpfs; return upgrade_to_tmpfs;
} }
void dir_node::collect_module_files(const char *module, int dfd) { void dir_node::collect_module_files(std::string_view module, int dfd) {
auto dir = xopen_dir(xopenat(dfd, name().data(), O_RDONLY | O_CLOEXEC)); auto dir = xopen_dir(xopenat(dfd, name().data(), O_RDONLY | O_CLOEXEC));
if (!dir) if (!dir)
return; return;
@ -149,7 +149,9 @@ void module_node::mount() {
VLOGD("delete", "null", node_path().data()); VLOGD("delete", "null", node_path().data());
return; return;
} }
std::string path = module + (parent()->root()->prefix + node_path()); std::string path{module.begin(), module.end()};
path += parent()->root()->prefix;
path += node_path();
string mnt_src = module_mnt + path; string mnt_src = module_mnt + path;
{ {
string src = MODULEROOT "/" + path; string src = MODULEROOT "/" + path;
@ -267,9 +269,7 @@ static void inject_zygisk_libs(root_node *system) {
} }
} }
vector<module_info> *module_list; static void load_modules(const rust::Vec<ModuleInfo> &module_list) {
void load_modules() {
node_entry::module_mnt = get_magisk_tmp() + "/"s MODULEMNT "/"; node_entry::module_mnt = get_magisk_tmp() + "/"s MODULEMNT "/";
auto root = make_unique<root_node>(""); auto root = make_unique<root_node>("");
@ -278,14 +278,14 @@ void load_modules() {
char buf[4096]; char buf[4096];
LOGI("* Loading modules\n"); LOGI("* Loading modules\n");
for (const auto &m : *module_list) { for (const auto &m : module_list) {
const char *module = m.name.data(); char *b = buf + ssprintf(buf, sizeof(buf), "%s/" MODULEMNT "/%.*s/",
char *b = buf + ssprintf(buf, sizeof(buf), "%s/" MODULEMNT "/%s/", get_magisk_tmp(), module); get_magisk_tmp(), (int) m.name.size(), m.name.data());
// Read props // Read props
strcpy(b, "system.prop"); strcpy(b, "system.prop");
if (access(buf, F_OK) == 0) { if (access(buf, F_OK) == 0) {
LOGI("%s: loading [system.prop]\n", module); LOGI("%.*s: loading [system.prop]\n", (int) m.name.size(), m.name.data());
// Do NOT go through property service as it could cause boot lock // Do NOT go through property service as it could cause boot lock
load_prop_file(buf, true); load_prop_file(buf, true);
} }
@ -300,10 +300,10 @@ void load_modules() {
if (access(buf, F_OK) != 0) if (access(buf, F_OK) != 0)
continue; continue;
LOGI("%s: loading mount files\n", module); LOGI("%.*s: loading mount files\n", (int) m.name.size(), m.name.data());
b[-1] = '\0'; b[-1] = '\0';
int fd = xopen(buf, O_RDONLY | O_CLOEXEC); int fd = xopen(buf, O_RDONLY | O_CLOEXEC);
system->collect_module_files(module, fd); system->collect_module_files({ m.name.begin(), m.name.end() }, fd);
close(fd); close(fd);
} }
if (get_magisk_tmp() != "/sbin"sv || !str_contains(getenv("PATH") ?: "", "/sbin")) { if (get_magisk_tmp() != "/sbin"sv || !str_contains(getenv("PATH") ?: "", "/sbin")) {
@ -392,8 +392,9 @@ static void foreach_module(Func fn) {
} }
} }
static void collect_modules(bool open_zygisk) { static rust::Vec<ModuleInfo> collect_modules(bool open_zygisk) {
foreach_module([=](int dfd, dirent *entry, int modfd) { rust::Vec<ModuleInfo> modules;
foreach_module([&](int dfd, dirent *entry, int modfd) {
if (faccessat(modfd, "remove", F_OK, 0) == 0) { if (faccessat(modfd, "remove", F_OK, 0) == 0) {
LOGI("%s: remove\n", entry->d_name); LOGI("%s: remove\n", entry->d_name);
auto uninstaller = MODULEROOT + "/"s + entry->d_name + "/uninstall.sh"; auto uninstaller = MODULEROOT + "/"s + entry->d_name + "/uninstall.sh";
@ -407,7 +408,7 @@ static void collect_modules(bool open_zygisk) {
if (faccessat(modfd, "disable", F_OK, 0) == 0) if (faccessat(modfd, "disable", F_OK, 0) == 0)
return; return;
module_info info; ModuleInfo info{};
if (zygisk_enabled) { if (zygisk_enabled) {
// Riru and its modules are not compatible with zygisk // Riru and its modules are not compatible with zygisk
if (entry->d_name == "riru-core"sv || faccessat(modfd, "riru", F_OK, 0) == 0) { if (entry->d_name == "riru-core"sv || faccessat(modfd, "riru", F_OK, 0) == 0) {
@ -417,11 +418,13 @@ static void collect_modules(bool open_zygisk) {
if (open_zygisk) { if (open_zygisk) {
#if defined(__arm__) #if defined(__arm__)
info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC); info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC);
info.z64 = -1;
#elif defined(__aarch64__) #elif defined(__aarch64__)
info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC); info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC);
info.z64 = openat(modfd, "zygisk/arm64-v8a.so", O_RDONLY | O_CLOEXEC); info.z64 = openat(modfd, "zygisk/arm64-v8a.so", O_RDONLY | O_CLOEXEC);
#elif defined(__i386__) #elif defined(__i386__)
info.z32 = openat(modfd, "zygisk/x86.so", O_RDONLY | O_CLOEXEC); info.z32 = openat(modfd, "zygisk/x86.so", O_RDONLY | O_CLOEXEC);
info.z64 = -1;
#elif defined(__x86_64__) #elif defined(__x86_64__)
info.z32 = openat(modfd, "zygisk/x86.so", O_RDONLY | O_CLOEXEC); info.z32 = openat(modfd, "zygisk/x86.so", O_RDONLY | O_CLOEXEC);
info.z64 = openat(modfd, "zygisk/x86_64.so", O_RDONLY | O_CLOEXEC); info.z64 = openat(modfd, "zygisk/x86_64.so", O_RDONLY | O_CLOEXEC);
@ -441,7 +444,7 @@ static void collect_modules(bool open_zygisk) {
} }
} }
info.name = entry->d_name; info.name = entry->d_name;
module_list->push_back(info); modules.push_back(std::move(info));
}); });
if (zygisk_enabled) { if (zygisk_enabled) {
bool use_memfd = true; bool use_memfd = true;
@ -461,23 +464,23 @@ static void collect_modules(bool open_zygisk) {
} }
return fd; return fd;
}; };
std::for_each(module_list->begin(), module_list->end(), [&](module_info &info) { std::for_each(modules.begin(),modules.end(), [&](ModuleInfo &info) {
info.z32 = convert_to_memfd(info.z32); info.z32 = convert_to_memfd(info.z32);
#if defined(__LP64__) #if defined(__LP64__)
info.z64 = convert_to_memfd(info.z64); info.z64 = convert_to_memfd(info.z64);
#endif #endif
}); });
} }
return modules;
} }
void handle_modules() { void MagiskD::handle_modules() const noexcept {
prepare_modules(); prepare_modules();
collect_modules(false); exec_module_scripts("post-fs-data", collect_modules(false));
exec_module_scripts("post-fs-data");
// Recollect modules (module scripts could remove itself) // Recollect modules (module scripts could remove itself)
module_list->clear(); auto list = collect_modules(true);
collect_modules(true); load_modules(list);
set_module_list(std::move(list));
} }
static int check_rules_dir(char *buf, size_t sz) { static int check_rules_dir(char *buf, size_t sz) {
@ -517,10 +520,3 @@ void remove_modules() {
}); });
rm_rf(MODULEROOT); rm_rf(MODULEROOT);
} }
void exec_module_scripts(const char *stage) {
vector<string_view> module_names;
std::transform(module_list->begin(), module_list->end(), std::back_inserter(module_names),
[](const module_info &info) -> string_view { return info.name; });
exec_module_scripts(stage, module_names);
}

View File

@ -105,7 +105,7 @@ public:
**************/ **************/
// Traverse through module directories to generate a tree of module files // Traverse through module directories to generate a tree of module files
void collect_module_files(const char *module, int dfd); void collect_module_files(std::string_view module, int dfd);
// Traverse through the real filesystem and prepare the tree for magic mount. // Traverse through the real filesystem and prepare the tree for magic mount.
// Return true to indicate that this node needs to be upgraded to tmpfs_node. // Return true to indicate that this node needs to be upgraded to tmpfs_node.
@ -279,16 +279,16 @@ public:
class module_node : public node_entry { class module_node : public node_entry {
public: public:
module_node(const char *module, dirent *entry) module_node(std::string_view module, dirent *entry)
: node_entry(entry->d_name, entry->d_type, this), module(module) {} : node_entry(entry->d_name, entry->d_type, this), module(module) {}
module_node(node_entry *node, const char *module) : node_entry(this), module(module) { module_node(node_entry *node, std::string_view module) : node_entry(this), module(module) {
node_entry::consume(node); node_entry::consume(node);
} }
void mount() override; void mount() override;
private: private:
const char *module; std::string_view module;
}; };
// Don't create tmpfs_node before prepare // Don't create tmpfs_node before prepare

View File

@ -117,9 +117,9 @@ static bool operator>(const timespec &a, const timespec &b) {
return a.tv_nsec > b.tv_nsec; return a.tv_nsec > b.tv_nsec;
} }
void exec_module_scripts(const char *stage, const vector<string_view> &modules) { void exec_module_scripts(const char *stage, const rust::Vec<ModuleInfo> &module_list) {
LOGI("* Running module %s scripts\n", stage); LOGI("* Running module %s scripts\n", stage);
if (modules.empty()) if (module_list.empty())
return; return;
bool pfs = stage == "post-fs-data"sv; bool pfs = stage == "post-fs-data"sv;
@ -134,12 +134,11 @@ void exec_module_scripts(const char *stage, const vector<string_view> &modules)
PFS_SETUP() PFS_SETUP()
char path[4096]; char path[4096];
for (auto &m : modules) { for (auto &m : module_list) {
const char *module = m.data(); sprintf(path, MODULEROOT "/%.*s/%s.sh", (int) m.name.size(), m.name.data(), stage);
sprintf(path, MODULEROOT "/%s/%s.sh", module, stage);
if (access(path, F_OK) == -1) if (access(path, F_OK) == -1)
continue; continue;
LOGI("%s: exec [%s.sh]\n", module, stage); LOGI("%.*s: exec [%s.sh]\n", (int) m.name.size(), m.name.data(), stage);
exec_t exec { exec_t exec {
.pre_exec = set_script_env, .pre_exec = set_script_env,
.fork = pfs ? xfork : fork_dont_care .fork = pfs ? xfork : fork_dont_care

View File

@ -15,6 +15,8 @@ using namespace std;
string native_bridge = "0"; string native_bridge = "0";
using modules_t = const rust::Vec<ModuleInfo>&;
static bool is_compatible_with(uint32_t) { static bool is_compatible_with(uint32_t) {
zygisk_logging(); zygisk_logging();
hook_entry(); hook_entry();
@ -55,20 +57,20 @@ int remote_get_info(int uid, const char *process, uint32_t *flags, vector<int> &
// The following code runs in magiskd // The following code runs in magiskd
static vector<int> get_module_fds(bool is_64_bit) { static vector<int> get_module_fds(bool is_64_bit, modules_t module_list) {
vector<int> fds; vector<int> fds;
// All fds passed to send_fds have to be valid file descriptors. // All fds passed to send_fds have to be valid file descriptors.
// To workaround this issue, send over STDOUT_FILENO as an indicator of an // To workaround this issue, send over STDOUT_FILENO as an indicator of an
// invalid fd as it will always be /dev/null in magiskd // invalid fd as it will always be /dev/null in magiskd
#if defined(__LP64__) #if defined(__LP64__)
if (is_64_bit) { if (is_64_bit) {
std::transform(module_list->begin(), module_list->end(), std::back_inserter(fds), std::transform(module_list.begin(), module_list.end(), std::back_inserter(fds),
[](const module_info &info) { return info.z64 < 0 ? STDOUT_FILENO : info.z64; }); [](const ModuleInfo &info) { return info.z64 < 0 ? STDOUT_FILENO : info.z64; });
} else } else
#endif #endif
{ {
std::transform(module_list->begin(), module_list->end(), std::back_inserter(fds), std::transform(module_list.begin(), module_list.end(), std::back_inserter(fds),
[](const module_info &info) { return info.z32 < 0 ? STDOUT_FILENO : info.z32; }); [](const ModuleInfo &info) { return info.z32 < 0 ? STDOUT_FILENO : info.z32; });
} }
return fds; return fds;
} }
@ -77,9 +79,10 @@ static pthread_mutex_t zygiskd_lock = PTHREAD_MUTEX_INITIALIZER;
static int zygiskd_sockets[] = { -1, -1 }; static int zygiskd_sockets[] = { -1, -1 };
#define zygiskd_socket zygiskd_sockets[is_64_bit] #define zygiskd_socket zygiskd_sockets[is_64_bit]
static void connect_companion(int client, bool is_64_bit) { static void connect_companion(int client, modules_t module_list) {
mutex_guard g(zygiskd_lock); mutex_guard g(zygiskd_lock);
bool is_64_bit = read_int(client);
if (zygiskd_socket >= 0) { if (zygiskd_socket >= 0) {
// Make sure the socket is still valid // Make sure the socket is still valid
pollfd pfd = { zygiskd_socket, 0, 0 }; pollfd pfd = { zygiskd_socket, 0, 0 };
@ -109,7 +112,7 @@ static void connect_companion(int client, bool is_64_bit) {
exit(-1); exit(-1);
} }
close(fds[1]); close(fds[1]);
vector<int> module_fds = get_module_fds(is_64_bit); vector<int> module_fds = get_module_fds(is_64_bit, module_list);
send_fds(zygiskd_socket, module_fds.data(), module_fds.size()); send_fds(zygiskd_socket, module_fds.data(), module_fds.size());
// Wait for ack // Wait for ack
if (read_int(zygiskd_socket) != 0) { if (read_int(zygiskd_socket) != 0) {
@ -120,7 +123,7 @@ static void connect_companion(int client, bool is_64_bit) {
send_fd(zygiskd_socket, client); send_fd(zygiskd_socket, client);
} }
static void get_process_info(int client, const sock_cred *cred) { static void get_process_info(int client, const sock_cred *cred, modules_t module_list) {
int uid = read_int(client); int uid = read_int(client);
string process = read_string(client); string process = read_string(client);
int arch = read_int(client); int arch = read_int(client);
@ -144,7 +147,7 @@ static void get_process_info(int client, const sock_cred *cred) {
xwrite(client, &flags, sizeof(flags)); xwrite(client, &flags, sizeof(flags));
if (should_load_modules(flags)) { if (should_load_modules(flags)) {
vector<int> fds = get_module_fds(arch); vector<int> fds = get_module_fds(arch, module_list);
send_fds(client, fds.data(), fds.size()); send_fds(client, fds.data(), fds.size());
} }
@ -159,12 +162,12 @@ static void get_process_info(int client, const sock_cred *cred) {
xxread(client, &l, sizeof(l)); xxread(client, &l, sizeof(l));
bits.emplace_back(l); bits.emplace_back(l);
} }
for (int id = 0; id < module_list->size(); ++id) { for (int id = 0; id < module_list.size(); ++id) {
if (!as_const(bits)[id]) { if (!as_const(bits)[id]) {
// Either not a zygisk module, or incompatible // Either not a zygisk module, or incompatible
char buf[4096]; char buf[4096];
ssprintf(buf, sizeof(buf), MODULEROOT "/%s/zygisk", ssprintf(buf, sizeof(buf), MODULEROOT "/%s/zygisk",
module_list->operator[](id).name.data()); module_list[id].name.data());
if (int dirfd = open(buf, O_RDONLY | O_CLOEXEC); dirfd >= 0) { if (int dirfd = open(buf, O_RDONLY | O_CLOEXEC); dirfd >= 0) {
close(xopenat(dirfd, "unloaded", O_CREAT | O_RDONLY, 0644)); close(xopenat(dirfd, "unloaded", O_CREAT | O_RDONLY, 0644));
close(dirfd); close(dirfd);
@ -173,28 +176,28 @@ static void get_process_info(int client, const sock_cred *cred) {
} }
} }
static void get_moddir(int client) { static void get_moddir(int client, modules_t module_list) {
int id = read_int(client); int id = read_int(client);
char buf[4096]; char buf[4096];
ssprintf(buf, sizeof(buf), MODULEROOT "/%s", module_list->operator[](id).name.data()); auto &m = module_list[id];
ssprintf(buf, sizeof(buf), MODULEROOT "/%.*s", (int) m.name.size(), m.name.data());
int dfd = xopen(buf, O_RDONLY | O_CLOEXEC); int dfd = xopen(buf, O_RDONLY | O_CLOEXEC);
send_fd(client, dfd); send_fd(client, dfd);
close(dfd); close(dfd);
} }
void zygisk_handler(int client, const sock_cred *cred) { void zygisk_handler(int client, const sock_cred *cred) {
auto &module_list = MagiskD().module_list();
int code = read_int(client); int code = read_int(client);
switch (code) { switch (code) {
case ZygiskRequest::GET_INFO: case ZygiskRequest::GET_INFO:
get_process_info(client, cred); get_process_info(client, cred, module_list);
break; break;
case ZygiskRequest::CONNECT_COMPANION: { case ZygiskRequest::CONNECT_COMPANION:
int arch = read_int(client); connect_companion(client, module_list);
connect_companion(client, arch);
break; break;
}
case ZygiskRequest::GET_MODDIR: case ZygiskRequest::GET_MODDIR:
get_moddir(client); get_moddir(client, module_list);
break; break;
default: default:
// Unknown code // Unknown code