mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 20:37:39 +00:00
MagiskHide refactor
This commit is contained in:
parent
cccb5a3e08
commit
504a9b4746
@ -25,7 +25,6 @@ LOCAL_SRC_FILES := \
|
||||
daemon/log_monitor.c \
|
||||
daemon/bootstages.c \
|
||||
magiskhide/magiskhide.c \
|
||||
magiskhide/hide_daemon.c \
|
||||
magiskhide/proc_monitor.c \
|
||||
magiskhide/hide_utils.c \
|
||||
magiskpolicy/magiskpolicy.c \
|
||||
|
@ -1,129 +0,0 @@
|
||||
/* hide_daemon.c - MagiskHide daemon
|
||||
*
|
||||
* A dedicated process to join the target namespace,
|
||||
* and hide all traces in that particular namespace
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <fcntl.h>
|
||||
#include <signal.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "magiskhide.h"
|
||||
|
||||
static int pid;
|
||||
|
||||
static void lazy_unmount(const char* mountpoint) {
|
||||
if (umount2(mountpoint, MNT_DETACH) != -1)
|
||||
LOGI("hide_daemon: Unmounted (%s)\n", mountpoint);
|
||||
else
|
||||
LOGI("hide_daemon: Unmount Failed (%s)\n", mountpoint);
|
||||
}
|
||||
|
||||
static void hide_daemon_err() {
|
||||
LOGD("hide_daemon: error occured, stopping magiskhide services\n");
|
||||
// Resume process if possible
|
||||
kill(pid, SIGCONT);
|
||||
int err = 1;
|
||||
write(sv[1], &err, sizeof(err));
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
int hide_daemon() {
|
||||
// Fork to a new process
|
||||
hide_pid = fork();
|
||||
switch(hide_pid) {
|
||||
case -1:
|
||||
PLOGE("fork");
|
||||
return 1;
|
||||
case 0:
|
||||
break;
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
||||
close(sv[0]);
|
||||
|
||||
// Set the process name
|
||||
strcpy(argv0, "magiskhide_daemon");
|
||||
LOGD("hide_daemon: listening for hide requests");
|
||||
// When an error occurs, report its failure to main process
|
||||
err_handler = hide_daemon_err;
|
||||
|
||||
char buffer[4096], cache_block[256], *line;
|
||||
struct vector mount_list;
|
||||
|
||||
cache_block[0] = '\0';
|
||||
|
||||
while(1) {
|
||||
xxread(sv[1], &pid, sizeof(pid));
|
||||
// Termination called
|
||||
if(pid == -1) {
|
||||
LOGD("hide_daemon: received termination request\n");
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
manage_selinux();
|
||||
relink_sbin();
|
||||
|
||||
if (switch_mnt_ns(pid))
|
||||
continue;
|
||||
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
||||
vec_init(&mount_list);
|
||||
file_to_vector(buffer, &mount_list);
|
||||
|
||||
// Find the cache block name if not found yet
|
||||
if (strlen(cache_block) == 0) {
|
||||
vec_for_each(&mount_list, line) {
|
||||
if (strstr(line, " /cache ")) {
|
||||
sscanf(line, "%256s", cache_block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First unmount dummy skeletons, /sbin links, cache mounts, and mirrors
|
||||
vec_for_each(&mount_list, line) {
|
||||
if (strstr(line, "tmpfs /system") || strstr(line, "tmpfs /vendor") || strstr(line, "tmpfs /sbin")
|
||||
|| (strstr(line, cache_block) && (strstr(line, " /system") || strstr(line, " /vendor")))
|
||||
|| strstr(line, MIRRDIR)) {
|
||||
sscanf(line, "%*s %512s", buffer);
|
||||
lazy_unmount(buffer);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
vec_destroy(&mount_list);
|
||||
|
||||
// Re-read mount infos
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
||||
vec_init(&mount_list);
|
||||
file_to_vector(buffer, &mount_list);
|
||||
|
||||
// Unmount any loop mounts and dummy mounts
|
||||
vec_for_each(&mount_list, line) {
|
||||
if (strstr(line, "/dev/block/loop") || strstr(line, DUMMDIR)) {
|
||||
sscanf(line, "%*s %512s", buffer);
|
||||
lazy_unmount(buffer);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
vec_destroy(&mount_list);
|
||||
|
||||
// All done, send resume signal
|
||||
kill(pid, SIGCONT);
|
||||
|
||||
// Tell main process all is well
|
||||
pid = 0;
|
||||
xwrite(sv[1], &pid, sizeof(pid));
|
||||
}
|
||||
|
||||
// Should never go here
|
||||
}
|
@ -44,7 +44,7 @@ void manage_selinux() {
|
||||
}
|
||||
|
||||
void hide_sensitive_props() {
|
||||
LOGI("hide_pre_proc: Hiding sensitive props\n");
|
||||
LOGI("hide_utils: Hiding sensitive props\n");
|
||||
|
||||
// Hide all sensitive props
|
||||
char *value;
|
||||
@ -66,7 +66,7 @@ void relink_sbin() {
|
||||
struct dirent *entry;
|
||||
char from[PATH_MAX], to[PATH_MAX];
|
||||
|
||||
LOGI("hide_pre_proc: Re-linking /sbin\n");
|
||||
LOGI("hide_utils: Re-linking /sbin\n");
|
||||
|
||||
xmount(NULL, "/", NULL, MS_REMOUNT, NULL);
|
||||
xrename("/sbin", "/sbin_orig");
|
||||
|
@ -6,13 +6,10 @@
|
||||
// Kill process
|
||||
void kill_proc(int pid);
|
||||
|
||||
// Hide daemon
|
||||
int hide_daemon();
|
||||
|
||||
// Process monitor
|
||||
void proc_monitor();
|
||||
|
||||
// Preprocess
|
||||
// Utility functions
|
||||
void manage_selinux();
|
||||
void hide_sensitive_props();
|
||||
void relink_sbin();
|
||||
@ -23,7 +20,7 @@ int rm_list(char *proc);
|
||||
int init_list();
|
||||
int destroy_list();
|
||||
|
||||
extern int sv[2], hide_pid, hideEnabled;
|
||||
extern int hideEnabled;
|
||||
extern struct vector *hide_list;
|
||||
extern pthread_mutex_t hide_lock, file_lock;
|
||||
|
||||
|
@ -1,7 +1,8 @@
|
||||
/* proc_monitor.c - Monitor am_proc_start events
|
||||
/* proc_monitor.c - Monitor am_proc_start events and unmount
|
||||
*
|
||||
* We monitor the logcat am_proc_start events, pause it,
|
||||
* and send the target PID to hide daemon ASAP
|
||||
* 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
|
||||
*/
|
||||
|
||||
#include <stdlib.h>
|
||||
@ -12,18 +13,17 @@
|
||||
#include <pthread.h>
|
||||
#include <sys/types.h>
|
||||
#include <sys/wait.h>
|
||||
#include <sys/mount.h>
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "magiskhide.h"
|
||||
|
||||
static int zygote_num;
|
||||
static char init_ns[32], zygote_ns[2][32];
|
||||
static int log_pid, log_fd;
|
||||
static char init_ns[32], zygote_ns[2][32], cache_block[256];
|
||||
static int log_pid, log_fd, target_pid;
|
||||
static char *buffer;
|
||||
|
||||
int sv[2], hide_pid = -1;
|
||||
|
||||
// Workaround for the lack of pthread_cancel
|
||||
static void quit_pthread(int sig) {
|
||||
err_handler = do_nothing;
|
||||
@ -32,17 +32,14 @@ static void quit_pthread(int sig) {
|
||||
free(buffer);
|
||||
hideEnabled = 0;
|
||||
// Kill the logging if needed
|
||||
if (log_pid) {
|
||||
if (log_pid > 0) {
|
||||
kill(log_pid, SIGTERM);
|
||||
waitpid(log_pid, NULL, 0);
|
||||
close(log_fd);
|
||||
log_fd = log_pid = 0;
|
||||
}
|
||||
int kill = -1;
|
||||
// If process monitor dies, kill hide daemon too
|
||||
write(sv[0], &kill, sizeof(kill));
|
||||
close(sv[0]);
|
||||
waitpid(hide_pid, NULL, 0);
|
||||
// Resume process if possible
|
||||
if (target_pid > 0)
|
||||
kill(target_pid, SIGCONT);
|
||||
pthread_mutex_destroy(&hide_lock);
|
||||
pthread_mutex_destroy(&file_lock);
|
||||
LOGD("proc_monitor: terminating...\n");
|
||||
@ -54,15 +51,13 @@ static void proc_monitor_err() {
|
||||
quit_pthread(SIGUSR1);
|
||||
}
|
||||
|
||||
static void read_namespace(const int pid, char* target, const size_t size) {
|
||||
static int read_namespace(const int pid, char* target, const size_t size) {
|
||||
char path[32];
|
||||
snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid);
|
||||
if (access(path, R_OK) == -1) {
|
||||
LOGE("proc_monitor: Your kernel doesn't support mount namespace :(\n");
|
||||
proc_monitor_err();
|
||||
return;
|
||||
}
|
||||
if (access(path, R_OK) == -1)
|
||||
return 1;
|
||||
xreadlink(path, target, size);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void store_zygote_ns(int pid) {
|
||||
@ -74,6 +69,76 @@ static void store_zygote_ns(int pid) {
|
||||
++zygote_num;
|
||||
}
|
||||
|
||||
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() {
|
||||
LOGD("hide_daemon: error occured, stopping magiskhide services\n");
|
||||
_exit(-1);
|
||||
}
|
||||
|
||||
static void hide_daemon(int pid) {
|
||||
LOGD("hide_daemon: start unmount for pid=[%d]\n", pid);
|
||||
// When an error occurs, report its failure to main process
|
||||
err_handler = hide_daemon_err;
|
||||
|
||||
char *line;
|
||||
struct vector mount_list;
|
||||
|
||||
manage_selinux();
|
||||
relink_sbin();
|
||||
|
||||
if (switch_mnt_ns(pid))
|
||||
return;
|
||||
|
||||
snprintf(buffer, PATH_MAX, "/proc/%d/mounts", pid);
|
||||
vec_init(&mount_list);
|
||||
file_to_vector(buffer, &mount_list);
|
||||
|
||||
// Find the cache block name if not found yet
|
||||
if (cache_block[0] == '\0') {
|
||||
vec_for_each(&mount_list, line) {
|
||||
if (strstr(line, " /cache ")) {
|
||||
sscanf(line, "%256s", cache_block);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// First unmount dummy skeletons, /sbin links, cache mounts, and mirrors
|
||||
vec_for_each(&mount_list, line) {
|
||||
if (strstr(line, "tmpfs /system") || strstr(line, "tmpfs /vendor") || strstr(line, "tmpfs /sbin")
|
||||
|| (strstr(line, cache_block) && (strstr(line, " /system") || strstr(line, " /vendor")))
|
||||
|| strstr(line, MIRRDIR)) {
|
||||
sscanf(line, "%*s %4096s", buffer);
|
||||
lazy_unmount(buffer);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
vec_destroy(&mount_list);
|
||||
|
||||
// Re-read mount infos
|
||||
snprintf(buffer, PATH_MAX, "/proc/%d/mounts", pid);
|
||||
vec_init(&mount_list);
|
||||
file_to_vector(buffer, &mount_list);
|
||||
|
||||
// Unmount any loop mounts and dummy mounts
|
||||
vec_for_each(&mount_list, line) {
|
||||
if (strstr(line, "/dev/block/loop") || strstr(line, DUMMDIR)) {
|
||||
sscanf(line, "%*s %4096s", buffer);
|
||||
lazy_unmount(buffer);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
|
||||
// Free uo memory
|
||||
vec_destroy(&mount_list);
|
||||
}
|
||||
|
||||
void proc_monitor() {
|
||||
// Register the cancel signal
|
||||
struct sigaction act;
|
||||
@ -83,12 +148,16 @@ void proc_monitor() {
|
||||
|
||||
// The error handler should stop magiskhide services
|
||||
err_handler = proc_monitor_err;
|
||||
log_pid = target_pid = -1;
|
||||
|
||||
int pid;
|
||||
buffer = xmalloc(PATH_MAX);
|
||||
cache_block[0] = '\0';
|
||||
|
||||
// Get the mount namespace of init
|
||||
read_namespace(1, init_ns, 32);
|
||||
if (read_namespace(1, init_ns, 32)) {
|
||||
LOGE("proc_monitor: Your kernel doesn't support mount namespace :(\n");
|
||||
proc_monitor_err();
|
||||
}
|
||||
LOGI("proc_monitor: init ns=%s\n", init_ns);
|
||||
|
||||
// Get the mount namespace of zygote
|
||||
@ -109,20 +178,8 @@ void proc_monitor() {
|
||||
break;
|
||||
}
|
||||
|
||||
if (socketpair(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0, sv) == -1)
|
||||
quit_pthread(SIGUSR1);
|
||||
|
||||
/*
|
||||
* The setns system call do not support multithread processes
|
||||
* We have to fork a new process, and communicate with sockets
|
||||
*/
|
||||
if (hide_daemon())
|
||||
quit_pthread(SIGUSR1);
|
||||
|
||||
close(sv[1]);
|
||||
|
||||
while (1) {
|
||||
// Clear previous buffer
|
||||
// Clear previous logcat buffer
|
||||
system("logcat -b events -c");
|
||||
|
||||
// Monitor am_proc_start
|
||||
@ -134,7 +191,7 @@ void proc_monitor() {
|
||||
if (kill(log_pid, 0)) continue;
|
||||
|
||||
while(fdgets(buffer, PATH_MAX, log_fd)) {
|
||||
int ret, comma = 0;
|
||||
int pid, ret, comma = 0;
|
||||
char *pos = buffer, *line, processName[256];
|
||||
|
||||
while(1) {
|
||||
@ -159,10 +216,11 @@ void proc_monitor() {
|
||||
pthread_mutex_lock(&hide_lock);
|
||||
vec_for_each(hide_list, line) {
|
||||
if (strcmp(processName, line) == 0) {
|
||||
target_pid = pid;
|
||||
while(1) {
|
||||
ret = 1;
|
||||
for (int i = 0; i < zygote_num; ++i) {
|
||||
read_namespace(pid, buffer, 32);
|
||||
read_namespace(target_pid, buffer, 32);
|
||||
if (strcmp(buffer, zygote_ns[i]) == 0) {
|
||||
usleep(50);
|
||||
ret = 0;
|
||||
@ -172,29 +230,39 @@ void proc_monitor() {
|
||||
if (ret) break;
|
||||
}
|
||||
|
||||
ret = 0;
|
||||
|
||||
// Send pause signal ASAP
|
||||
if (kill(pid, SIGSTOP) == -1) continue;
|
||||
if (kill(target_pid, SIGSTOP) == -1) continue;
|
||||
|
||||
LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, pid, buffer);
|
||||
LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, target_pid, buffer);
|
||||
|
||||
// Unmount start
|
||||
xwrite(sv[0], &pid, sizeof(pid));
|
||||
/*
|
||||
* The setns system call do not support multithread processes
|
||||
* We have to fork a new process, setns, then do the unmounts
|
||||
*/
|
||||
int hide_pid = fork();
|
||||
switch(hide_pid) {
|
||||
case -1:
|
||||
PLOGE("fork");
|
||||
return;
|
||||
case 0:
|
||||
hide_daemon(target_pid);
|
||||
_exit(0);
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
// Get the hide daemon return code
|
||||
xxread(sv[0], &ret, sizeof(ret));
|
||||
LOGD("proc_monitor: hide daemon response code: %d\n", ret);
|
||||
// Wait till the unmount process is done
|
||||
waitpid(hide_pid, &ret, 0);
|
||||
if (WEXITSTATUS(ret))
|
||||
quit_pthread(SIGUSR1);
|
||||
|
||||
// All done, send resume signal
|
||||
kill(target_pid, SIGCONT);
|
||||
target_pid = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&hide_lock);
|
||||
|
||||
if (ret) {
|
||||
// Wait hide process to kill itself
|
||||
waitpid(hide_pid, NULL, 0);
|
||||
quit_pthread(SIGUSR1);
|
||||
}
|
||||
}
|
||||
|
||||
// For some reason it went here, restart logging
|
||||
|
Loading…
x
Reference in New Issue
Block a user