Magisk/native/jni/magiskhide/proc_monitor.cpp

188 lines
4.4 KiB
C++
Raw Normal View History

2018-11-01 13:23:12 -04:00
/* proc_monitor.cpp - 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>
2018-07-13 22:14:32 +08:00
#include <fcntl.h>
2017-04-06 06:12:29 +08:00
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
2017-07-10 23:39:33 +08:00
#include <sys/mount.h>
2019-01-19 23:59:37 -05:00
#include <vector>
#include <string>
2017-04-06 06:12:29 +08:00
#include "magisk.h"
2018-07-02 22:11:28 +08:00
#include "daemon.h"
2018-11-03 03:06:01 -04:00
#include "utils.h"
2016-12-31 02:44:24 +08:00
#include "magiskhide.h"
2019-01-19 23:59:37 -05:00
using namespace std;
2018-07-02 22:11:28 +08:00
static int sockfd = -1;
extern char *system_block, *vendor_block, *magiskloop;
2017-04-07 07:50:02 +08:00
2017-04-06 06:12:29 +08:00
// Workaround for the lack of pthread_cancel
2018-11-01 13:23:12 -04:00
static void term_thread(int) {
LOGD("proc_monitor: running cleanup\n");
2019-01-19 23:59:37 -05:00
hide_list.clear();
2018-11-16 00:37:41 -05:00
hide_enabled = false;
2018-07-02 22:11:28 +08:00
close(sockfd);
sockfd = -1;
2018-11-01 13:23:12 -04:00
pthread_mutex_destroy(&list_lock);
LOGD("proc_monitor: terminating\n");
2018-11-07 02:10:38 -05:00
pthread_exit(nullptr);
2017-04-06 06:12:29 +08:00
}
2017-01-01 18:54:13 +08:00
2018-07-11 23:41:38 +08:00
static int read_ns(const int pid, struct stat *st) {
2017-07-03 01:02:11 +08:00
char path[32];
sprintf(path, "/proc/%d/ns/mnt", pid);
2018-07-11 23:41:38 +08:00
return stat(path, st);
2017-07-03 01:02:11 +08:00
}
2018-11-23 14:32:33 -05:00
static inline void lazy_unmount(const char* mountpoint) {
2018-01-12 00:23:38 +08:00
if (umount2(mountpoint, MNT_DETACH) != -1)
2017-07-10 23:39:33 +08:00
LOGD("hide_daemon: Unmounted (%s)\n", mountpoint);
}
static int parse_ppid(int pid) {
2018-11-23 14:32:33 -05:00
char path[32];
int ppid;
sprintf(path, "/proc/%d/stat", pid);
2018-11-24 15:53:15 -05:00
FILE *stat = fopen(path, "re");
2018-11-23 14:32:33 -05:00
if (stat == nullptr)
return -1;
/* PID COMM STATE PPID ..... */
2018-11-23 14:32:33 -05:00
fscanf(stat, "%*d %*s %*c %d", &ppid);
2018-11-23 21:15:44 -05:00
fclose(stat);
return ppid;
}
static void hide_daemon(int pid) {
LOGD("hide_daemon: handling pid=[%d]\n", pid);
2017-07-10 23:39:33 +08:00
2018-11-23 14:32:33 -05:00
char buffer[4096];
2019-01-19 23:59:37 -05:00
vector<string> mounts;
2017-07-10 23:39:33 +08:00
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))
goto exit;
2017-07-10 23:39:33 +08:00
2018-11-13 02:07:02 -05:00
snprintf(buffer, sizeof(buffer), "/proc/%d", pid);
chdir(buffer);
2017-07-10 23:39:33 +08:00
2019-01-19 23:59:37 -05:00
mounts = file_to_vector("mounts");
2018-06-17 05:16:52 +08:00
// Unmount dummy skeletons and /sbin links
2018-11-01 13:23:12 -04:00
for (auto &s : mounts) {
2019-01-19 23:59:37 -05:00
if (str_contains(s, "tmpfs /system/") || str_contains(s, "tmpfs /vendor/") ||
str_contains(s, "tmpfs /sbin")) {
sscanf(s.c_str(), "%*s %4096s", buffer);
2017-07-10 23:39:33 +08:00
lazy_unmount(buffer);
}
}
// Re-read mount infos
2019-01-19 23:59:37 -05:00
mounts = file_to_vector("mounts");
2017-07-10 23:39:33 +08:00
2018-06-17 05:16:52 +08:00
// Unmount everything under /system, /vendor, and loop mounts
2018-11-01 13:23:12 -04:00
for (auto &s : mounts) {
2019-01-19 23:59:37 -05:00
if ((str_contains(s, " /system/") || str_contains(s, " /vendor/")) &&
(str_contains(s, system_block) || str_contains(s, vendor_block) || str_contains(s, magiskloop))) {
sscanf(s.c_str(), "%*s %4096s", buffer);
2017-07-10 23:39:33 +08:00
lazy_unmount(buffer);
}
}
exit:
// Send resume signal
kill(pid, SIGCONT);
_exit(0);
2017-07-10 23:39:33 +08:00
}
2017-04-22 00:54:08 +08:00
void proc_monitor() {
// Unblock user signals
sigset_t block_set;
sigemptyset(&block_set);
sigaddset(&block_set, TERM_THREAD);
2019-01-19 23:59:37 -05:00
pthread_sigmask(SIG_UNBLOCK, &block_set, nullptr);
2017-04-06 06:12:29 +08:00
// Register the cancel signal
2019-01-19 23:59:37 -05:00
struct sigaction act{};
act.sa_handler = term_thread;
2019-01-19 23:59:37 -05:00
sigaction(TERM_THREAD, &act, nullptr);
2017-05-08 03:11:14 +08:00
if (access("/proc/1/ns/mnt", F_OK) != 0) {
2017-07-10 23:39:33 +08:00
LOGE("proc_monitor: Your kernel doesn't support mount namespace :(\n");
term_thread(TERM_THREAD);
2017-07-10 23:39:33 +08:00
}
2018-10-12 00:50:47 -04:00
// Connect to the log daemon
sockfd = connect_log_daemon();
if (sockfd < 0)
2018-11-23 14:32:33 -05:00
pthread_exit(nullptr);
2018-10-12 00:50:47 -04:00
write_int(sockfd, HIDE_CONNECT);
FILE *log_in = fdopen(sockfd, "r");
char buf[4096];
while (fgets(buf, sizeof(buf), log_in)) {
char *log;
int pid, ppid;
2018-10-12 00:50:47 -04:00
struct stat ns, pns;
if ((log = strchr(buf, '[')) == nullptr)
continue;
// Extract pid
if (sscanf(log, "[%*d,%d", &pid) != 1)
continue;
// Extract last token (component name)
const char *tok, *cpnt = "";
while ((tok = strtok_r(nullptr, ",[]\n", &log)))
cpnt = tok;
if (cpnt[0] == '\0')
2018-10-12 00:50:47 -04:00
continue;
// Make sure our target is alive
2018-11-23 14:32:33 -05:00
if ((ppid = parse_ppid(pid)) < 0 || read_ns(ppid, &pns))
2018-10-12 00:50:47 -04:00
continue;
2018-11-01 13:23:12 -04:00
bool hide = false;
pthread_mutex_lock(&list_lock);
for (auto &s : hide_list) {
2019-01-19 23:59:37 -05:00
if (strncmp(cpnt, s.c_str(), s.size() - 1) == 0) {
2018-11-01 13:23:12 -04:00
hide = true;
2018-10-12 00:50:47 -04:00
break;
}
2018-10-12 00:50:47 -04:00
}
2018-11-01 13:23:12 -04:00
pthread_mutex_unlock(&list_lock);
2018-11-23 14:32:33 -05:00
if (!hide)
2018-10-12 00:50:47 -04:00
continue;
2018-11-23 14:32:33 -05:00
while (read_ns(pid, &ns) == 0 && ns.st_dev == pns.st_dev && ns.st_ino == pns.st_ino)
usleep(500);
2018-10-12 00:50:47 -04:00
// Send pause signal ASAP
if (kill(pid, SIGSTOP) == -1)
continue;
/*
* The setns system call do not support multithread processes
* We have to fork a new process, setns, then do the unmounts
*/
LOGI("proc_monitor: %s PID=[%d] ns=[%llu]\n", cpnt, pid, ns.st_ino);
2018-10-12 00:50:47 -04:00
if (fork_dont_care() == 0)
hide_daemon(pid);
2017-06-03 04:31:01 +08:00
}
pthread_exit(nullptr);
}