Unload first stage on main thread

This commit is contained in:
topjohnwu 2021-09-22 02:46:07 -07:00
parent 12e9873514
commit cf4ef54dc5
2 changed files with 28 additions and 34 deletions

View File

@ -16,7 +16,6 @@
using namespace std; using namespace std;
static void *self_handle = nullptr; static void *self_handle = nullptr;
static atomic<int> active_threads = -1;
static int zygisk_log(int prio, const char *fmt, va_list ap); static int zygisk_log(int prio, const char *fmt, va_list ap);
@ -31,23 +30,19 @@ static void zygisk_logging() {
void self_unload() { void self_unload() {
LOGD("zygisk: Request to self unload\n"); LOGD("zygisk: Request to self unload\n");
// If deny failed, do not unload or else it will cause SIGSEGV // If unhooking failed, do not unload or else it will cause SIGSEGV
if (!unhook_functions()) if (!unhook_functions())
return; return;
new_daemon_thread(reinterpret_cast<thread_entry>(&dlclose), self_handle); new_daemon_thread(reinterpret_cast<thread_entry>(&dlclose), self_handle);
active_threads--;
} }
static void *unload_first_stage(void *v) { static void unload_first_stage(int, siginfo_t *info, void *) {
// Wait 1ms to make sure first stage is completely done auto path = static_cast<char *>(info->si_value.sival_ptr);
timespec ts = { .tv_sec = 0, .tv_nsec = 1000000L };
nanosleep(&ts, nullptr);
auto path = static_cast<const char *>(v);
unmap_all(path); unmap_all(path);
free(v); free(path);
active_threads--; struct sigaction action{};
return nullptr; action.sa_handler = SIG_DFL;
sigaction(SIGUSR1, &action, nullptr);
} }
// Make sure /proc/self/environ is sanitized // Make sure /proc/self/environ is sanitized
@ -68,17 +63,8 @@ static void sanitize_environ() {
__attribute__((destructor)) __attribute__((destructor))
static void zygisk_cleanup_wait() { static void zygisk_cleanup_wait() {
if (active_threads < 0) // Wait 10us to make sure none of our code is executing
return; timespec ts = { .tv_sec = 0, .tv_nsec = 10000L };
// Setup 1ms
timespec ts = { .tv_sec = 0, .tv_nsec = 1000000L };
// Check flag in busy loop
while (active_threads)
nanosleep(&ts, nullptr);
// Wait another 1ms to make sure all threads left our code
nanosleep(&ts, nullptr); nanosleep(&ts, nullptr);
} }
@ -86,17 +72,12 @@ static void zygisk_cleanup_wait() {
static decltype(&unload_first_stage) second_stage_entry(void *handle) { static decltype(&unload_first_stage) second_stage_entry(void *handle) {
self_handle = handle; self_handle = handle;
unsetenv(INJECT_ENV_2); unsetenv(INJECT_ENV_2);
unsetenv(SECOND_STAGE_PTR); unsetenv(SECOND_STAGE_PTR);
zygisk_logging(); zygisk_logging();
LOGD("zygisk: inject 2nd stage\n"); LOGD("zygisk: inject 2nd stage\n");
active_threads = 1;
hook_functions(); hook_functions();
active_threads++;
return &unload_first_stage; return &unload_first_stage;
} }
@ -131,10 +112,23 @@ static void first_stage_entry() {
char *env = getenv(SECOND_STAGE_PTR); char *env = getenv(SECOND_STAGE_PTR);
decltype(&second_stage_entry) second_stage; decltype(&second_stage_entry) second_stage;
sscanf(env, "%p", &second_stage); sscanf(env, "%p", &second_stage);
auto unload = second_stage(handle); auto unload_handler = second_stage(handle);
// Schedule to unload 1st stage // Register signal handler to unload 1st stage
new_daemon_thread(unload, path); struct sigaction action{};
action.sa_sigaction = unload_handler;
sigaction(SIGUSR1, &action, nullptr);
// Schedule to unload 1st stage 10us later
timer_t timer;
sigevent_t event{};
event.sigev_notify = SIGEV_SIGNAL;
event.sigev_signo = SIGUSR1;
event.sigev_value.sival_ptr = path;
timer_create(CLOCK_MONOTONIC, &event, &timer);
itimerspec time{};
time.it_value.tv_nsec = 10000L;
timer_settime(&timer, 0, &time, nullptr);
} }
__attribute__((constructor)) __attribute__((constructor))

View File

@ -265,10 +265,10 @@ void HookContext::nativeSpecializeAppProcess_post() {
self_unload(); self_unload();
} else { } else {
run_modules_post(); run_modules_post();
}
if (info.is_magisk_app) { if (info.is_magisk_app) {
setenv("ZYGISK_ENABLED", "1", 1); setenv("ZYGISK_ENABLED", "1", 1);
} }
}
g_ctx = nullptr; g_ctx = nullptr;
} }