From 886e2f8396979781d82983f9536b76f75373d909 Mon Sep 17 00:00:00 2001 From: "Pedro.js" Date: Sat, 29 Mar 2025 12:17:57 -0300 Subject: [PATCH] improve: mounting system, compatibility; remove: logging on release (#111) This commit adds numerous improvements to the state of hidden'ility of ReZygisk, and also for compatibility. Recommended to check #111 for more information. --- loader/src/common/daemon.cpp | 47 ++-- loader/src/common/dl.cpp | 9 +- loader/src/common/elf_util.cpp | 6 +- loader/src/common/logging.cpp | 36 --- loader/src/include/daemon.h | 18 +- loader/src/include/elf_util.h | 16 +- loader/src/include/logging.h | 39 ++-- loader/src/include/solist.hpp | 61 ++--- loader/src/injector/entry.cpp | 8 +- loader/src/injector/hook.cpp | 95 ++++---- loader/src/injector/module.hpp | 8 +- loader/src/injector/unmount.cpp | 145 ------------ loader/src/injector/zygisk.hpp | 6 - module/src/sepolicy.rule | 30 +-- zygiskd/build.gradle.kts | 2 +- zygiskd/src/constants.h | 35 ++- zygiskd/src/root_impl/common.c | 3 + zygiskd/src/utils.c | 389 +++++++++++++++++++++++++++++++- zygiskd/src/utils.h | 2 + zygiskd/src/zygiskd.c | 78 +++---- 20 files changed, 621 insertions(+), 412 deletions(-) delete mode 100644 loader/src/common/logging.cpp delete mode 100644 loader/src/injector/unmount.cpp diff --git a/loader/src/common/daemon.cpp b/loader/src/common/daemon.cpp index 34a188c..bd558ca 100644 --- a/loader/src/common/daemon.cpp +++ b/loader/src/common/daemon.cpp @@ -63,19 +63,6 @@ namespace zygiskd { return true; } - int RequestLogcatFd() { - int fd = Connect(1); - if (fd == -1) { - PLOGE("RequestLogcatFd"); - - return -1; - } - - socket_utils::write_u8(fd, (uint8_t) SocketAction::RequestLogcatFd); - - return fd; - } - uint32_t GetProcessFlags(uid_t uid) { int fd = Connect(1); if (fd == -1) { @@ -94,8 +81,8 @@ namespace zygiskd { return res; } - std::vector ReadModules() { - std::vector modules; + std::vector ReadModules() { + std::vector modules; int fd = Connect(1); if (fd == -1) { PLOGE("ReadModules"); @@ -260,4 +247,34 @@ namespace zygiskd { close(fd); } else info->running = false; } + + std::string UpdateMountNamespace(enum mount_namespace_state nms_state) { + int fd = Connect(1); + if (fd == -1) { + PLOGE("UpdateMountNamespace"); + + return ""; + } + + socket_utils::write_u8(fd, (uint8_t) SocketAction::UpdateMountNamespace); + socket_utils::write_u32(fd, getpid()); + socket_utils::write_u8(fd, (uint8_t)nms_state); + + uint32_t target_pid = socket_utils::read_u32(fd); + int target_fd = 0; + + if (target_pid == 0) goto error; + + target_fd = (int)socket_utils::read_u32(fd); + if (target_fd == 0) goto error; + + close(fd); + + return "/proc/" + std::to_string(target_pid) + "/fd/" + std::to_string(target_fd); + + error: + close(fd); + + return ""; + } } diff --git a/loader/src/common/dl.cpp b/loader/src/common/dl.cpp index 6d30432..352b8f9 100644 --- a/loader/src/common/dl.cpp +++ b/loader/src/common/dl.cpp @@ -46,9 +46,14 @@ void* DlopenExt(const char* path, int flags) { } void* DlopenMem(int fd, int flags) { - auto info = android_dlextinfo{ + auto info = android_dlextinfo { .flags = ANDROID_DLEXT_USE_LIBRARY_FD, - .library_fd = fd + .reserved_addr = NULL, + .reserved_size = 0, + .relro_fd = 0, + .library_fd = fd, + .library_fd_offset = 0, + .library_namespace = NULL }; /* INFO: We need to find the path of the fd since passing "" to android_dlopen_ext diff --git a/loader/src/common/elf_util.cpp b/loader/src/common/elf_util.cpp index d265b3c..2ce61b8 100644 --- a/loader/src/common/elf_util.cpp +++ b/loader/src/common/elf_util.cpp @@ -187,7 +187,7 @@ ElfW(Addr) ElfImg::LinearLookup(std::string_view name) const { } } -std::string_view ElfImg::LinearLookupByPrefix(std::string_view name) const { +ElfW(Addr) ElfImg::LinearLookupByPrefix(std::string_view name) const { if (symtabs_.empty()) { symtabs_.reserve(symtab_count); if (symtab_start != nullptr && symstr_offset_for_symtab != 0) { @@ -207,11 +207,11 @@ std::string_view ElfImg::LinearLookupByPrefix(std::string_view name) const { if (symtab.first.size() < size) continue; if (symtab.first.substr(0, size) == name) { - return symtab.first; + return symtab.second->st_value; } } - return ""; + return 0; } diff --git a/loader/src/common/logging.cpp b/loader/src/common/logging.cpp deleted file mode 100644 index 887025f..0000000 --- a/loader/src/common/logging.cpp +++ /dev/null @@ -1,36 +0,0 @@ -#include -#include - -#include "logging.h" -#include "socket_utils.h" - -namespace logging { - static int logfd = -1; - - void setfd(int fd) { - close(logfd); - logfd = fd; - } - - int getfd() { - return logfd; - } - - void log(int prio, const char* tag, const char* fmt, ...) { - if (logfd == -1) { - va_list ap; - va_start(ap, fmt); - __android_log_vprint(prio, tag, fmt, ap); - va_end(ap); - } else { - char buf[BUFSIZ]; - va_list ap; - va_start(ap, fmt); - vsnprintf(buf, sizeof(buf), fmt, ap); - va_end(ap); - socket_utils::write_u8(logfd, prio); - socket_utils::write_string(logfd, tag); - socket_utils::write_string(logfd, buf); - } - } -} diff --git a/loader/src/include/daemon.h b/loader/src/include/daemon.h index dfb04cc..dad3c18 100644 --- a/loader/src/include/daemon.h +++ b/loader/src/include/daemon.h @@ -61,18 +61,23 @@ struct zygote_info { bool running; }; +enum mount_namespace_state { + Clean, + Rooted, + Module +}; + namespace zygiskd { - struct Module { + struct ModuleInfo { std::string name; UniqueFd memfd; - inline explicit Module(std::string name, int memfd) : name(name), memfd(memfd) {} + inline explicit ModuleInfo(std::string name, int memfd) : name(name), memfd(memfd) {} }; enum class SocketAction { PingHeartBeat, - RequestLogcatFd, GetProcessFlags, GetInfo, ReadModules, @@ -80,6 +85,7 @@ namespace zygiskd { GetModuleDir, ZygoteRestart, SystemServerStarted, + UpdateMountNamespace }; void Init(const char *path); @@ -88,9 +94,7 @@ namespace zygiskd { bool PingHeartbeat(); - int RequestLogcatFd(); - - std::vector ReadModules(); + std::vector ReadModules(); uint32_t GetProcessFlags(uid_t uid); @@ -103,4 +107,6 @@ namespace zygiskd { void SystemServerStarted(); void GetInfo(struct zygote_info *info); + + std::string UpdateMountNamespace(enum mount_namespace_state mns_state); } diff --git a/loader/src/include/elf_util.h b/loader/src/include/elf_util.h index 1b8c0b7..42a08c6 100644 --- a/loader/src/include/elf_util.h +++ b/loader/src/include/elf_util.h @@ -48,8 +48,13 @@ namespace SandHook { } } - std::string_view findSymbolNameByPrefix(std::string_view prefix) const { - return LinearLookupByPrefix(prefix); + constexpr ElfW(Addr) getSymbAddressByPrefix(std::string_view prefix) const { + ElfW(Addr) offset = LinearLookupByPrefix(prefix); + if (offset > 0 && base != nullptr) { + return static_cast((uintptr_t) base + offset - bias); + } else { + return 0; + } } template @@ -57,6 +62,11 @@ namespace SandHook { return reinterpret_cast(getSymbAddress(name)); } + template + constexpr T getSymbAddressByPrefix(std::string_view prefix) const { + return reinterpret_cast(getSymbAddressByPrefix(prefix)); + } + bool isValid() const { return base != nullptr; } @@ -76,7 +86,7 @@ namespace SandHook { ElfW(Addr) LinearLookup(std::string_view name) const; - std::string_view LinearLookupByPrefix(std::string_view name) const; + ElfW(Addr) LinearLookupByPrefix(std::string_view name) const; constexpr static uint32_t ElfHash(std::string_view name); diff --git a/loader/src/include/logging.h b/loader/src/include/logging.h index 0318bbe..687fdaf 100644 --- a/loader/src/include/logging.h +++ b/loader/src/include/logging.h @@ -1,35 +1,30 @@ -#pragma once +#ifndef LOGGING_H +#define LOGGING_H #include #include #include #ifndef LOG_TAG -#if defined(__LP64__) -# define LOG_TAG "zygisk-core64" -#else -# define LOG_TAG "zygisk-core32" -#endif + #ifdef __LP64__ + #define LOG_TAG "zygisk-core64" + #else + #define LOG_TAG "zygisk-core32" + #endif #endif #ifndef NDEBUG -#define LOGD(...) logging::log(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) -#define LOGV(...) logging::log(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) + #define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__) + #define LOGV(...) __android_log_print(ANDROID_LOG_VERBOSE, LOG_TAG, __VA_ARGS__) #else -#define LOGD(...) -#define LOGV(...) + #define LOGD(...) + #define LOGV(...) #endif -#define LOGI(...) logging::log(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) -#define LOGW(...) logging::log(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) -#define LOGE(...) logging::log(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) -#define LOGF(...) logging::log(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__) + +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) +#define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) +#define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) +#define LOGF(...) __android_log_print(ANDROID_LOG_FATAL, LOG_TAG, __VA_ARGS__) #define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno)) -namespace logging { - void setfd(int fd); - - int getfd(); - - [[gnu::format(printf, 3, 4)]] - void log(int prio, const char* tag, const char* fmt, ...); -} +#endif /* LOGGING_H */ \ No newline at end of file diff --git a/loader/src/include/solist.hpp b/loader/src/include/solist.hpp index f55d4b1..6835517 100644 --- a/loader/src/include/solist.hpp +++ b/loader/src/include/solist.hpp @@ -21,7 +21,6 @@ namespace SoList { #endif inline static const char *(*get_realpath_sym)(SoInfo *) = NULL; - inline static const char *(*get_soname_sym)(SoInfo *) = NULL; inline static void (*soinfo_free)(SoInfo *) = NULL; inline SoInfo *get_next() { @@ -38,12 +37,6 @@ namespace SoList { return ((std::string *) ((uintptr_t) this + solist_realpath_offset))->c_str(); } - inline const char *get_name() { - if (get_soname_sym) return get_soname_sym(this); - - return ((std::string *) ((uintptr_t) this + solist_realpath_offset - sizeof(void *)))->c_str(); - } - void set_next(SoInfo *si) { *(SoInfo **) ((uintptr_t) this + solist_next_offset) = si; } @@ -110,6 +103,13 @@ namespace SoList { return addr == NULL ? NULL : *addr; } + template + inline T *getStaticPointerByPrefix(const SandHook::ElfImg &linker, const char *name) { + auto *addr = reinterpret_cast(linker.getSymbAddressByPrefix(name)); + + return addr == NULL ? NULL : *addr; + } + static bool DropSoPath(const char* target_path) { bool path_found = false; if (solist == NULL && !Initialize()) { @@ -117,9 +117,9 @@ namespace SoList { return path_found; } for (auto iter = solist; iter; iter = iter->get_next()) { - if (iter->get_name() && iter->get_path() && strstr(iter->get_path(), target_path)) { + if (iter->get_path() && strstr(iter->get_path(), target_path)) { SoList::ProtectedDataGuard guard; - LOGI("dropping solist record for %s loaded at %s with size %zu", iter->get_name(), iter->get_path(), iter->get_size()); + LOGV("dropping solist record loaded at %s with size %zu", iter->get_path(), iter->get_size()); if (iter->get_size() > 0) { iter->set_size(0); SoInfo::soinfo_free(iter); @@ -136,7 +136,7 @@ namespace SoList { return; } if (g_module_load_counter == NULL || g_module_unload_counter == NULL) { - LOGI("g_module counters not defined, skip reseting them"); + LOGD("g_module counters not defined, skip reseting them"); return; } auto loaded_modules = *g_module_load_counter; @@ -163,57 +163,26 @@ namespace SoList { See #63 for more information. */ - - std::string_view solist_sym_name = linker.findSymbolNameByPrefix("__dl__ZL6solist"); - if (solist_sym_name.empty()) return false; - LOGD("found symbol name %s", solist_sym_name.data()); - - std::string_view soinfo_free_name = linker.findSymbolNameByPrefix("__dl__ZL11soinfo_freeP6soinfo"); - if (soinfo_free_name.empty()) return false; - LOGD("found symbol name %s", soinfo_free_name.data()); - - /* INFO: The size isn't a magic number, it's the size for the string: .llvm.7690929523238822858 */ - char llvm_sufix[25 + 1]; - - if (solist_sym_name.length() != strlen("__dl__ZL6solist")) { - strncpy(llvm_sufix, solist_sym_name.data() + strlen("__dl__ZL6solist"), sizeof(llvm_sufix)); - } else { - llvm_sufix[0] = '\0'; - } - - solist = getStaticPointer(linker, solist_sym_name.data()); + solist = getStaticPointerByPrefix(linker, "__dl__ZL6solist"); if (solist == NULL) return false; LOGD("found symbol solist"); - char somain_sym_name[sizeof("__dl__ZL6somain") + sizeof(llvm_sufix)]; - snprintf(somain_sym_name, sizeof(somain_sym_name), "__dl__ZL6somain%s", llvm_sufix); - - char sonext_sym_name[sizeof("__dl__ZL6sonext") + sizeof(llvm_sufix)]; - snprintf(sonext_sym_name, sizeof(somain_sym_name), "__dl__ZL6sonext%s", llvm_sufix); - - char vdso_sym_name[sizeof("__dl__ZL4vdso") + sizeof(llvm_sufix)]; - snprintf(vdso_sym_name, sizeof(vdso_sym_name), "__dl__ZL4vdso%s", llvm_sufix); - - somain = getStaticPointer(linker, somain_sym_name); + somain = getStaticPointerByPrefix(linker, "__dl__ZL6somain"); if (somain == NULL) return false; LOGD("found symbol somain"); - sonext = linker.getSymbAddress(sonext_sym_name); + sonext = linker.getSymbAddressByPrefix("__dl__ZL6sonext"); if (sonext == NULL) return false; LOGD("found symbol sonext"); - SoInfo *vdso = getStaticPointer(linker, vdso_sym_name); + SoInfo *vdso = getStaticPointerByPrefix(linker, "__dl__ZL4vdso"); if (vdso != NULL) LOGD("found symbol vdso"); SoInfo::get_realpath_sym = reinterpret_cast(linker.getSymbAddress("__dl__ZNK6soinfo12get_realpathEv")); if (SoInfo::get_realpath_sym == NULL) return false; LOGD("found symbol get_realpath_sym"); - SoInfo::get_soname_sym = reinterpret_cast(linker.getSymbAddress("__dl__ZNK6soinfo10get_sonameEv")); - if (SoInfo::get_soname_sym == NULL) return false; - LOGD("found symbol get_soname_sym"); - - SoInfo::soinfo_free = reinterpret_cast(linker.getSymbAddress(soinfo_free_name)); + SoInfo::soinfo_free = reinterpret_cast(linker.getSymbAddressByPrefix("__dl__ZL11soinfo_freeP6soinfo")); if (SoInfo::soinfo_free == NULL) return false; LOGD("found symbol soinfo_free"); diff --git a/loader/src/injector/entry.cpp b/loader/src/injector/entry.cpp index a927042..fabe209 100644 --- a/loader/src/injector/entry.cpp +++ b/loader/src/injector/entry.cpp @@ -9,7 +9,7 @@ size_t block_size = 0; extern "C" [[gnu::visibility("default")]] void entry(void* addr, size_t size, const char* path) { - LOGI("Zygisk library injected, version %s", ZKSU_VERSION); + LOGD("Zygisk library injected, version %s", ZKSU_VERSION); start_addr = addr; block_size = size; zygiskd::Init(path); @@ -19,11 +19,7 @@ void entry(void* addr, size_t size, const char* path) { return; } -#ifdef NDEBUG - logging::setfd(zygiskd::RequestLogcatFd()); -#endif - - LOGI("start plt hooking"); + LOGD("start plt hooking"); hook_functions(); clean_trace(path, 1, 0, false); } diff --git a/loader/src/injector/hook.cpp b/loader/src/injector/hook.cpp index 5255d37..5b77ba3 100644 --- a/loader/src/injector/hook.cpp +++ b/loader/src/injector/hook.cpp @@ -137,6 +137,36 @@ DCL_HOOK_FUNC(int, fork) { return (g_ctx && g_ctx->pid >= 0) ? g_ctx->pid : old_fork(); } +bool update_mnt_ns(enum mount_namespace_state mns_state, bool dry_run) { + std::string ns_path = zygiskd::UpdateMountNamespace(mns_state); + if (ns_path.empty()) { + PLOGE("Failed to update mount namespace"); + + return false; + } + + if (dry_run) return true; + + int updated_ns = open(ns_path.data(), O_RDONLY); + if (updated_ns == -1) { + PLOGE("Failed to open mount namespace [%s]", ns_path.data()); + + return false; + } + + LOGD("set mount namespace to [%s] fd=[%d]\n", ns_path.data(), updated_ns); + if (setns(updated_ns, CLONE_NEWNS) == -1) { + PLOGE("Failed to set mount namespace [%s]", ns_path.data()); + close(updated_ns); + + return false; + } + + close(updated_ns); + + return true; +} + // Unmount stuffs in the process's private mount namespace DCL_HOOK_FUNC(int, unshare, int flags) { int res = old_unshare(flags); @@ -144,37 +174,22 @@ DCL_HOOK_FUNC(int, unshare, int flags) { // For some unknown reason, unmounting app_process in SysUI can break. // This is reproducible on the official AVD running API 26 and 27. // Simply avoid doing any unmounts for SysUI to avoid potential issues. - (g_ctx->info_flags & PROCESS_IS_SYS_UI) == 0) { - if (g_ctx->flags[DO_REVERT_UNMOUNT]) { - if (g_ctx->info_flags & PROCESS_ROOT_IS_KSU) { - revert_unmount_ksu(); - } else if (g_ctx->info_flags & PROCESS_ROOT_IS_APATCH){ - revert_unmount_apatch(); - } else if (g_ctx->info_flags & PROCESS_ROOT_IS_MAGISK) { - revert_unmount_magisk(); - } + !g_ctx->flags[SERVER_FORK_AND_SPECIALIZE] && !(g_ctx->info_flags & PROCESS_IS_FIRST_STARTED)) { + if (g_ctx->info_flags & (PROCESS_IS_MANAGER | PROCESS_GRANTED_ROOT)) { + update_mnt_ns(Rooted, false); + } else if (!(g_ctx->flags[DO_REVERT_UNMOUNT])) { + update_mnt_ns(Module, false); } - /* Zygisksu changed: No umount app_process */ - - // Restore errno back to 0 - errno = 0; + old_unshare(CLONE_NEWNS); } + + /* INFO: To spoof the errno value */ + errno = 0; + return res; } -// Close logd_fd if necessary to prevent crashing -// For more info, check comments in zygisk_log_write -DCL_HOOK_FUNC(void, android_log_close) { - if (g_ctx == nullptr) { - // Happens during un-managed fork like nativeForkApp, nativeForkUsap - logging::setfd(-1); - } else if (!g_ctx->flags[SKIP_FD_SANITIZATION]) { - logging::setfd(-1); - } - old_android_log_close(); -} - // We cannot directly call `dlclose` to unload ourselves, otherwise when `dlclose` returns, // it will return to our code which has been unmapped, causing segmentation fault. // Instead, we hook `pthread_attr_setstacksize` which will be called when VM daemon threads start. @@ -189,11 +204,13 @@ DCL_HOOK_FUNC(int, pthread_attr_setstacksize, void *target, size_t size) { if (should_unmap_zygisk) { unhook_functions(); cached_map_infos.clear(); + if (should_unmap_zygisk) { // Because both `pthread_attr_setstacksize` and `dlclose` have the same function signature, // we can use `musttail` to let the compiler reuse our stack frame and thus // `dlclose` will directly return to the caller of `pthread_attr_setstacksize`. - LOGI("unmap libzygisk.so loaded at %p with size %zu", start_addr, block_size); + LOGD("unmap libzygisk.so loaded at %p with size %zu", start_addr, block_size); + [[clang::musttail]] return munmap(start_addr, block_size); } } @@ -598,14 +615,18 @@ void ZygiskContext::run_modules_post() { /* Zygisksu changed: Load module fds */ void ZygiskContext::app_specialize_pre() { flags[APP_SPECIALIZE] = true; + info_flags = zygiskd::GetProcessFlags(g_ctx->args.app->uid); + if (info_flags & PROCESS_IS_FIRST_STARTED) { + update_mnt_ns(Clean, true); + } if ((info_flags & PROCESS_ON_DENYLIST) == PROCESS_ON_DENYLIST) { - flags[DO_REVERT_UNMOUNT] = true; + flags[DO_REVERT_UNMOUNT] = true; } if ((info_flags & (PROCESS_IS_MANAGER | PROCESS_ROOT_IS_MAGISK)) == (PROCESS_IS_MANAGER | PROCESS_ROOT_IS_MAGISK)) { - LOGI("Manager process detected. Notifying that Zygisk has been enabled."); + LOGD("Manager process detected. Notifying that Zygisk has been enabled."); setenv("ZYGISK_ENABLED", "1", 1); } else { @@ -620,7 +641,6 @@ void ZygiskContext::app_specialize_post() { // Cleanups env->ReleaseStringUTFChars(args.app->nice_name, process); g_ctx = nullptr; - logging::setfd(-1); } bool ZygiskContext::exempt_fd(int fd) { @@ -653,11 +673,10 @@ void ZygiskContext::nativeForkSystemServer_pre() { flags[SERVER_FORK_AND_SPECIALIZE] = true; fork_pre(); - if (pid != 0) - return; - - run_modules_pre(); - zygiskd::SystemServerStarted(); + if (is_child()) { + run_modules_pre(); + zygiskd::SystemServerStarted(); + } sanitize_fds(); } @@ -673,12 +692,9 @@ void ZygiskContext::nativeForkSystemServer_post() { void ZygiskContext::nativeForkAndSpecialize_pre() { process = env->GetStringUTFChars(args.app->nice_name, nullptr); LOGV("pre forkAndSpecialize [%s]", process); - flags[APP_FORK_AND_SPECIALIZE] = true; - /* Zygisksu changed: No args.app->fds_to_ignore check since we are Android 10+ */ - if (logging::getfd() != -1) { - exempted_fds.push_back(logging::getfd()); - } + + update_mnt_ns(Clean, false); fork_pre(); if (pid == 0) { @@ -805,7 +821,6 @@ void hook_functions() { PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, fork); PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, unshare); PLT_HOOK_REGISTER(android_runtime_dev, android_runtime_inode, strdup); - PLT_HOOK_REGISTER_SYM(android_runtime_dev, android_runtime_inode, "__android_log_close", android_log_close); hook_commit(); // Remove unhooked methods diff --git a/loader/src/injector/module.hpp b/loader/src/injector/module.hpp index 24111fc..f02bd7d 100644 --- a/loader/src/injector/module.hpp +++ b/loader/src/injector/module.hpp @@ -126,13 +126,13 @@ namespace { PROCESS_GRANTED_ROOT = zygisk::StateFlag::PROCESS_GRANTED_ROOT, PROCESS_ON_DENYLIST = zygisk::StateFlag::PROCESS_ON_DENYLIST, - PROCESS_IS_MANAGER = (1u << 28), - PROCESS_ROOT_IS_APATCH = (1u << 27), + PROCESS_IS_MANAGER = (1u << 27), + PROCESS_ROOT_IS_APATCH = (1u << 28), PROCESS_ROOT_IS_KSU = (1u << 29), PROCESS_ROOT_IS_MAGISK = (1u << 30), - PROCESS_IS_SYS_UI = (1u << 31), + PROCESS_IS_FIRST_STARTED = (1u << 31), - PRIVATE_MASK = PROCESS_IS_SYS_UI + PRIVATE_MASK = PROCESS_IS_FIRST_STARTED }; struct api_abi_base { diff --git a/loader/src/injector/unmount.cpp b/loader/src/injector/unmount.cpp deleted file mode 100644 index a657467..0000000 --- a/loader/src/injector/unmount.cpp +++ /dev/null @@ -1,145 +0,0 @@ -#include -#include - -#include "files.hpp" -#include "logging.h" -#include "misc.hpp" -#include "zygisk.hpp" - -using namespace std::string_view_literals; - -namespace { - constexpr auto MODULE_DIR = "/data/adb/modules"; - constexpr auto KSU_OVERLAY_SOURCE = "KSU"; - constexpr auto AP_OVERLAY_SOURCE = "APatch"; - const std::vector DEVICE_PARTITIONS{"/system", "/vendor", "/product", "/system_ext", "/odm", "/oem"}; - - void lazy_unmount(const char* mountpoint) { - if (umount2(mountpoint, MNT_DETACH) != -1) { - LOGD("Unmounted (%s)", mountpoint); - } else { -#ifndef NDEBUG - PLOGE("Unmount (%s)", mountpoint); -#endif - } - } -} - -void revert_unmount_ksu() { - std::string ksu_loop; - std::vector targets; - - // Unmount ksu module dir last - targets.emplace_back(MODULE_DIR); - - for (auto& info: parse_mount_info("self")) { - if (info.target == MODULE_DIR) { - ksu_loop = info.source; - continue; - } - - // Unmount everything mounted to /data/adb - if (info.target.starts_with("/data/adb")) { - targets.emplace_back(info.target); - } - - // Unmount everything mounted to /data/adb - if (info.root.starts_with("/adb/modules")) { - targets.emplace_back(info.target); - } - - // Unmount ksu overlays - if (info.type == "overlay" - && info.source == KSU_OVERLAY_SOURCE - && std::find(DEVICE_PARTITIONS.begin(), DEVICE_PARTITIONS.end(), info.target) != DEVICE_PARTITIONS.end()) { - targets.emplace_back(info.target); - } - - // Unmount temp dir - if (info.type == "tmpfs" && info.source == KSU_OVERLAY_SOURCE) { - targets.emplace_back(info.target); - } - } - - for (auto& info: parse_mount_info("self")) { - // Unmount everything from ksu loop except ksu module dir - if (info.source == ksu_loop && info.target != MODULE_DIR) { - targets.emplace_back(info.target); - } - } - - // Do unmount - for (auto& s: reversed(targets)) { - lazy_unmount(s.data()); - } -} - -void revert_unmount_magisk() { - std::vector targets; - - // Unmount dummy skeletons and MAGISKTMP - // since mirror nodes are always mounted under skeleton, we don't have to specifically unmount - for (auto& info: parse_mount_info("self")) { - if (info.source == "magisk" || info.source == "worker" || // magisktmp tmpfs - info.root.starts_with("/adb/modules")) { // bind mount from data partition - targets.push_back(info.target); - } - // Unmount everything mounted to /data/adb - if (info.target.starts_with("/data/adb")) { - targets.emplace_back(info.target); - } - } - - for (auto& s: reversed(targets)) { - lazy_unmount(s.data()); - } -} - -void revert_unmount_apatch() { - std::string ap_loop; - std::vector targets; - - // Unmount ksu module dir last - targets.emplace_back(MODULE_DIR); - - for (auto& info: parse_mount_info("self")) { - if (info.target == MODULE_DIR) { - ap_loop = info.source; - continue; - } - - // Unmount everything mounted to /data/adb - if (info.target.starts_with("/data/adb")) { - targets.emplace_back(info.target); - } - - // Unmount everything mounted to /data/adb - if (info.root.starts_with("/adb/modules")) { - targets.emplace_back(info.target); - } - - // Unmount ksu overlays - if (info.type == "overlay" - && info.source == AP_OVERLAY_SOURCE - && std::find(DEVICE_PARTITIONS.begin(), DEVICE_PARTITIONS.end(), info.target) != DEVICE_PARTITIONS.end()) { - targets.emplace_back(info.target); - } - - // Unmount temp dir - if (info.type == "tmpfs" && info.source == AP_OVERLAY_SOURCE) { - targets.emplace_back(info.target); - } - } - - for (auto& info: parse_mount_info("self")) { - // Unmount everything from ksu loop except ksu module dir - if (info.source == ap_loop && info.target != MODULE_DIR) { - targets.emplace_back(info.target); - } - } - - // Do unmount - for (auto& s: reversed(targets)) { - lazy_unmount(s.data()); - } -} diff --git a/loader/src/injector/zygisk.hpp b/loader/src/injector/zygisk.hpp index 793ba78..d171890 100644 --- a/loader/src/injector/zygisk.hpp +++ b/loader/src/injector/zygisk.hpp @@ -8,9 +8,3 @@ extern size_t block_size; void hook_functions(); void clean_trace(const char* path, size_t load = 1, size_t unload = 0, bool spoof_maps = false); - -void revert_unmount_ksu(); - -void revert_unmount_magisk(); - -void revert_unmount_apatch(); diff --git a/module/src/sepolicy.rule b/module/src/sepolicy.rule index 48669a6..859f87f 100644 --- a/module/src/sepolicy.rule +++ b/module/src/sepolicy.rule @@ -1,21 +1,15 @@ -allow zygote tmpfs file * -allow zygote appdomain_tmpfs file * +type zygisk_file file_type +typeattribute zygisk_file mlstrustedobject +allow zygote zygisk_file sock_file {read write} -type magisk_file file_type -typeattribute magisk_file mlstrustedobject - -allow * magisk_file file * -allow * magisk_file dir * -allow * magisk_file fifo_file * -allow * magisk_file chr_file * -allow * magisk_file lnk_file * -allow * magisk_file sock_file * - -allow system_server system_server process execmem -allow zygote zygote process execmem +allow zygote magisk lnk_file read +allow zygote unlabeled file {read open} +allow zygote zygote capability sys_chroot +allow zygote su dir search +allow zygote su {lnk_file file} read allow zygote adb_data_file dir search -allow zygote mnt_vendor_file dir search -allow zygote system_file dir mounton -allow zygote labeledfs filesystem mount -allow zygote fs_type filesystem unmount +allow zygote zygote process execmem +allow system_server system_server process execmem +allow zygote tmpfs file * +allow zygote appdomain_tmpfs file * diff --git a/zygiskd/build.gradle.kts b/zygiskd/build.gradle.kts index b830189..a3a2984 100644 --- a/zygiskd/build.gradle.kts +++ b/zygiskd/build.gradle.kts @@ -42,7 +42,7 @@ val CFlagsRelease = arrayOf( ) val CFlagsDebug = arrayOf( - "-g", "-O0" + "-g", "-O0", "-DDEBUG" ) val Files = arrayOf( diff --git a/zygiskd/src/constants.h b/zygiskd/src/constants.h index 8342ebb..71e3f29 100644 --- a/zygiskd/src/constants.h +++ b/zygiskd/src/constants.h @@ -7,12 +7,6 @@ #define true 1 #define false 0 -#if DEBUG == false - #define MAX_LOG_LEVEL ANDROID_LOG_VERBOSE -#else - #define MAX_LOG_LEVEL ANDROID_LOG_INFO -#endif - #if (defined(__LP64__) || defined(_LP64)) #define lp_select(a, b) b #else @@ -26,25 +20,24 @@ enum DaemonSocketAction { PingHeartbeat = 0, - RequestLogcatFd = 1, - GetProcessFlags = 2, - GetInfo = 3, - ReadModules = 4, - RequestCompanionSocket = 5, - GetModuleDir = 6, - ZygoteRestart = 7, - SystemServerStarted = 8 + GetProcessFlags = 1, + GetInfo = 2, + ReadModules = 3, + RequestCompanionSocket = 4, + GetModuleDir = 5, + ZygoteRestart = 6, + SystemServerStarted = 7, + GetCleanNamespace = 8 }; enum ProcessFlags: uint32_t { PROCESS_GRANTED_ROOT = (1u << 0), PROCESS_ON_DENYLIST = (1u << 1), - PROCESS_IS_MANAGER = (1u << 28), - PROCESS_ROOT_IS_APATCH = (1u << 27), + PROCESS_IS_MANAGER = (1u << 27), + PROCESS_ROOT_IS_APATCH = (1u << 28), PROCESS_ROOT_IS_KSU = (1u << 29), PROCESS_ROOT_IS_MAGISK = (1u << 30), - PROCESS_IS_SYS_UI = (1u << 31), - PROCESS_IS_SYSUI = (1u << 31) + PROCESS_IS_FIRST_STARTED = (1u << 31) }; enum RootImplState { @@ -54,4 +47,10 @@ enum RootImplState { Abnormal }; +enum MountNamespaceState { + Clean, + Rooted, + Module +}; + #endif /* CONSTANTS_H */ diff --git a/zygiskd/src/root_impl/common.c b/zygiskd/src/root_impl/common.c index e679f55..2198bdc 100644 --- a/zygiskd/src/root_impl/common.c +++ b/zygiskd/src/root_impl/common.c @@ -1,6 +1,9 @@ #include +#include +#include #include +#include #include "../utils.h" #include "kernelsu.h" diff --git a/zygiskd/src/utils.c b/zygiskd/src/utils.c index d0e7eba..6922599 100644 --- a/zygiskd/src/utils.c +++ b/zygiskd/src/utils.c @@ -3,11 +3,13 @@ #include #include #include +#include #include #include #include #include -#include +#include +#include #include #include @@ -18,6 +20,11 @@ #include "utils.h" #include "root_impl/common.h" +#include "root_impl/magisk.h" + +int clean_namespace_fd = 0; +int rooted_namespace_fd = 0; +int module_namespace_fd = 0; bool switch_mount_namespace(pid_t pid) { char path[PATH_MAX]; @@ -184,7 +191,7 @@ int unix_listener_from_path(char *restrict path) { return -1; } - if (chcon(path, "u:object_r:magisk_file:s0") == -1) { + if (chcon(path, "u:object_r:zygisk_file:s0") == -1) { LOGE("chcon: %s\n", strerror(errno)); return -1; @@ -450,3 +457,381 @@ void stringify_root_impl_name(struct root_impl impl, char *restrict output) { } } } + +struct mountinfo { + unsigned int id; + unsigned int parent; + dev_t device; + const char *root; + const char *target; + const char *vfs_option; + struct { + unsigned int shared; + unsigned int master; + unsigned int propagate_from; + } optional; + const char *type; + const char *source; + const char *fs_option; +}; + +struct mountinfos { + struct mountinfo *mounts; + size_t length; +}; + +char *strndup(const char *restrict str, size_t length) { + char *restrict copy = malloc(length + 1); + if (copy == NULL) return NULL; + + memcpy(copy, str, length); + copy[length] = '\0'; + + return copy; +} + +void free_mounts(struct mountinfos *restrict mounts) { + for (size_t i = 0; i < mounts->length; i++) { + free((void *)mounts->mounts[i].root); + free((void *)mounts->mounts[i].target); + free((void *)mounts->mounts[i].vfs_option); + free((void *)mounts->mounts[i].type); + free((void *)mounts->mounts[i].source); + free((void *)mounts->mounts[i].fs_option); + } + + free((void *)mounts->mounts); +} + +bool parse_mountinfo(const char *restrict pid, struct mountinfos *restrict mounts) { + char path[PATH_MAX]; + snprintf(path, PATH_MAX, "/proc/%s/mountinfo", pid); + + FILE *mountinfo = fopen(path, "r"); + if (mountinfo == NULL) { + LOGE("fopen: %s\n", strerror(errno)); + + return false; + } + + char line[PATH_MAX]; + size_t i = 0; + + mounts->mounts = NULL; + mounts->length = 0; + + while (fgets(line, sizeof(line), mountinfo) != NULL) { + int root_start = 0, root_end = 0; + int target_start = 0, target_end = 0; + int vfs_option_start = 0, vfs_option_end = 0; + int type_start = 0, type_end = 0; + int source_start = 0, source_end = 0; + int fs_option_start = 0, fs_option_end = 0; + int optional_start = 0, optional_end = 0; + unsigned int id, parent, maj, min; + sscanf(line, + "%u " // (1) id + "%u " // (2) parent + "%u:%u " // (3) maj:min + "%n%*s%n " // (4) mountroot + "%n%*s%n " // (5) target + "%n%*s%n" // (6) vfs options (fs-independent) + "%n%*[^-]%n - " // (7) optional fields + "%n%*s%n " // (8) FS type + "%n%*s%n " // (9) source + "%n%*s%n", // (10) fs options (fs specific) + &id, &parent, &maj, &min, &root_start, &root_end, &target_start, + &target_end, &vfs_option_start, &vfs_option_end, + &optional_start, &optional_end, &type_start, &type_end, + &source_start, &source_end, &fs_option_start, &fs_option_end); + + mounts->mounts = (struct mountinfo *)realloc(mounts->mounts, (i + 1) * sizeof(struct mountinfo)); + if (!mounts->mounts) { + LOGE("Failed to allocate memory for mounts->mounts"); + + fclose(mountinfo); + free_mounts(mounts); + + return false; + } + + unsigned int shared = 0; + unsigned int master = 0; + unsigned int propagate_from = 0; + if (strstr(line + optional_start, "shared:")) { + shared = (unsigned int)atoi(strstr(line + optional_start, "shared:") + 7); + } + + if (strstr(line + optional_start, "master:")) { + master = (unsigned int)atoi(strstr(line + optional_start, "master:") + 7); + } + + if (strstr(line + optional_start, "propagate_from:")) { + propagate_from = (unsigned int)atoi(strstr(line + optional_start, "propagate_from:") + 15); + } + + mounts->mounts[i].id = id; + mounts->mounts[i].parent = parent; + mounts->mounts[i].device = (dev_t)(makedev(maj, min)); + mounts->mounts[i].root = strndup(line + root_start, (size_t)(root_end - root_start)); + mounts->mounts[i].target = strndup(line + target_start, (size_t)(target_end - target_start)); + mounts->mounts[i].vfs_option = strndup(line + vfs_option_start, (size_t)(vfs_option_end - vfs_option_start)); + mounts->mounts[i].optional.shared = shared; + mounts->mounts[i].optional.master = master; + mounts->mounts[i].optional.propagate_from = propagate_from; + mounts->mounts[i].type = strndup(line + type_start, (size_t)(type_end - type_start)); + mounts->mounts[i].source = strndup(line + source_start, (size_t)(source_end - source_start)); + mounts->mounts[i].fs_option = strndup(line + fs_option_start, (size_t)(fs_option_end - fs_option_start)); + + i++; + } + + fclose(mountinfo); + + mounts->length = i; + + return true; +} + +enum mns_umount_state { + Complete, + NotComplete, + Error +}; + +enum mns_umount_state unmount_root(bool modules_only, struct root_impl impl) { + /* INFO: We are already in the target pid mount namespace, so actually, + when we use self here, we meant its pid. + */ + struct mountinfos mounts; + if (!parse_mountinfo("self", &mounts)) { + LOGE("Failed to parse mountinfo\n"); + + return Error; + } + + /* INFO: Implementations like Magisk Kitsune will mount MagiskSU when boot is completed, + so if we cache the clean mount done before the boot is completed, it will get + it mounted later and hence it will leak mounts. To avoid that we will detect + if implementation is Kitsune, and if so, see if /system/bin... is mounted, + if not, it won't cache this namespace. */ + bool magiskSU_umounted = false; + + switch (impl.impl) { + case None: { break; } + case Multiple: { break; } + + case KernelSU: + case APatch: { + char source_name[LONGEST_ROOT_IMPL_NAME]; + if (impl.impl == KernelSU) strcpy(source_name, "KSU"); + else strcpy(source_name, "APatch"); + + const char **targets_to_unmount = NULL; + size_t num_targets = 0; + + for (size_t i = 0; i < mounts.length; i++) { + struct mountinfo mount = mounts.mounts[i]; + + bool should_unmount = false; + + if (modules_only) { + if (strncmp(mount.target, "/debug_ramdisk", strlen("/debug_ramdisk")) == 0) + should_unmount = true; + } else { + if (strcmp(mount.source, source_name) == 0) should_unmount = true; + if (strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0) should_unmount = true; + if (strncmp(mount.target, "/data/adb/modules", strlen("/data/adb/modules")) == 0) should_unmount = true; + } + + if (!should_unmount) continue; + + num_targets++; + targets_to_unmount = realloc(targets_to_unmount, num_targets * sizeof(char*)); + if (targets_to_unmount == NULL) { + LOGE("[%s] Failed to allocate memory for targets_to_unmount\n", source_name); + + free(targets_to_unmount); + free_mounts(&mounts); + + return Error; + } + + targets_to_unmount[num_targets - 1] = mount.target; + } + + for (size_t i = num_targets; i > 0; i--) { + const char *target = targets_to_unmount[i - 1]; + + if (umount2(target, MNT_DETACH) == -1) { + LOGE("[%s] Failed to unmount %s: %s\n", source_name, target, strerror(errno)); + } else { + LOGI("[%s] Unmounted %s\n", source_name, target); + } + } + free(targets_to_unmount); + + break; + } + case Magisk: { + LOGI("[Magisk] Unmounting root %s modules\n", modules_only ? "only" : "with"); + + const char **targets_to_unmount = NULL; + size_t num_targets = 0; + + for (size_t i = 0; i < mounts.length; i++) { + struct mountinfo mount = mounts.mounts[i]; + + bool should_unmount = false; + if ( + ( + modules_only && + ( + strcmp(mount.source, "magisk") == 0 || + strncmp(mount.target, "/debug_ramdisk", strlen("/debug_ramdisk")) == 0 || + strncmp(mount.target, "/system/bin", strlen("/system/bin")) == 0 + ) + ) || + ( + !modules_only && + ( + strcmp(mount.source, "magisk") == 0 || + strncmp(mount.target, "/debug_ramdisk", strlen("/debug_ramdisk")) == 0 || + strncmp(mount.target, "/data/adb/modules", strlen("/data/adb/modules")) == 0 || + strncmp(mount.root, "/adb/modules", strlen("/adb/modules")) == 0 || + strncmp(mount.target, "/system/bin", strlen("/system/bin")) == 0 + ) + ) + ) { + should_unmount = true; + } + + if (!should_unmount) continue; + + num_targets++; + targets_to_unmount = realloc(targets_to_unmount, num_targets * sizeof(char*)); + if (targets_to_unmount == NULL) { + LOGE("[Magisk] Failed to allocate memory for targets_to_unmount\n"); + + free(targets_to_unmount); + free_mounts(&mounts); + + return Error; + } + + targets_to_unmount[num_targets - 1] = mount.target; + + if (impl.impl == Magisk && strncmp(mount.target, "/system/bin", strlen("/system/bin")) == 0) + magiskSU_umounted = true; + } + + for (size_t i = num_targets; i > 0; i--) { + const char *target = targets_to_unmount[i - 1]; + if (umount2(target, MNT_DETACH) == -1) { + LOGE("[Magisk] Failed to unmount %s: %s\n", target, strerror(errno)); + } else { + LOGI("[Magisk] Unmounted %s\n", target); + } + } + free(targets_to_unmount); + + break; + } + } + + free_mounts(&mounts); + + return (impl.impl == Magisk && !magiskSU_umounted) ? NotComplete : Complete; +} + +int save_mns_fd(int pid, enum MountNamespaceState mns_state, struct root_impl impl) { + if (mns_state == Clean && clean_namespace_fd != 0) return clean_namespace_fd; + if (mns_state == Rooted && rooted_namespace_fd != 0) return rooted_namespace_fd; + if (mns_state == Module && module_namespace_fd != 0) return module_namespace_fd; + + int sockets[2]; + if (socketpair(AF_UNIX, SOCK_STREAM, 0, sockets) == -1) { + LOGE("socketpair: %s\n", strerror(errno)); + + return -1; + } + + int reader = sockets[0]; + int writer = sockets[1]; + + pid_t fork_pid = fork(); + if (fork_pid == 0) { + switch_mount_namespace(pid); + + enum mns_umount_state umount_state = Complete; + + if (mns_state != Rooted) { + unshare(CLONE_NEWNS); + umount_state = unmount_root(mns_state == Module, impl); + if (umount_state == Error) { + write_uint8_t(writer, (uint8_t)umount_state); + + _exit(1); + } + } + + uint32_t mypid = 0; + while (mypid != (uint32_t)getpid()) { + write_uint8_t(writer, (uint8_t)umount_state); + usleep(50); + read_uint32_t(reader, &mypid); + } + + _exit(0); + } else if (fork_pid > 0) { + enum mns_umount_state umount_state = (enum mns_umount_state)0; + read_uint8_t(reader, (uint8_t *)&umount_state); + + if (umount_state == Error) { + LOGE("Failed to unmount root\n"); + + return -1; + } + + char ns_path[PATH_MAX]; + snprintf(ns_path, PATH_MAX, "/proc/%d/ns/mnt", fork_pid); + + int ns_fd = open(ns_path, O_RDONLY); + if (ns_fd == -1) { + LOGE("open: %s\n", strerror(errno)); + + return -1; + } + + write_uint32_t(writer, (uint32_t)fork_pid); + + if (close(reader) == -1) { + LOGE("Failed to close reader: %s\n", strerror(errno)); + + return -1; + } + + if (close(writer) == -1) { + LOGE("Failed to close writer: %s\n", strerror(errno)); + + return -1; + } + + if (waitpid(fork_pid, NULL, 0) == -1) { + LOGE("waitpid: %s\n", strerror(errno)); + + return -1; + } + + if (mns_state == Rooted) return (rooted_namespace_fd = ns_fd); + else if (mns_state == Clean && umount_state == Complete) return (clean_namespace_fd = ns_fd); + else if (mns_state == Module && umount_state == Complete) return (module_namespace_fd = ns_fd); + else return ns_fd; + } else { + LOGE("fork: %s\n", strerror(errno)); + + return -1; + } + + return -1; +} diff --git a/zygiskd/src/utils.h b/zygiskd/src/utils.h index 7cc6bbf..1d8bebb 100644 --- a/zygiskd/src/utils.h +++ b/zygiskd/src/utils.h @@ -107,4 +107,6 @@ int non_blocking_execv(const char *restrict file, char *const argv[]); void stringify_root_impl_name(struct root_impl impl, char *restrict output); +int save_mns_fd(int pid, enum MountNamespaceState mns_state, struct root_impl impl); + #endif /* UTILS_H */ diff --git a/zygiskd/src/zygiskd.c b/zygiskd/src/zygiskd.c index 0c0d952..429c143 100644 --- a/zygiskd/src/zygiskd.c +++ b/zygiskd/src/zygiskd.c @@ -382,6 +382,7 @@ void zygiskd_start(char *restrict argv[]) { return; } + bool first_process = true; while (1) { int client_fd = accept(socket_fd, NULL, NULL); if (client_fd == -1) { @@ -437,51 +438,26 @@ void zygiskd_start(char *restrict argv[]) { break; } - /* TODO: Move to another thread and save client fds to an epoll list - so that we can, in a single-thread, deal with multiple logcats */ - case RequestLogcatFd: { - uint8_t level = 0; - ssize_t ret = read_uint8_t(client_fd, &level); - ASSURE_SIZE_READ_BREAK("RequestLogcatFd", "level", ret, sizeof(level)); - - char tag[128 + 1]; - ret = read_string(client_fd, tag, sizeof(tag)); - if (ret == -1) { - LOGE("Failed reading logcat tag.\n"); - - close(client_fd); - - break; - } - - char message[1024 + 1]; - ret = read_string(client_fd, message, sizeof(message)); - if (ret == -1) { - LOGE("Failed reading logcat message.\n"); - - close(client_fd); - - break; - } - - __android_log_print(level, tag, "%s", message); - - break; - } case GetProcessFlags: { uint32_t uid = 0; ssize_t ret = read_uint32_t(client_fd, &uid); ASSURE_SIZE_READ_BREAK("GetProcessFlags", "uid", ret, sizeof(uid)); uint32_t flags = 0; - if (uid_is_manager(uid)) { - flags |= PROCESS_IS_MANAGER; + if (first_process) { + flags |= PROCESS_IS_FIRST_STARTED; + + first_process = false; } else { - if (uid_granted_root(uid)) { - flags |= PROCESS_GRANTED_ROOT; - } - if (uid_should_umount(uid)) { - flags |= PROCESS_ON_DENYLIST; + if (uid_is_manager(uid)) { + flags |= PROCESS_IS_MANAGER; + } else { + if (uid_granted_root(uid)) { + flags |= PROCESS_GRANTED_ROOT; + } + if (uid_should_umount(uid)) { + flags |= PROCESS_ON_DENYLIST; + } } } @@ -671,11 +647,35 @@ void zygiskd_start(char *restrict argv[]) { break; } + break; + } + case GetCleanNamespace: { + pid_t pid = 0; + ssize_t ret = read_uint32_t(client_fd, (uint32_t *)&pid); + ASSURE_SIZE_READ_BREAK("GetCleanNamespace", "pid", ret, sizeof(pid)); + + uint8_t mns_state = 0; + ret = read_uint8_t(client_fd, &mns_state); + ASSURE_SIZE_READ_BREAK("GetCleanNamespace", "mns_state", ret, sizeof(mns_state)); + + uint32_t our_pid = (uint32_t)getpid(); + ret = write_uint32_t(client_fd, (uint32_t)our_pid); + ASSURE_SIZE_WRITE_BREAK("GetCleanNamespace", "our_pid", ret, sizeof(our_pid)); + + if ((enum MountNamespaceState)mns_state == Clean) { + save_mns_fd(pid, Rooted, impl); + save_mns_fd(pid, Module, impl); + } + + uint32_t clean_namespace_fd = (uint32_t)save_mns_fd(pid, (enum MountNamespaceState)mns_state, impl); + ret = write_uint32_t(client_fd, clean_namespace_fd); + ASSURE_SIZE_WRITE_BREAK("GetCleanNamespace", "clean_namespace_fd", ret, sizeof(clean_namespace_fd)); + break; } } - if (action != RequestCompanionSocket && action != RequestLogcatFd) close(client_fd); + if (action != RequestCompanionSocket) close(client_fd); continue; }