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.
This commit is contained in:
topjohnwu 2016-12-28 04:02:35 +08:00
parent 4e88186903
commit b6412afe96

View File

@ -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));
}
}