From 50515d91288df67c552bcd3eecab7c2b8e248465 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Tue, 16 Nov 2021 01:59:45 -0800 Subject: [PATCH] Close unclosed fds from modules --- native/jni/zygisk/hook.cpp | 50 +++++++++++++++++++-------- native/jni/zygisk/module.hpp | 65 +++++++++++++++++++----------------- 2 files changed, 71 insertions(+), 44 deletions(-) diff --git a/native/jni/zygisk/hook.cpp b/native/jni/zygisk/hook.cpp index 0959d9385..93a3dbc02 100644 --- a/native/jni/zygisk/hook.cpp +++ b/native/jni/zygisk/hook.cpp @@ -164,7 +164,7 @@ DCL_HOOK_FUNC(int, unshare, int flags) { return res; } -// A place to clean things up before calling into zygote::ForkCommon/SpecializeCommon +// A place to clean things up before zygote evaluates fd table DCL_HOOK_FUNC(void, android_log_close) { HookContext::close_fds(); if (g_ctx && g_ctx->pid <= 0) { @@ -282,7 +282,13 @@ void hookJniNativeMethods(JNIEnv *env, const char *clz, JNINativeMethod *methods old_jniRegisterNativeMethods(env, clz, hooks.data(), hooks.size()); } -bool ZygiskModule::registerModule(ApiTable *table, long *module) { +ZygiskModule::ZygiskModule(int id, void *handle, void *entry) +: raw_entry(entry), api(this), id(id), handle(handle) {} + +ApiTable::ApiTable(ZygiskModule *m) +: module(m), registerModule(&ZygiskModule::RegisterModule) {} + +bool ZygiskModule::RegisterModule(ApiTable *table, long *module) { long ver = *module; // Unsupported version if (ver > ZYGISK_API_VERSION) @@ -339,36 +345,52 @@ void HookContext::run_modules_pre(const vector &fds) { for (int i = 0; i < fds.size(); ++i) { snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fds[i]); if (void *h = dlopen(buf, RTLD_LAZY)) { - void (*module_entry)(void *, void *); - *(void **) &module_entry = dlsym(h, "zygisk_module_entry"); - if (module_entry) { - modules.emplace_back(i, h); - auto api = new ApiTable(&modules.back()); - module_entry(api, env); - modules.back().table = api; + if (void *e = dlsym(h, "zygisk_module_entry")) { + modules.emplace_back(i, h, e); } } close(fds[i]); } + + // Record all open fds + bitset<1024> open_fds; + auto dir = open_dir("/proc/self/fd"); + for (dirent *entry; (entry = xreaddir(dir.get()));) { + int fd = parse_int(entry->d_name); + if (fd < 0 || fd >= 1024) { + close(fd); + continue; + } + open_fds[fd] = true; + } + for (auto &m : modules) { + m.entry(&m.api, env); if (flags[APP_SPECIALIZE]) { m.preAppSpecialize(args); } else if (flags[SERVER_SPECIALIZE]) { m.preServerSpecialize(server_args); } } + + // Close all unrecorded fds + rewinddir(dir.get()); + for (dirent *entry; (entry = xreaddir(dir.get()));) { + int fd = parse_int(entry->d_name); + if (fd < 0 || fd >= 1024 || !open_fds[fd]) { + close(fd); + } + } } void HookContext::run_modules_post() { - for (auto &m : modules) { + for (const auto &m : modules) { if (flags[APP_SPECIALIZE]) { m.postAppSpecialize(args); } else if (flags[SERVER_SPECIALIZE]) { m.postServerSpecialize(server_args); } - if (m.unload) { - dlclose(m.handle); - } + m.doUnload(); } } @@ -385,7 +407,7 @@ void HookContext::unload_zygisk() { // Strip out all API function pointers for (auto &m : modules) { - memset(m.table, 0, sizeof(*m.table)); + memset(&m.api, 0, sizeof(m.api)); } new_daemon_thread(reinterpret_cast(&dlclose), self_handle); diff --git a/native/jni/zygisk/module.hpp b/native/jni/zygisk/module.hpp index b573f4df5..215602fac 100644 --- a/native/jni/zygisk/module.hpp +++ b/native/jni/zygisk/module.hpp @@ -6,7 +6,7 @@ namespace { using module_abi_v1 = zygisk::internal::module_abi; struct HookContext; -struct ApiTable; +struct ZygiskModule; struct AppSpecializeArgsImpl { jint &uid; @@ -67,55 +67,60 @@ force_cast_wrapper force_cast(R &&x) { return force_cast_wrapper(std::forward(x)); } +struct ApiTable { + // These first 2 entries are permanent + ZygiskModule *module; + bool (*registerModule)(ApiTable *, long *); + + struct { + void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int); + void (*pltHookRegister)(const char *, const char *, void *, void **); + void (*pltHookExclude)(const char *, const char *); + bool (*pltHookCommit)(); + + int (*connectCompanion)(ZygiskModule *); + void (*setOption)(ZygiskModule *, zygisk::Option); + } v1; + + ApiTable(ZygiskModule *m); +}; + struct ZygiskModule { - void preAppSpecialize(AppSpecializeArgsImpl *args) { + void preAppSpecialize(AppSpecializeArgsImpl *args) const { v1->preAppSpecialize(v1->_this, force_cast(args)); } - void postAppSpecialize(const AppSpecializeArgsImpl *args) { + void postAppSpecialize(const AppSpecializeArgsImpl *args) const { v1->postAppSpecialize(v1->_this, force_cast(args)); } - void preServerSpecialize(ServerSpecializeArgsImpl *args) { + void preServerSpecialize(ServerSpecializeArgsImpl *args) const { v1->preServerSpecialize(v1->_this, force_cast(args)); } - void postServerSpecialize(const ServerSpecializeArgsImpl *args) { + void postServerSpecialize(const ServerSpecializeArgsImpl *args) const { v1->postServerSpecialize(v1->_this, force_cast(args)); } int connectCompanion() const; void setOption(zygisk::Option opt); - static bool registerModule(ApiTable *table, long *module); + void doUnload() const { if (unload) dlclose(handle); } - ZygiskModule(int id, void *handle) : handle(handle), id(id) {} + ZygiskModule(int id, void *handle, void *entry); - void * const handle; - ApiTable *table = nullptr; - bool unload = false; + static bool RegisterModule(ApiTable *table, long *module); + + union { + void (* const entry)(void *, void *); + void * const raw_entry; + }; + ApiTable api; private: - int id; + const int id; + bool unload = false; + void * const handle; union { long *ver = nullptr; module_abi_v1 *v1; }; }; -struct ApiTable { - ZygiskModule *module; - bool (*registerModule)(ApiTable *, long *); - - union { - void *padding[6] = {}; - struct { - void (*hookJniNativeMethods)(JNIEnv *, const char *, JNINativeMethod *, int); - void (*pltHookRegister)(const char *, const char *, void *, void **); - void (*pltHookExclude)(const char *, const char *); - bool (*pltHookCommit)(); - - int (*connectCompanion)(ZygiskModule *); - void (*setOption)(ZygiskModule *, zygisk::Option); - } v1; - }; - ApiTable(ZygiskModule *m) : module(m), registerModule(&ZygiskModule::registerModule) {} -}; - } // namespace