2017-07-10 17:39:33 +02:00
|
|
|
/* proc_monitor.c - Monitor am_proc_start events and unmount
|
2017-08-01 09:34:16 +02:00
|
|
|
*
|
2017-07-10 17:39:33 +02: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 00:12:29 +02: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 01:25:10 +02:00
|
|
|
#include <sys/wait.h>
|
2017-07-10 17:39:33 +02:00
|
|
|
#include <sys/mount.h>
|
2017-04-06 00:12:29 +02:00
|
|
|
|
|
|
|
#include "magisk.h"
|
|
|
|
#include "utils.h"
|
2016-12-30 19:44:24 +01:00
|
|
|
#include "magiskhide.h"
|
|
|
|
|
2018-06-19 19:20:49 +02:00
|
|
|
static int pipefd[2] = { -1, -1 };
|
2017-04-07 01:50:02 +02:00
|
|
|
|
2017-04-06 00:12:29 +02:00
|
|
|
// Workaround for the lack of pthread_cancel
|
2017-11-08 20:05:01 +01:00
|
|
|
static void term_thread(int sig) {
|
2017-04-09 01:25:10 +02:00
|
|
|
LOGD("proc_monitor: running cleanup\n");
|
2017-04-20 16:45:56 +02:00
|
|
|
destroy_list();
|
|
|
|
hideEnabled = 0;
|
2017-10-08 23:05:52 +02:00
|
|
|
// Unregister listener
|
2017-12-18 11:17:37 +01:00
|
|
|
log_events[HIDE_EVENT].fd = -1;
|
2017-10-08 23:05:52 +02:00
|
|
|
close(pipefd[0]);
|
|
|
|
close(pipefd[1]);
|
|
|
|
pipefd[0] = pipefd[1] = -1;
|
2017-04-21 18:54:08 +02:00
|
|
|
pthread_mutex_destroy(&hide_lock);
|
2017-05-07 21:11:14 +02:00
|
|
|
pthread_mutex_destroy(&file_lock);
|
2017-04-09 01:25:10 +02:00
|
|
|
LOGD("proc_monitor: terminating...\n");
|
|
|
|
pthread_exit(NULL);
|
2017-04-06 00:12:29 +02:00
|
|
|
}
|
2017-01-01 11:54:13 +01:00
|
|
|
|
2017-07-10 17:39:33 +02:00
|
|
|
static int read_namespace(const int pid, char* target, const size_t size) {
|
2017-07-02 19:02:11 +02:00
|
|
|
char path[32];
|
2018-06-19 19:20:49 +02:00
|
|
|
sprintf(path, "/proc/%d/ns/mnt", pid);
|
2017-07-10 17:39:33 +02:00
|
|
|
if (access(path, R_OK) == -1)
|
|
|
|
return 1;
|
2017-07-02 19:02:11 +02:00
|
|
|
xreadlink(path, target, size);
|
2017-07-10 17:39:33 +02:00
|
|
|
return 0;
|
2017-07-02 19:02:11 +02:00
|
|
|
}
|
|
|
|
|
2017-07-10 17:39:33 +02:00
|
|
|
static void lazy_unmount(const char* mountpoint) {
|
2018-01-11 17:23:38 +01:00
|
|
|
if (umount2(mountpoint, MNT_DETACH) != -1)
|
2017-07-10 17:39:33 +02:00
|
|
|
LOGD("hide_daemon: Unmounted (%s)\n", mountpoint);
|
|
|
|
}
|
|
|
|
|
2018-06-19 19:20:49 +02:00
|
|
|
static int parse_ppid(int pid) {
|
|
|
|
char stat[512], path[32];
|
|
|
|
int fd, ppid;
|
|
|
|
sprintf(path, "/proc/%d/stat", pid);
|
|
|
|
fd = xopen(path, O_RDONLY);
|
|
|
|
xread(fd, stat, sizeof(stat));
|
|
|
|
close(fd);
|
|
|
|
/* PID COMM STATE PPID ..... */
|
|
|
|
sscanf(stat, "%*d %*s %*c %d", &ppid);
|
|
|
|
return ppid;
|
|
|
|
}
|
|
|
|
|
2018-04-29 09:10:35 +02:00
|
|
|
static void hide_daemon(int pid) {
|
2017-07-10 17:39:33 +02:00
|
|
|
LOGD("hide_daemon: start unmount for pid=[%d]\n", pid);
|
|
|
|
|
2017-10-08 23:05:52 +02:00
|
|
|
char *line, buffer[PATH_MAX];
|
2017-07-10 17:39:33 +02:00
|
|
|
struct vector mount_list;
|
|
|
|
|
|
|
|
manage_selinux();
|
2017-07-18 06:26:23 +02:00
|
|
|
clean_magisk_props();
|
2017-07-10 17:39:33 +02:00
|
|
|
|
|
|
|
if (switch_mnt_ns(pid))
|
2017-10-08 23:05:52 +02:00
|
|
|
goto exit;
|
2017-07-10 17:39:33 +02:00
|
|
|
|
2017-10-08 23:05:52 +02:00
|
|
|
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
2017-07-10 17:39:33 +02:00
|
|
|
vec_init(&mount_list);
|
|
|
|
file_to_vector(buffer, &mount_list);
|
|
|
|
|
2018-06-16 23:16:52 +02:00
|
|
|
// Unmount dummy skeletons and /sbin links
|
2017-07-10 17:39:33 +02:00
|
|
|
vec_for_each(&mount_list, line) {
|
2018-06-16 23:16:52 +02:00
|
|
|
if (strstr(line, "tmpfs /system/") || strstr(line, "tmpfs /vendor/") || strstr(line, "tmpfs /sbin")) {
|
2017-07-10 17:39:33 +02:00
|
|
|
sscanf(line, "%*s %4096s", buffer);
|
|
|
|
lazy_unmount(buffer);
|
|
|
|
}
|
|
|
|
free(line);
|
|
|
|
}
|
|
|
|
vec_destroy(&mount_list);
|
|
|
|
|
|
|
|
// Re-read mount infos
|
2017-10-08 23:05:52 +02:00
|
|
|
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
2017-07-10 17:39:33 +02:00
|
|
|
vec_init(&mount_list);
|
|
|
|
file_to_vector(buffer, &mount_list);
|
|
|
|
|
2018-06-16 23:16:52 +02:00
|
|
|
// Unmount everything under /system, /vendor, and loop mounts
|
2017-07-10 17:39:33 +02:00
|
|
|
vec_for_each(&mount_list, line) {
|
2018-06-16 23:16:52 +02:00
|
|
|
if (strstr(line, "/dev/block/loop") || strstr(line, " /system/") || strstr(line, " /vendor/")) {
|
2017-07-10 17:39:33 +02:00
|
|
|
sscanf(line, "%*s %4096s", buffer);
|
|
|
|
lazy_unmount(buffer);
|
|
|
|
}
|
|
|
|
free(line);
|
|
|
|
}
|
2018-06-16 23:16:52 +02:00
|
|
|
vec_destroy(&mount_list);
|
2017-07-10 17:39:33 +02:00
|
|
|
|
2017-10-08 23:05:52 +02:00
|
|
|
exit:
|
|
|
|
// Send resume signal
|
|
|
|
kill(pid, SIGCONT);
|
|
|
|
_exit(0);
|
2017-07-10 17:39:33 +02:00
|
|
|
}
|
|
|
|
|
2017-04-21 18:54:08 +02:00
|
|
|
void proc_monitor() {
|
2017-11-14 22:15:58 +01:00
|
|
|
// Unblock user signals
|
|
|
|
sigset_t block_set;
|
|
|
|
sigemptyset(&block_set);
|
|
|
|
sigaddset(&block_set, TERM_THREAD);
|
|
|
|
pthread_sigmask(SIG_UNBLOCK, &block_set, NULL);
|
|
|
|
|
2017-04-06 00:12:29 +02:00
|
|
|
// Register the cancel signal
|
2017-05-07 21:11:14 +02:00
|
|
|
struct sigaction act;
|
|
|
|
memset(&act, 0, sizeof(act));
|
2017-11-08 20:05:01 +01:00
|
|
|
act.sa_handler = term_thread;
|
|
|
|
sigaction(TERM_THREAD, &act, NULL);
|
2017-05-07 21:11:14 +02:00
|
|
|
|
2018-06-19 19:20:49 +02:00
|
|
|
if (access("/proc/1/ns/mnt", F_OK) != 0) {
|
2017-07-10 17:39:33 +02:00
|
|
|
LOGE("proc_monitor: Your kernel doesn't support mount namespace :(\n");
|
2017-11-08 20:05:01 +01:00
|
|
|
term_thread(TERM_THREAD);
|
2017-07-10 17:39:33 +02:00
|
|
|
}
|
2017-03-25 11:21:48 +01:00
|
|
|
|
2017-10-08 23:05:52 +02:00
|
|
|
// Register our listener to logcat monitor
|
|
|
|
xpipe2(pipefd, O_CLOEXEC);
|
2017-12-18 11:17:37 +01:00
|
|
|
log_events[HIDE_EVENT].fd = pipefd[1];
|
2017-07-02 17:04:57 +02:00
|
|
|
|
2018-07-01 12:18:12 +02:00
|
|
|
FILE *logs = fdopen(pipefd[0], "r");
|
|
|
|
char log[PIPE_BUF], *line;
|
|
|
|
while (1) {
|
|
|
|
/* It might be interrupted */
|
|
|
|
if (fgets(log, sizeof(log), logs) == NULL)
|
2017-11-14 22:15:58 +01:00
|
|
|
continue;
|
2017-12-18 11:17:37 +01:00
|
|
|
char *ss = strchr(log, '[');
|
2018-06-19 19:20:49 +02:00
|
|
|
int pid, ppid, ret, comma = 0;
|
|
|
|
char *pos = ss, proc[256], ns[32], pns[32];
|
2017-12-18 11:17:37 +01:00
|
|
|
|
|
|
|
while(1) {
|
|
|
|
pos = strchr(pos, ',');
|
|
|
|
if(pos == NULL)
|
|
|
|
break;
|
|
|
|
pos[0] = ' ';
|
|
|
|
++comma;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (comma == 6)
|
2018-06-19 19:20:49 +02:00
|
|
|
ret = sscanf(ss, "[%*d %d %*d %*d %256s", &pid, proc);
|
2017-12-18 11:17:37 +01:00
|
|
|
else
|
2018-06-19 19:20:49 +02:00
|
|
|
ret = sscanf(ss, "[%*d %d %*d %256s", &pid, proc);
|
2016-12-30 19:44:24 +01:00
|
|
|
|
2017-12-18 11:17:37 +01:00
|
|
|
if(ret != 2)
|
|
|
|
continue;
|
|
|
|
|
2018-06-19 19:20:49 +02:00
|
|
|
ppid = parse_ppid(pid);
|
|
|
|
|
2018-04-29 09:10:35 +02:00
|
|
|
// Allow hiding sub-services of applications
|
2018-06-19 19:20:49 +02:00
|
|
|
char *colon = strchr(proc, ':');
|
2018-04-29 09:10:35 +02:00
|
|
|
if (colon)
|
|
|
|
*colon = '\0';
|
|
|
|
|
2017-12-18 11:17:37 +01:00
|
|
|
// Critical region
|
|
|
|
pthread_mutex_lock(&hide_lock);
|
|
|
|
vec_for_each(hide_list, line) {
|
2018-06-19 19:20:49 +02:00
|
|
|
if (strcmp(proc, line) == 0) {
|
|
|
|
read_namespace(ppid, pns, sizeof(pns));
|
|
|
|
do {
|
|
|
|
read_namespace(pid, ns, sizeof(ns));
|
|
|
|
if (strcmp(ns, pns) == 0)
|
|
|
|
usleep(50);
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
} while (1);
|
2017-01-01 11:54:13 +01:00
|
|
|
|
2017-12-18 11:17:37 +01:00
|
|
|
// Send pause signal ASAP
|
2018-06-19 19:20:49 +02:00
|
|
|
if (kill(pid, SIGSTOP) == -1)
|
|
|
|
continue;
|
2017-07-10 17:39:33 +02:00
|
|
|
|
2018-04-29 09:10:35 +02:00
|
|
|
// Restore the colon so we can log the actual process name
|
|
|
|
if (colon)
|
|
|
|
*colon = ':';
|
2018-06-19 19:20:49 +02:00
|
|
|
#ifdef MAGISK_DEBUG
|
|
|
|
LOGI("proc_monitor: %s (PID=[%d] ns=%s)(PPID=[%d] ns=%s)\n", proc, pid, ns + 4, ppid, pns + 4);
|
|
|
|
#else
|
|
|
|
LOGI("proc_monitor: %s\n", proc);
|
|
|
|
#endif
|
2017-07-10 17:39:33 +02:00
|
|
|
|
2017-12-18 11:17:37 +01:00
|
|
|
/*
|
|
|
|
* The setns system call do not support multithread processes
|
|
|
|
* We have to fork a new process, setns, then do the unmounts
|
|
|
|
*/
|
|
|
|
if (fork_dont_care() == 0)
|
2018-04-29 09:10:35 +02:00
|
|
|
hide_daemon(pid);
|
2017-04-09 01:25:10 +02:00
|
|
|
|
2017-12-18 11:17:37 +01:00
|
|
|
break;
|
2016-12-30 19:44:24 +01:00
|
|
|
}
|
2017-04-09 01:25:10 +02:00
|
|
|
}
|
2017-12-18 11:17:37 +01:00
|
|
|
pthread_mutex_unlock(&hide_lock);
|
2017-06-02 22:31:01 +02:00
|
|
|
}
|
2017-03-24 20:45:12 +01:00
|
|
|
}
|