#include #include #include #include #include using namespace std; /************************ * Filesystem operations ************************/ template 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 collect_modules(bool zygisk_enabled, bool open_zygisk) { rust::Vec 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 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); }