2023-06-06 17:11:42 -07:00
|
|
|
#include <sys/mman.h>
|
2023-04-08 11:56:39 +08:00
|
|
|
#include <sys/syscall.h>
|
2020-04-18 02:00:48 -07:00
|
|
|
#include <sys/mount.h>
|
|
|
|
#include <map>
|
|
|
|
#include <utility>
|
|
|
|
|
2022-05-12 02:03:42 -07:00
|
|
|
#include <base.hpp>
|
2023-11-08 01:46:02 -08:00
|
|
|
#include <consts.hpp>
|
|
|
|
#include <core.hpp>
|
2020-04-18 02:00:48 -07:00
|
|
|
#include <selinux.hpp>
|
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2025-01-30 00:47:01 +08:00
|
|
|
static void load_modules(bool zygisk_enabled, const rust::Vec<ModuleInfo> &module_list) {
|
2021-04-13 16:26:58 +08:00
|
|
|
char buf[4096];
|
2020-12-30 22:11:24 -08:00
|
|
|
LOGI("* Loading modules\n");
|
2025-01-26 19:41:34 +08:00
|
|
|
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());
|
2022-05-06 01:40:19 -07:00
|
|
|
|
|
|
|
// Read props
|
|
|
|
strcpy(b, "system.prop");
|
|
|
|
if (access(buf, F_OK) == 0) {
|
2025-01-26 19:41:34 +08:00
|
|
|
LOGI("%.*s: loading [system.prop]\n", (int) m.name.size(), m.name.data());
|
2023-05-18 20:26:20 -07:00
|
|
|
// Do NOT go through property service as it could cause boot lock
|
|
|
|
load_prop_file(buf, true);
|
2022-05-06 01:40:19 -07:00
|
|
|
}
|
2021-10-26 01:50:29 +08:00
|
|
|
}
|
2025-03-11 00:33:47 +08:00
|
|
|
std::string magisk_path;
|
2023-11-02 15:50:36 -07:00
|
|
|
if (get_magisk_tmp() != "/sbin"sv || !str_contains(getenv("PATH") ?: "", "/sbin")) {
|
2020-12-30 22:11:24 -08:00
|
|
|
// Need to inject our binaries into /system/bin
|
2025-03-11 00:33:47 +08:00
|
|
|
magisk_path = "/system/bin";
|
|
|
|
for (struct stat st{}; auto &item: split(getenv("PATH"), ":")) {
|
|
|
|
item.erase(0, item.starts_with("/system/") ? 8 : 1);
|
|
|
|
auto &&system_path = "/system/"s + item;
|
|
|
|
if (stat(system_path.data(), &st) == 0 && st.st_mode & S_IXOTH) {
|
|
|
|
magisk_path = std::move(system_path);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
}
|
|
|
|
|
2023-11-06 17:19:12 -08:00
|
|
|
if (zygisk_enabled) {
|
|
|
|
string native_bridge_orig = get_prop(NBPROP);
|
|
|
|
if (native_bridge_orig.empty()) {
|
|
|
|
native_bridge_orig = "0";
|
|
|
|
}
|
|
|
|
native_bridge = native_bridge_orig != "0" ? ZYGISKLDR + native_bridge_orig : ZYGISKLDR;
|
2023-12-17 03:12:08 +08:00
|
|
|
set_prop(NBPROP, native_bridge.data());
|
2023-11-06 17:19:12 -08:00
|
|
|
// Weather Huawei's Maple compiler is enabled.
|
|
|
|
// If so, system server will be created by a special Zygote which ignores the native bridge
|
|
|
|
// and make system server out of our control. Avoid it by disabling.
|
|
|
|
if (get_prop("ro.maple.enable") == "1") {
|
2023-12-17 03:12:08 +08:00
|
|
|
set_prop("ro.maple.enable", "0");
|
2023-11-06 17:19:12 -08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2025-03-11 00:33:47 +08:00
|
|
|
deploy_modules(module_list, native_bridge, magisk_path);
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2023-02-25 18:11:25 -08:00
|
|
|
/************************
|
|
|
|
* Filesystem operations
|
|
|
|
************************/
|
|
|
|
|
2020-04-18 02:00:48 -07:00
|
|
|
static void prepare_modules() {
|
2020-12-30 22:11:24 -08:00
|
|
|
// 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);
|
|
|
|
}
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2020-10-11 18:30:03 -07:00
|
|
|
template<typename Func>
|
2020-10-25 21:41:14 -07:00
|
|
|
static void foreach_module(Func fn) {
|
2020-12-30 22:11:24 -08:00
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
|
|
|
|
2025-01-30 00:47:01 +08:00
|
|
|
static rust::Vec<ModuleInfo> collect_modules(bool zygisk_enabled, bool open_zygisk) {
|
2025-01-26 19:41:34 +08:00
|
|
|
rust::Vec<ModuleInfo> modules;
|
|
|
|
foreach_module([&](int dfd, dirent *entry, int modfd) {
|
2020-12-30 22:11:24 -08:00
|
|
|
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);
|
2021-09-23 23:54:46 -07:00
|
|
|
if (faccessat(modfd, "disable", F_OK, 0) == 0)
|
|
|
|
return;
|
|
|
|
|
2025-01-31 01:07:33 +08:00
|
|
|
ModuleInfo info{{}, -1, -1};
|
2021-11-24 16:51:18 +08:00
|
|
|
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) {
|
2021-10-13 04:52:02 -07:00
|
|
|
#if defined(__arm__)
|
|
|
|
info.z32 = openat(modfd, "zygisk/armeabi-v7a.so", O_RDONLY | O_CLOEXEC);
|
2025-01-26 19:41:34 +08:00
|
|
|
info.z64 = -1;
|
2021-10-13 04:52:02 -07:00
|
|
|
#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);
|
2025-01-26 19:41:34 +08:00
|
|
|
info.z64 = -1;
|
2021-10-13 04:52:02 -07:00
|
|
|
#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);
|
2024-04-04 22:15:14 +08:00
|
|
|
#elif defined(__riscv)
|
|
|
|
info.z32 = -1;
|
|
|
|
info.z64 = openat(modfd, "zygisk/riscv64.so", O_RDONLY | O_CLOEXEC);
|
2021-10-13 04:52:02 -07:00
|
|
|
#else
|
|
|
|
#error Unsupported ABI
|
|
|
|
#endif
|
2022-01-21 04:43:27 -08:00
|
|
|
unlinkat(modfd, "zygisk/unloaded", 0);
|
2021-11-24 16:51:18 +08:00
|
|
|
}
|
|
|
|
} 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;
|
2021-11-12 21:11:53 +08:00
|
|
|
}
|
2021-10-13 04:52:02 -07:00
|
|
|
}
|
|
|
|
info.name = entry->d_name;
|
2025-01-26 19:41:34 +08:00
|
|
|
modules.push_back(std::move(info));
|
2020-12-30 22:11:24 -08:00
|
|
|
});
|
2021-11-24 16:51:18 +08:00
|
|
|
if (zygisk_enabled) {
|
2021-10-28 00:26:18 -07:00
|
|
|
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;
|
|
|
|
};
|
2025-01-26 19:41:34 +08:00
|
|
|
std::for_each(modules.begin(),modules.end(), [&](ModuleInfo &info) {
|
2021-10-28 00:26:18 -07:00
|
|
|
info.z32 = convert_to_memfd(info.z32);
|
|
|
|
info.z64 = convert_to_memfd(info.z64);
|
|
|
|
});
|
|
|
|
}
|
2025-01-26 19:41:34 +08:00
|
|
|
return modules;
|
2020-10-11 18:30:03 -07:00
|
|
|
}
|
|
|
|
|
2025-02-02 12:57:09 +08:00
|
|
|
rust::Vec<ModuleInfo> MagiskD::handle_modules() const noexcept {
|
2025-01-30 00:47:01 +08:00
|
|
|
bool zygisk = zygisk_enabled();
|
2020-12-30 22:11:24 -08:00
|
|
|
prepare_modules();
|
2025-01-30 00:47:01 +08:00
|
|
|
exec_module_scripts("post-fs-data", collect_modules(zygisk, false));
|
2020-12-30 22:11:24 -08:00
|
|
|
// Recollect modules (module scripts could remove itself)
|
2025-01-30 00:47:01 +08:00
|
|
|
auto list = collect_modules(zygisk, true);
|
|
|
|
load_modules(zygisk, list);
|
2025-02-02 12:57:09 +08:00
|
|
|
return list;
|
2020-04-18 02:00:48 -07:00
|
|
|
}
|
2020-04-30 01:26:50 -07:00
|
|
|
|
2023-01-19 04:25:44 +08:00
|
|
|
static int check_rules_dir(char *buf, size_t sz) {
|
2023-11-02 15:50:36 -07:00
|
|
|
int off = ssprintf(buf, sz, "%s/" PREINITMIRR, get_magisk_tmp());
|
2023-01-19 04:25:44 +08:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
2020-10-11 18:30:03 -07:00
|
|
|
void disable_modules() {
|
2023-01-19 04:25:44 +08:00
|
|
|
char buf[4096];
|
|
|
|
int off = check_rules_dir(buf, sizeof(buf));
|
|
|
|
foreach_module([&](int, dirent *entry, int modfd) {
|
2020-12-30 22:11:24 -08:00
|
|
|
close(xopenat(modfd, "disable", O_RDONLY | O_CREAT | O_CLOEXEC, 0));
|
2023-01-19 04:25:44 +08:00
|
|
|
if (off) {
|
2023-01-20 14:41:22 +08:00
|
|
|
ssprintf(buf + off, sizeof(buf) - off, "/%s/sepolicy.rule", entry->d_name);
|
2023-01-19 04:25:44 +08:00
|
|
|
unlink(buf);
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
});
|
2020-10-11 18:30:03 -07:00
|
|
|
}
|
2020-04-30 01:26:50 -07:00
|
|
|
|
2020-10-11 18:30:03 -07:00
|
|
|
void remove_modules() {
|
2023-01-19 04:25:44 +08:00
|
|
|
char buf[4096];
|
|
|
|
int off = check_rules_dir(buf, sizeof(buf));
|
|
|
|
foreach_module([&](int, dirent *entry, int) {
|
2020-12-30 22:11:24 -08:00
|
|
|
auto uninstaller = MODULEROOT + "/"s + entry->d_name + "/uninstall.sh";
|
|
|
|
if (access(uninstaller.data(), F_OK) == 0)
|
|
|
|
exec_script(uninstaller.data());
|
2023-01-19 04:25:44 +08:00
|
|
|
if (off) {
|
2023-01-20 14:41:22 +08:00
|
|
|
ssprintf(buf + off, sizeof(buf) - off, "/%s/sepolicy.rule", entry->d_name);
|
2023-01-19 04:25:44 +08:00
|
|
|
unlink(buf);
|
|
|
|
}
|
2020-12-30 22:11:24 -08:00
|
|
|
});
|
|
|
|
rm_rf(MODULEROOT);
|
2020-04-30 01:26:50 -07:00
|
|
|
}
|