Close unclosed fds from modules

This commit is contained in:
topjohnwu 2021-11-16 01:59:45 -08:00
parent 28b5faab0c
commit 50515d9128
2 changed files with 71 additions and 44 deletions

View File

@ -164,7 +164,7 @@ DCL_HOOK_FUNC(int, unshare, int flags) {
return res; 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) { DCL_HOOK_FUNC(void, android_log_close) {
HookContext::close_fds(); HookContext::close_fds();
if (g_ctx && g_ctx->pid <= 0) { 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()); 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; long ver = *module;
// Unsupported version // Unsupported version
if (ver > ZYGISK_API_VERSION) if (ver > ZYGISK_API_VERSION)
@ -339,36 +345,52 @@ void HookContext::run_modules_pre(const vector<int> &fds) {
for (int i = 0; i < fds.size(); ++i) { for (int i = 0; i < fds.size(); ++i) {
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fds[i]); snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fds[i]);
if (void *h = dlopen(buf, RTLD_LAZY)) { if (void *h = dlopen(buf, RTLD_LAZY)) {
void (*module_entry)(void *, void *); if (void *e = dlsym(h, "zygisk_module_entry")) {
*(void **) &module_entry = dlsym(h, "zygisk_module_entry"); modules.emplace_back(i, h, e);
if (module_entry) {
modules.emplace_back(i, h);
auto api = new ApiTable(&modules.back());
module_entry(api, env);
modules.back().table = api;
} }
} }
close(fds[i]); 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) { for (auto &m : modules) {
m.entry(&m.api, env);
if (flags[APP_SPECIALIZE]) { if (flags[APP_SPECIALIZE]) {
m.preAppSpecialize(args); m.preAppSpecialize(args);
} else if (flags[SERVER_SPECIALIZE]) { } else if (flags[SERVER_SPECIALIZE]) {
m.preServerSpecialize(server_args); 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() { void HookContext::run_modules_post() {
for (auto &m : modules) { for (const auto &m : modules) {
if (flags[APP_SPECIALIZE]) { if (flags[APP_SPECIALIZE]) {
m.postAppSpecialize(args); m.postAppSpecialize(args);
} else if (flags[SERVER_SPECIALIZE]) { } else if (flags[SERVER_SPECIALIZE]) {
m.postServerSpecialize(server_args); m.postServerSpecialize(server_args);
} }
if (m.unload) { m.doUnload();
dlclose(m.handle);
}
} }
} }
@ -385,7 +407,7 @@ void HookContext::unload_zygisk() {
// Strip out all API function pointers // Strip out all API function pointers
for (auto &m : modules) { for (auto &m : modules) {
memset(m.table, 0, sizeof(*m.table)); memset(&m.api, 0, sizeof(m.api));
} }
new_daemon_thread(reinterpret_cast<thread_entry>(&dlclose), self_handle); new_daemon_thread(reinterpret_cast<thread_entry>(&dlclose), self_handle);

View File

@ -6,7 +6,7 @@ namespace {
using module_abi_v1 = zygisk::internal::module_abi; using module_abi_v1 = zygisk::internal::module_abi;
struct HookContext; struct HookContext;
struct ApiTable; struct ZygiskModule;
struct AppSpecializeArgsImpl { struct AppSpecializeArgsImpl {
jint &uid; jint &uid;
@ -67,55 +67,60 @@ force_cast_wrapper<R> force_cast(R &&x) {
return force_cast_wrapper<R>(std::forward<R>(x)); return force_cast_wrapper<R>(std::forward<R>(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 { struct ZygiskModule {
void preAppSpecialize(AppSpecializeArgsImpl *args) { void preAppSpecialize(AppSpecializeArgsImpl *args) const {
v1->preAppSpecialize(v1->_this, force_cast(args)); 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)); v1->postAppSpecialize(v1->_this, force_cast(args));
} }
void preServerSpecialize(ServerSpecializeArgsImpl *args) { void preServerSpecialize(ServerSpecializeArgsImpl *args) const {
v1->preServerSpecialize(v1->_this, force_cast(args)); 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)); v1->postServerSpecialize(v1->_this, force_cast(args));
} }
int connectCompanion() const; int connectCompanion() const;
void setOption(zygisk::Option opt); 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; static bool RegisterModule(ApiTable *table, long *module);
ApiTable *table = nullptr;
bool unload = false; union {
void (* const entry)(void *, void *);
void * const raw_entry;
};
ApiTable api;
private: private:
int id; const int id;
bool unload = false;
void * const handle;
union { union {
long *ver = nullptr; long *ver = nullptr;
module_abi_v1 *v1; 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 } // namespace