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();
setup_mounts();
handle_modules();
load_modules();
return false;
}
@ -189,7 +188,7 @@ void MagiskD::late_start() const noexcept {
LOGI("** late_start service mode running\n");
exec_common_scripts("service");
exec_module_scripts("service");
exec_module_scripts("service", module_list());
}
void MagiskD::boot_complete() const noexcept {

View File

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

View File

@ -1,6 +1,6 @@
use crate::consts::{MAGISK_FULL_VER, MAIN_CONFIG};
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::logging::{magisk_logging, start_log_daemon};
use crate::package::ManagerInfo;
@ -59,6 +59,7 @@ pub struct MagiskD {
pub sql_connection: Mutex<Option<Sqlite3>>,
pub manager_info: Mutex<ManagerInfo>,
boot_stage_lock: Mutex<BootStateFlags>,
module_list: OnceLock<Vec<ModuleInfo>>,
sdk_int: i32,
pub is_emulator: bool,
is_recovery: bool,
@ -73,6 +74,14 @@ impl MagiskD {
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 {
if self.sdk_int >= 24 {
cstr!("/data/user_de")

View File

@ -26,16 +26,7 @@ enum class RespondCode : int {
END
};
struct module_info {
std::string name;
int z32 = -1;
#if defined(__LP64__)
int z64 = -1;
#endif
};
extern bool zygisk_enabled;
extern std::vector<module_info> *module_list;
extern std::string native_bridge;
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);
// Module stuffs
void handle_modules();
void load_modules();
void disable_modules();
void remove_modules();
void exec_module_scripts(const char *stage);
// Scripting
void exec_script(const char *script);
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);
[[noreturn]] void install_module(const char *file);

View File

@ -135,6 +135,12 @@ pub mod ffi {
notify: bool,
}
struct ModuleInfo {
name: String,
z32: i32,
z64: i32,
}
unsafe extern "C++" {
include!("include/sqlite.hpp");
@ -185,6 +191,8 @@ pub mod ffi {
fn uid_granted_root(&self, mut uid: i32) -> bool;
#[cxx_name = "get_manager"]
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"]
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 late_start(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;
}
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));
if (!dir)
return;
@ -149,7 +149,9 @@ void module_node::mount() {
VLOGD("delete", "null", node_path().data());
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 src = MODULEROOT "/" + path;
@ -267,9 +269,7 @@ static void inject_zygisk_libs(root_node *system) {
}
}
vector<module_info> *module_list;
void load_modules() {
static void load_modules(const rust::Vec<ModuleInfo> &module_list) {
node_entry::module_mnt = get_magisk_tmp() + "/"s MODULEMNT "/";
auto root = make_unique<root_node>("");
@ -278,14 +278,14 @@ void load_modules() {
char buf[4096];
LOGI("* Loading modules\n");
for (const auto &m : *module_list) {
const char *module = m.name.data();
char *b = buf + ssprintf(buf, sizeof(buf), "%s/" MODULEMNT "/%s/", get_magisk_tmp(), module);
for (const auto &m : module_list) {
char *b = buf + ssprintf(buf, sizeof(buf), "%s/" MODULEMNT "/%.*s/",
get_magisk_tmp(), (int) m.name.size(), m.name.data());
// Read props
strcpy(b, "system.prop");
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
load_prop_file(buf, true);
}
@ -300,10 +300,10 @@ void load_modules() {
if (access(buf, F_OK) != 0)
continue;
LOGI("%s: loading mount files\n", module);
LOGI("%.*s: loading mount files\n", (int) m.name.size(), m.name.data());
b[-1] = '\0';
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);
}
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) {
foreach_module([=](int dfd, dirent *entry, int modfd) {
static rust::Vec<ModuleInfo> collect_modules(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";
@ -407,7 +408,7 @@ static void collect_modules(bool open_zygisk) {
if (faccessat(modfd, "disable", F_OK, 0) == 0)
return;
module_info info;
ModuleInfo info{};
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) {
@ -417,11 +418,13 @@ static void collect_modules(bool open_zygisk) {
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);
@ -441,7 +444,7 @@ static void collect_modules(bool open_zygisk) {
}
}
info.name = entry->d_name;
module_list->push_back(info);
modules.push_back(std::move(info));
});
if (zygisk_enabled) {
bool use_memfd = true;
@ -461,23 +464,23 @@ static void collect_modules(bool open_zygisk) {
}
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);
#if defined(__LP64__)
info.z64 = convert_to_memfd(info.z64);
#endif
});
}
return modules;
}
void handle_modules() {
void MagiskD::handle_modules() const noexcept {
prepare_modules();
collect_modules(false);
exec_module_scripts("post-fs-data");
exec_module_scripts("post-fs-data", collect_modules(false));
// Recollect modules (module scripts could remove itself)
module_list->clear();
collect_modules(true);
auto list = collect_modules(true);
load_modules(list);
set_module_list(std::move(list));
}
static int check_rules_dir(char *buf, size_t sz) {
@ -517,10 +520,3 @@ void remove_modules() {
});
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
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.
// 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 {
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) {}
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);
}
void mount() override;
private:
const char *module;
std::string_view module;
};
// 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;
}
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);
if (modules.empty())
if (module_list.empty())
return;
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()
char path[4096];
for (auto &m : modules) {
const char *module = m.data();
sprintf(path, MODULEROOT "/%s/%s.sh", module, stage);
for (auto &m : module_list) {
sprintf(path, MODULEROOT "/%.*s/%s.sh", (int) m.name.size(), m.name.data(), stage);
if (access(path, F_OK) == -1)
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 {
.pre_exec = set_script_env,
.fork = pfs ? xfork : fork_dont_care

View File

@ -15,6 +15,8 @@ using namespace std;
string native_bridge = "0";
using modules_t = const rust::Vec<ModuleInfo>&;
static bool is_compatible_with(uint32_t) {
zygisk_logging();
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
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;
// 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
// invalid fd as it will always be /dev/null in magiskd
#if defined(__LP64__)
if (is_64_bit) {
std::transform(module_list->begin(), module_list->end(), std::back_inserter(fds),
[](const module_info &info) { return info.z64 < 0 ? STDOUT_FILENO : info.z64; });
std::transform(module_list.begin(), module_list.end(), std::back_inserter(fds),
[](const ModuleInfo &info) { return info.z64 < 0 ? STDOUT_FILENO : info.z64; });
} else
#endif
{
std::transform(module_list->begin(), module_list->end(), std::back_inserter(fds),
[](const module_info &info) { return info.z32 < 0 ? STDOUT_FILENO : info.z32; });
std::transform(module_list.begin(), module_list.end(), std::back_inserter(fds),
[](const ModuleInfo &info) { return info.z32 < 0 ? STDOUT_FILENO : info.z32; });
}
return fds;
}
@ -77,9 +79,10 @@ static pthread_mutex_t zygiskd_lock = PTHREAD_MUTEX_INITIALIZER;
static int zygiskd_sockets[] = { -1, -1 };
#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);
bool is_64_bit = read_int(client);
if (zygiskd_socket >= 0) {
// Make sure the socket is still valid
pollfd pfd = { zygiskd_socket, 0, 0 };
@ -109,7 +112,7 @@ static void connect_companion(int client, bool is_64_bit) {
exit(-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());
// Wait for ack
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);
}
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);
string process = read_string(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));
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());
}
@ -159,12 +162,12 @@ static void get_process_info(int client, const sock_cred *cred) {
xxread(client, &l, sizeof(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]) {
// Either not a zygisk module, or incompatible
char buf[4096];
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) {
close(xopenat(dirfd, "unloaded", O_CREAT | O_RDONLY, 0644));
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);
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);
send_fd(client, dfd);
close(dfd);
}
void zygisk_handler(int client, const sock_cred *cred) {
auto &module_list = MagiskD().module_list();
int code = read_int(client);
switch (code) {
case ZygiskRequest::GET_INFO:
get_process_info(client, cred);
get_process_info(client, cred, module_list);
break;
case ZygiskRequest::CONNECT_COMPANION: {
int arch = read_int(client);
connect_companion(client, arch);
case ZygiskRequest::CONNECT_COMPANION:
connect_companion(client, module_list);
break;
}
case ZygiskRequest::GET_MODDIR:
get_moddir(client);
get_moddir(client, module_list);
break;
default:
// Unknown code