From b6412afe96305ccc714ae78e1cb2baa3d943a125 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Wed, 28 Dec 2016 04:02:35 +0800 Subject: [PATCH] Fix Magisk Hide losing root issue This is the issue that has been haunting since day 1. Root and mounted files randomly disappears, and only an reboot can fix it. The issue is that Zygote requires some time to isolate the mount namespace for the children it forks (read: most processes), so in rare cases such as the CPU is on heavy load, or CPU is in deep sleep, it takes longer than usual to finish the mount namespace isolation. Magisk Hide kicks in before the isolation is done, and it will switch to Zygote's namespace and do the unmounting. All children will then lose the mounted files, which includes root. The solution is to first find the namespace id of Zygote, and wait a small period of time and retry if the namespace isn't isolated yet. --- jni/magiskhide.c | 70 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 21 deletions(-) diff --git a/jni/magiskhide.c b/jni/magiskhide.c index e0de676b8..f47e6cfe6 100644 --- a/jni/magiskhide.c +++ b/jni/magiskhide.c @@ -18,8 +18,9 @@ #define HIDELIST "/magisk/.core/magiskhide/hidelist" FILE *logfile; -int i, list_size, pipefd[2]; +int i, list_size, pipefd[2], zygote_num = 0; char **hide_list = NULL; +char zygote_ns[2][32]; pthread_mutex_t mutex; char **file_to_str_arr(FILE *fp, int *size) { @@ -48,6 +49,13 @@ char **file_to_str_arr(FILE *fp, int *size) { return array; } +void read_namespace(const int pid, char* target, const size_t size) { + char path[32]; + snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid); + ssize_t len = readlink(path, target, size); + target[len] = '\0'; +} + void lazy_unmount(const char* mountpoint) { if (umount2(mountpoint, MNT_DETACH) != -1) fprintf(logfile, "MagiskHide: Unmounted (%s)\n", mountpoint); @@ -57,20 +65,40 @@ void lazy_unmount(const char* mountpoint) { int hideMagisk() { int pid; - char path[256], cache_block[256]; + char path[256], cache_block[256], namespace[32]; cache_block[0] = 0; close(pipefd[1]); while(1) { read(pipefd[0], &pid, sizeof(pid)); if(pid == -1) break; + + int badns; + do { + badns = 0; + read_namespace(pid, namespace, 32); + for (i = 0; i < zygote_num; ++i) { + if (strcmp(namespace, zygote_ns[i]) == 0) { + usleep(50000); + badns = 1; + break; + } + } + if (badns) continue; + break; + } while(1); + + fprintf(logfile, "ns=%s\n", namespace); + snprintf(path, 256, "/proc/%d/ns/mnt", pid); + int fd = open(path, O_RDONLY); if(fd == -1) continue; // Maybe process died.. if(setns(fd, 0) == -1) { fprintf(logfile, "MagiskHide: Unable to change namespace for pid=%d\n", pid); continue; } + close(fd); snprintf(path, 256, "/proc/%d/mounts", pid); FILE *mount_fp = fopen(path, "r"); @@ -123,20 +151,6 @@ int hideMagisk() { // Should never go here return 1; - - // Below are UID checks, not used now but I'll leave it here - - // struct stat info; - - // snprintf(path, 256, "/proc/%d", pid); - // if (stat(path, &info) == -1) { - // fprintf(logfile, "MagiskHide: Unable to get info for pid=%d\n", pid); - // return 1; - // } - // if (info.st_uid != uid) { - // fprintf(logfile, "MagiskHide: Incorrect uid=%d, expect uid=%d\n", info.st_uid, uid); - // return 1; - // } } void update_list(const char *listpath) { @@ -204,6 +218,8 @@ void run_as_daemon() { close(STDIN_FILENO); close(STDOUT_FILENO); close(STDERR_FILENO); + logfile = fopen(LOGFILE, "a+"); + setbuf(logfile, NULL); break; default: exit(0); @@ -214,8 +230,21 @@ int main(int argc, char **argv, char **envp) { run_as_daemon(); - logfile = fopen(LOGFILE, "a+"); - setbuf(logfile, NULL); + // Get the mount namespace of zygote for checking + char buffer[512]; + int pid; + FILE *p = popen("/data/busybox/ps | grep zygote | grep -v grep", "r"); + while(fgets(buffer, sizeof(buffer), p)) { + if (zygote_num == 2) break; + sscanf(buffer, "%d", &pid); + read_namespace(pid, zygote_ns[zygote_num], 32); + ++zygote_num; + } + pclose(p); + + for (i = 0; i < zygote_num; ++i) + fprintf(logfile, "Zygote(%d) ns=%s ", i, zygote_ns[i]); + fprintf(logfile, "\n"); // Fork a child to handle namespace switches and unmounts pipe(pipefd); @@ -234,8 +263,7 @@ int main(int argc, char **argv, char **envp) { pthread_mutex_init(&mutex, NULL); pthread_create(&list_monitor, NULL, monitor_list, HIDELIST); - char buffer[512]; - FILE *p = popen("while true; do logcat -b events -v raw -s am_proc_start; sleep 1; done", "r"); + p = popen("while true; do logcat -b events -v raw -s am_proc_start; sleep 1; done", "r"); while(!feof(p)) { //Format of am_proc_start is (as of Android 5.1 and 6.0) @@ -261,7 +289,7 @@ int main(int argc, char **argv, char **envp) { for (i = 0; i < list_size; ++i) { if(strstr(processName, hide_list[i])) { - fprintf(logfile, "MagiskHide: Disabling for process=%s, PID=%d, UID=%d\n", processName, pid, uid); + fprintf(logfile, "MagiskHide: Disabling for process=%s, PID=%d, ", processName, pid, uid); write(pipefd[1], &pid, sizeof(pid)); } }