Magisk/native/jni/magiskhide/proc_monitor.c

205 lines
4.8 KiB
C
Raw Normal View History

2017-07-10 15:39:33 +00:00
/* proc_monitor.c - Monitor am_proc_start events and unmount
2017-08-01 07:34:16 +00:00
*
2017-07-10 15:39:33 +00: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-05 22:12:29 +00:00
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
2017-07-10 15:39:33 +00:00
#include <sys/mount.h>
2017-04-05 22:12:29 +00:00
#include "magisk.h"
2018-07-02 14:11:28 +00:00
#include "daemon.h"
2017-04-05 22:12:29 +00:00
#include "utils.h"
2016-12-30 18:44:24 +00:00
#include "magiskhide.h"
2018-07-02 14:11:28 +00:00
static int sockfd = -1;
2017-04-06 23:50:02 +00:00
2017-04-05 22:12:29 +00:00
// Workaround for the lack of pthread_cancel
static void term_thread(int sig) {
LOGD("proc_monitor: running cleanup\n");
2017-04-20 14:45:56 +00:00
destroy_list();
hideEnabled = 0;
2018-07-02 14:11:28 +00:00
close(sockfd);
sockfd = -1;
2017-04-21 16:54:08 +00:00
pthread_mutex_destroy(&hide_lock);
2017-05-07 19:11:14 +00:00
pthread_mutex_destroy(&file_lock);
LOGD("proc_monitor: terminating...\n");
pthread_exit(NULL);
2017-04-05 22:12:29 +00:00
}
2017-01-01 10:54:13 +00:00
2017-07-10 15:39:33 +00:00
static int read_namespace(const int pid, char* target, const size_t size) {
2017-07-02 17:02:11 +00:00
char path[32];
sprintf(path, "/proc/%d/ns/mnt", pid);
2017-07-10 15:39:33 +00:00
if (access(path, R_OK) == -1)
return 1;
2017-07-02 17:02:11 +00:00
xreadlink(path, target, size);
2017-07-10 15:39:33 +00:00
return 0;
2017-07-02 17:02:11 +00:00
}
2017-07-10 15:39:33 +00:00
static void lazy_unmount(const char* mountpoint) {
2018-01-11 16:23:38 +00:00
if (umount2(mountpoint, MNT_DETACH) != -1)
2017-07-10 15:39:33 +00:00
LOGD("hide_daemon: Unmounted (%s)\n", mountpoint);
}
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;
}
static void hide_daemon(int pid) {
2017-07-10 15:39:33 +00:00
LOGD("hide_daemon: start unmount for pid=[%d]\n", pid);
char *line, buffer[PATH_MAX];
2017-07-10 15:39:33 +00:00
struct vector mount_list;
manage_selinux();
2017-07-18 04:26:23 +00:00
clean_magisk_props();
2017-07-10 15:39:33 +00:00
if (switch_mnt_ns(pid))
goto exit;
2017-07-10 15:39:33 +00:00
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
2017-07-10 15:39:33 +00:00
vec_init(&mount_list);
file_to_vector(buffer, &mount_list);
2018-06-16 21:16:52 +00:00
// Unmount dummy skeletons and /sbin links
2017-07-10 15:39:33 +00:00
vec_for_each(&mount_list, line) {
2018-06-16 21:16:52 +00:00
if (strstr(line, "tmpfs /system/") || strstr(line, "tmpfs /vendor/") || strstr(line, "tmpfs /sbin")) {
2017-07-10 15:39:33 +00:00
sscanf(line, "%*s %4096s", buffer);
lazy_unmount(buffer);
}
free(line);
}
vec_destroy(&mount_list);
// Re-read mount infos
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
2017-07-10 15:39:33 +00:00
vec_init(&mount_list);
file_to_vector(buffer, &mount_list);
2018-06-16 21:16:52 +00:00
// Unmount everything under /system, /vendor, and loop mounts
2017-07-10 15:39:33 +00:00
vec_for_each(&mount_list, line) {
2018-06-16 21:16:52 +00:00
if (strstr(line, "/dev/block/loop") || strstr(line, " /system/") || strstr(line, " /vendor/")) {
2017-07-10 15:39:33 +00:00
sscanf(line, "%*s %4096s", buffer);
lazy_unmount(buffer);
}
free(line);
}
2018-06-16 21:16:52 +00:00
vec_destroy(&mount_list);
2017-07-10 15:39:33 +00:00
exit:
// Send resume signal
kill(pid, SIGCONT);
_exit(0);
2017-07-10 15:39:33 +00:00
}
2017-04-21 16:54:08 +00:00
void proc_monitor() {
// Unblock user signals
sigset_t block_set;
sigemptyset(&block_set);
sigaddset(&block_set, TERM_THREAD);
pthread_sigmask(SIG_UNBLOCK, &block_set, NULL);
2017-04-05 22:12:29 +00:00
// Register the cancel signal
2017-05-07 19:11:14 +00:00
struct sigaction act;
memset(&act, 0, sizeof(act));
act.sa_handler = term_thread;
sigaction(TERM_THREAD, &act, NULL);
2017-05-07 19:11:14 +00:00
if (access("/proc/1/ns/mnt", F_OK) != 0) {
2017-07-10 15:39:33 +00:00
LOGE("proc_monitor: Your kernel doesn't support mount namespace :(\n");
term_thread(TERM_THREAD);
2017-07-10 15:39:33 +00:00
}
2018-07-02 14:11:28 +00:00
// Connect to the log daemon
connect_daemon2(LOG_DAEMON, &sockfd);
write_int(sockfd, HIDE_CONNECT);
2017-07-02 15:04:57 +00:00
2018-07-02 14:11:28 +00:00
FILE *logs = fdopen(sockfd, "r");
char log[4096], *line;
2018-07-01 10:18:12 +00:00
while (1) {
/* It might be interrupted */
if (fgets(log, sizeof(log), logs) == NULL)
continue;
char *ss = strchr(log, '[');
int pid, ppid, ret, comma = 0;
char *pos = ss, proc[256], ns[32], pns[32];
while(1) {
pos = strchr(pos, ',');
if(pos == NULL)
break;
pos[0] = ' ';
++comma;
}
if (comma == 6)
ret = sscanf(ss, "[%*d %d %*d %*d %256s", &pid, proc);
else
ret = sscanf(ss, "[%*d %d %*d %256s", &pid, proc);
2016-12-30 18:44:24 +00:00
if(ret != 2)
continue;
ppid = parse_ppid(pid);
// Allow hiding sub-services of applications
char *colon = strchr(proc, ':');
if (colon)
*colon = '\0';
// Critical region
pthread_mutex_lock(&hide_lock);
vec_for_each(hide_list, line) {
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 10:54:13 +00:00
// Send pause signal ASAP
if (kill(pid, SIGSTOP) == -1)
continue;
2017-07-10 15:39:33 +00:00
// Restore the colon so we can log the actual process name
if (colon)
*colon = ':';
#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 15:39:33 +00: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)
hide_daemon(pid);
break;
2016-12-30 18:44:24 +00:00
}
}
pthread_mutex_unlock(&hide_lock);
2017-06-02 20:31:01 +00:00
}
}