2017-07-10 23:39:33 +08:00
|
|
|
/* proc_monitor.c - Monitor am_proc_start events and unmount
|
2017-08-01 15:34:16 +08:00
|
|
|
*
|
2017-07-10 23:39:33 +08:00
|
|
|
* We monitor the logcat am_proc_start events. When a target starts up,
|
|
|
|
* we pause it ASAP, and fork a new process to join its mount namespace
|
|
|
|
* and do all the unmounting/mocking
|
2017-04-06 06:12:29 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
|
|
|
#include <signal.h>
|
|
|
|
#include <pthread.h>
|
|
|
|
#include <sys/types.h>
|
2017-04-09 07:25:10 +08:00
|
|
|
#include <sys/wait.h>
|
2017-07-10 23:39:33 +08:00
|
|
|
#include <sys/mount.h>
|
2017-04-06 06:12:29 +08:00
|
|
|
|
|
|
|
#include "magisk.h"
|
|
|
|
#include "utils.h"
|
2016-12-31 02:44:24 +08:00
|
|
|
#include "magiskhide.h"
|
|
|
|
|
2017-07-10 23:39:33 +08:00
|
|
|
static char init_ns[32], zygote_ns[2][32], cache_block[256];
|
2017-10-09 05:05:52 +08:00
|
|
|
static int zygote_num, has_cache = 1, pipefd[2] = { -1, -1 };
|
2017-04-07 07:50:02 +08:00
|
|
|
|
2017-04-06 06:12:29 +08:00
|
|
|
// Workaround for the lack of pthread_cancel
|
|
|
|
static void quit_pthread(int sig) {
|
2017-05-12 15:28:15 +08:00
|
|
|
err_handler = do_nothing;
|
2017-04-09 07:25:10 +08:00
|
|
|
LOGD("proc_monitor: running cleanup\n");
|
2017-04-20 22:45:56 +08:00
|
|
|
destroy_list();
|
|
|
|
hideEnabled = 0;
|
2017-10-09 05:05:52 +08:00
|
|
|
// Unregister listener
|
|
|
|
logcat_events[HIDE_EVENT] = -1;
|
|
|
|
close(pipefd[0]);
|
|
|
|
close(pipefd[1]);
|
|
|
|
pipefd[0] = pipefd[1] = -1;
|
2017-04-22 00:54:08 +08:00
|
|
|
pthread_mutex_destroy(&hide_lock);
|
2017-05-08 03:11:14 +08:00
|
|
|
pthread_mutex_destroy(&file_lock);
|
2017-04-09 07:25:10 +08:00
|
|
|
LOGD("proc_monitor: terminating...\n");
|
|
|
|
pthread_exit(NULL);
|
2017-04-06 06:12:29 +08:00
|
|
|
}
|
2017-01-01 18:54:13 +08:00
|
|
|
|
2017-07-03 01:02:11 +08:00
|
|
|
static void proc_monitor_err() {
|
2017-10-09 05:05:52 +08:00
|
|
|
LOGE("proc_monitor: error occured, stopping magiskhide services\n");
|
2017-07-03 01:02:11 +08:00
|
|
|
quit_pthread(SIGUSR1);
|
|
|
|
}
|
|
|
|
|
2017-07-10 23:39:33 +08:00
|
|
|
static int read_namespace(const int pid, char* target, const size_t size) {
|
2017-07-03 01:02:11 +08:00
|
|
|
char path[32];
|
|
|
|
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
|
2017-07-10 23:39:33 +08:00
|
|
|
if (access(path, R_OK) == -1)
|
|
|
|
return 1;
|
2017-07-03 01:02:11 +08:00
|
|
|
xreadlink(path, target, size);
|
2017-07-10 23:39:33 +08:00
|
|
|
return 0;
|
2017-07-03 01:02:11 +08:00
|
|
|
}
|
|
|
|
|
2017-04-07 07:50:02 +08:00
|
|
|
static void store_zygote_ns(int pid) {
|
2017-04-18 19:32:50 +08:00
|
|
|
if (zygote_num == 2) return;
|
2017-04-07 07:50:02 +08:00
|
|
|
do {
|
|
|
|
usleep(500);
|
|
|
|
read_namespace(pid, zygote_ns[zygote_num], 32);
|
|
|
|
} while (strcmp(zygote_ns[zygote_num], init_ns) == 0);
|
|
|
|
++zygote_num;
|
|
|
|
}
|
|
|
|
|
2017-07-10 23:39:33 +08:00
|
|
|
static void lazy_unmount(const char* mountpoint) {
|
|
|
|
if (umount2(mountpoint, MNT_DETACH) != -1)
|
|
|
|
LOGD("hide_daemon: Unmounted (%s)\n", mountpoint);
|
|
|
|
else
|
|
|
|
LOGD("hide_daemon: Unmount Failed (%s)\n", mountpoint);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void hide_daemon_err() {
|
2017-10-09 05:05:52 +08:00
|
|
|
LOGE("hide_daemon: error occured\n");
|
2017-07-10 23:39:33 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void hide_daemon(int pid) {
|
|
|
|
LOGD("hide_daemon: start unmount for pid=[%d]\n", pid);
|
2017-10-09 05:05:52 +08:00
|
|
|
// When an error occurs, report its failure
|
2017-07-10 23:39:33 +08:00
|
|
|
err_handler = hide_daemon_err;
|
|
|
|
|
2017-10-09 05:05:52 +08:00
|
|
|
char *line, buffer[PATH_MAX];
|
2017-07-10 23:39:33 +08:00
|
|
|
struct vector mount_list;
|
|
|
|
|
|
|
|
manage_selinux();
|
2017-07-18 12:26:23 +08:00
|
|
|
clean_magisk_props();
|
2017-07-10 23:39:33 +08:00
|
|
|
|
|
|
|
if (switch_mnt_ns(pid))
|
2017-10-09 05:05:52 +08:00
|
|
|
goto exit;
|
2017-07-10 23:39:33 +08:00
|
|
|
|
2017-10-09 05:05:52 +08:00
|
|
|
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
2017-07-10 23:39:33 +08:00
|
|
|
vec_init(&mount_list);
|
|
|
|
file_to_vector(buffer, &mount_list);
|
|
|
|
|
|
|
|
// Find the cache block name if not found yet
|
2017-09-13 15:45:07 +08:00
|
|
|
if (has_cache && cache_block[0] == '\0') {
|
2017-07-10 23:39:33 +08:00
|
|
|
vec_for_each(&mount_list, line) {
|
|
|
|
if (strstr(line, " /cache ")) {
|
|
|
|
sscanf(line, "%256s", cache_block);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2017-09-13 15:45:07 +08:00
|
|
|
if (strlen(cache_block) == 0)
|
|
|
|
has_cache = 0;
|
2017-07-10 23:39:33 +08:00
|
|
|
}
|
|
|
|
|
2017-09-13 15:45:07 +08:00
|
|
|
// Unmout cache mounts
|
|
|
|
if (has_cache) {
|
|
|
|
vec_for_each(&mount_list, line) {
|
|
|
|
if (strstr(line, cache_block) && (strstr(line, " /system/") || strstr(line, " /vendor/"))) {
|
|
|
|
sscanf(line, "%*s %4096s", buffer);
|
|
|
|
lazy_unmount(buffer);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Unmount dummy skeletons, /sbin links, and mirrors
|
2017-07-10 23:39:33 +08:00
|
|
|
vec_for_each(&mount_list, line) {
|
2017-09-13 15:45:07 +08:00
|
|
|
if (strstr(line, "tmpfs /system") || strstr(line, "tmpfs /vendor") || strstr(line, "tmpfs /sbin") || strstr(line, MIRRDIR)) {
|
2017-07-10 23:39:33 +08:00
|
|
|
sscanf(line, "%*s %4096s", buffer);
|
|
|
|
lazy_unmount(buffer);
|
|
|
|
}
|
|
|
|
free(line);
|
|
|
|
}
|
|
|
|
vec_destroy(&mount_list);
|
|
|
|
|
|
|
|
// Re-read mount infos
|
2017-10-09 05:05:52 +08:00
|
|
|
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
2017-07-10 23:39:33 +08:00
|
|
|
vec_init(&mount_list);
|
|
|
|
file_to_vector(buffer, &mount_list);
|
|
|
|
|
2017-09-27 04:35:16 +08:00
|
|
|
// Unmount any loop mounts
|
2017-07-10 23:39:33 +08:00
|
|
|
vec_for_each(&mount_list, line) {
|
2017-09-27 04:35:16 +08:00
|
|
|
if (strstr(line, "/dev/block/loop")) {
|
2017-07-10 23:39:33 +08:00
|
|
|
sscanf(line, "%*s %4096s", buffer);
|
|
|
|
lazy_unmount(buffer);
|
|
|
|
}
|
|
|
|
free(line);
|
|
|
|
}
|
|
|
|
|
2017-10-09 05:05:52 +08:00
|
|
|
exit:
|
|
|
|
// Send resume signal
|
|
|
|
kill(pid, SIGCONT);
|
|
|
|
// Free up memory
|
2017-07-10 23:39:33 +08:00
|
|
|
vec_destroy(&mount_list);
|
2017-10-09 05:05:52 +08:00
|
|
|
_exit(0);
|
2017-07-10 23:39:33 +08:00
|
|
|
}
|
|
|
|
|
2017-04-22 00:54:08 +08:00
|
|
|
void proc_monitor() {
|
2017-04-06 06:12:29 +08:00
|
|
|
// Register the cancel signal
|
2017-05-08 03:11:14 +08:00
|
|
|
struct sigaction act;
|
|
|
|
memset(&act, 0, sizeof(act));
|
|
|
|
act.sa_handler = quit_pthread;
|
2017-05-12 15:28:15 +08:00
|
|
|
sigaction(SIGUSR1, &act, NULL);
|
2017-05-08 03:11:14 +08:00
|
|
|
|
2017-04-24 21:43:30 +08:00
|
|
|
// The error handler should stop magiskhide services
|
2017-04-09 07:25:10 +08:00
|
|
|
err_handler = proc_monitor_err;
|
2017-03-25 11:21:48 +01:00
|
|
|
|
2017-07-10 23:39:33 +08:00
|
|
|
cache_block[0] = '\0';
|
2017-03-25 11:21:48 +01:00
|
|
|
|
2017-04-06 06:12:29 +08:00
|
|
|
// Get the mount namespace of init
|
2017-07-10 23:39:33 +08:00
|
|
|
if (read_namespace(1, init_ns, 32)) {
|
|
|
|
LOGE("proc_monitor: Your kernel doesn't support mount namespace :(\n");
|
|
|
|
proc_monitor_err();
|
|
|
|
}
|
2017-04-06 06:12:29 +08:00
|
|
|
LOGI("proc_monitor: init ns=%s\n", init_ns);
|
|
|
|
|
|
|
|
// Get the mount namespace of zygote
|
2017-07-02 23:04:57 +08:00
|
|
|
zygote_num = 0;
|
2017-04-17 16:36:49 +08:00
|
|
|
while(!zygote_num) {
|
|
|
|
// Check zygote every 2 secs
|
|
|
|
sleep(2);
|
|
|
|
ps_filter_proc_name("zygote", store_zygote_ns);
|
|
|
|
}
|
2017-05-04 02:58:37 +08:00
|
|
|
ps_filter_proc_name("zygote64", store_zygote_ns);
|
2017-04-06 06:12:29 +08:00
|
|
|
|
|
|
|
switch(zygote_num) {
|
|
|
|
case 1:
|
|
|
|
LOGI("proc_monitor: zygote ns=%s\n", zygote_ns[0]);
|
|
|
|
break;
|
|
|
|
case 2:
|
2017-07-08 23:51:58 +08:00
|
|
|
LOGI("proc_monitor: zygote ns=%s zygote64 ns=%s\n", zygote_ns[0], zygote_ns[1]);
|
2017-04-06 06:12:29 +08:00
|
|
|
break;
|
|
|
|
}
|
2017-03-25 11:21:48 +01:00
|
|
|
|
2017-10-09 05:05:52 +08:00
|
|
|
// Register our listener to logcat monitor
|
|
|
|
xpipe2(pipefd, O_CLOEXEC);
|
|
|
|
logcat_events[HIDE_EVENT] = pipefd[1];
|
2017-07-02 23:04:57 +08:00
|
|
|
|
2017-10-09 05:05:52 +08:00
|
|
|
for (char *log, *line; xxread(pipefd[0], &log, sizeof(log)) > 0; free(log)) {
|
|
|
|
char *ss;
|
|
|
|
if ((ss = strstr(log, "am_proc_start")) && (ss = strchr(ss, '['))) {
|
2017-07-10 23:39:33 +08:00
|
|
|
int pid, ret, comma = 0;
|
2017-10-09 05:05:52 +08:00
|
|
|
char *pos = ss, processName[256], ns[32];
|
2017-06-03 04:31:01 +08:00
|
|
|
|
|
|
|
while(1) {
|
|
|
|
pos = strchr(pos, ',');
|
|
|
|
if(pos == NULL)
|
|
|
|
break;
|
|
|
|
pos[0] = ' ';
|
|
|
|
++comma;
|
|
|
|
}
|
2016-12-31 02:44:24 +08:00
|
|
|
|
2017-06-03 04:31:01 +08:00
|
|
|
if (comma == 6)
|
2017-10-09 05:05:52 +08:00
|
|
|
ret = sscanf(ss, "[%*d %d %*d %*d %256s", &pid, processName);
|
2017-06-03 04:31:01 +08:00
|
|
|
else
|
2017-10-09 05:05:52 +08:00
|
|
|
ret = sscanf(ss, "[%*d %d %*d %256s", &pid, processName);
|
2017-06-03 04:31:01 +08:00
|
|
|
|
|
|
|
if(ret != 2)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
ret = 0;
|
|
|
|
|
|
|
|
// Critical region
|
|
|
|
pthread_mutex_lock(&hide_lock);
|
|
|
|
vec_for_each(hide_list, line) {
|
|
|
|
if (strcmp(processName, line) == 0) {
|
|
|
|
while(1) {
|
|
|
|
ret = 1;
|
|
|
|
for (int i = 0; i < zygote_num; ++i) {
|
2017-10-09 05:05:52 +08:00
|
|
|
read_namespace(pid, ns, sizeof(ns));
|
|
|
|
if (strcmp(ns, zygote_ns[i]) == 0) {
|
2017-06-03 04:31:01 +08:00
|
|
|
usleep(50);
|
|
|
|
ret = 0;
|
|
|
|
break;
|
|
|
|
}
|
2017-01-01 18:54:13 +08:00
|
|
|
}
|
2017-06-03 04:31:01 +08:00
|
|
|
if (ret) break;
|
2017-01-01 18:54:13 +08:00
|
|
|
}
|
|
|
|
|
2017-06-03 04:31:01 +08:00
|
|
|
// Send pause signal ASAP
|
2017-10-09 05:05:52 +08:00
|
|
|
if (kill(pid, SIGSTOP) == -1) continue;
|
2017-07-10 23:39:33 +08:00
|
|
|
|
2017-10-09 05:05:52 +08:00
|
|
|
LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, pid, ns);
|
2017-07-10 23:39:33 +08:00
|
|
|
|
|
|
|
/*
|
|
|
|
* The setns system call do not support multithread processes
|
|
|
|
* We have to fork a new process, setns, then do the unmounts
|
|
|
|
*/
|
2017-10-09 05:05:52 +08:00
|
|
|
if (fork_dont_care() == 0)
|
|
|
|
hide_daemon(pid);
|
2017-04-09 07:25:10 +08:00
|
|
|
|
2017-06-03 04:31:01 +08:00
|
|
|
break;
|
|
|
|
}
|
2016-12-31 02:44:24 +08:00
|
|
|
}
|
2017-06-03 04:31:01 +08:00
|
|
|
pthread_mutex_unlock(&hide_lock);
|
2017-04-09 07:25:10 +08:00
|
|
|
}
|
2017-06-03 04:31:01 +08:00
|
|
|
}
|
2017-03-24 20:45:12 +01:00
|
|
|
}
|