mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-10-27 23:38:46 +00:00
158 lines
5.2 KiB
C++
158 lines
5.2 KiB
C++
#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;
|
|
}
|
|
|
|
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);
|
|
}
|