From 8f6b33d7900df96a2aef6b34cc6d9d6e90d24fbd Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Thu, 6 Apr 2017 06:12:29 +0800 Subject: [PATCH] Rewrite magiskhide --- jni/Android.mk | 7 +- jni/magisk.h | 23 ++++- jni/magiskhide/Android.mk | 7 -- jni/magiskhide/hide.c | 78 ----------------- jni/magiskhide/hide_daemon.c | 129 ++++++++++++++++++++++++++++ jni/magiskhide/list_monitor.c | 56 ------------ jni/magiskhide/magiskhide.c | 116 +++++++++++-------------- jni/magiskhide/magiskhide.h | 49 ++--------- jni/magiskhide/proc_monitor.c | 155 ++++++++++++++++++++-------------- jni/magiskhide/util.c | 80 ------------------ jni/main.c | 39 +++++---- jni/utils/log_monitor.c | 5 +- jni/utils/misc.c | 36 ++++++++ jni/utils/utils.h | 11 +++ jni/utils/vector.c | 21 ++++- jni/utils/vector.h | 5 ++ jni/utils/xwrap.c | 57 ++++++++++++- 17 files changed, 447 insertions(+), 427 deletions(-) delete mode 100644 jni/magiskhide/Android.mk delete mode 100644 jni/magiskhide/hide.c create mode 100644 jni/magiskhide/hide_daemon.c delete mode 100644 jni/magiskhide/list_monitor.c delete mode 100644 jni/magiskhide/util.c create mode 100644 jni/utils/misc.c diff --git a/jni/Android.mk b/jni/Android.mk index ab392d9af..7478643cd 100644 --- a/jni/Android.mk +++ b/jni/Android.mk @@ -13,14 +13,13 @@ LOCAL_C_INCLUDES := \ LOCAL_SRC_FILES := \ main.c \ - utils/log_monitor.c \ + utils/misc.c \ utils/vector.c \ utils/xwrap.c \ + utils/log_monitor.c \ magiskhide/magiskhide.c \ - magiskhide/hide.c \ - magiskhide/list_monitor.c \ + magiskhide/hide_daemon.c \ magiskhide/proc_monitor.c \ - magiskhide/util.c \ magiskpolicy/magiskpolicy.c \ magiskpolicy/rules.c \ magiskpolicy/sepolicy.c \ diff --git a/jni/magisk.h b/jni/magisk.h index 240e093b0..a437dd8e1 100644 --- a/jni/magisk.h +++ b/jni/magisk.h @@ -1,3 +1,9 @@ +/* magisk.h - Top header + * + * Contain global functions like logging, + * and entrypoint for main + */ + #ifndef _MAGISK_H_ #define _MAGISK_H_ @@ -12,16 +18,19 @@ #else #define LOGD(...) stub(__VA_ARGS__) #endif +#define LOGI(...) __android_log_print(ANDROID_LOG_INFO, LOG_TAG, __VA_ARGS__) #define LOGW(...) __android_log_print(ANDROID_LOG_WARN, LOG_TAG, __VA_ARGS__) #define LOGE(...) __android_log_print(ANDROID_LOG_ERROR, LOG_TAG, __VA_ARGS__) -#define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno)) -#define PLOGEV(fmt, err, args...) LOGE(fmt " failed with %d: %s", ##args, err, strerror(err)) + +#define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno)); exit(1) +#define PLOGEV(fmt, err, args...) LOGE(fmt " failed with %d: %s", ##args, err, strerror(err)); exit(1) void stub(const char *fmt, ...); -// Global buffer +// Global buffer (only for main thread!!) #define BUF_SIZE 4096 extern char magiskbuf[BUF_SIZE]; +extern char *argv0; /* For changing process name */ // Multi-call entrypoints int magiskhide_main(int argc, char *argv[]); @@ -36,4 +45,12 @@ int resetprop_main(int argc, char *argv[]); } #endif +/************** + * MagiskHide * + **************/ + +void launch_magiskhide(); +void stop_magiskhide(); + + #endif diff --git a/jni/magiskhide/Android.mk b/jni/magiskhide/Android.mk deleted file mode 100644 index 10a76bb57..000000000 --- a/jni/magiskhide/Android.mk +++ /dev/null @@ -1,7 +0,0 @@ -LOCAL_PATH := $(call my-dir) - -include $(CLEAR_VARS) -LOCAL_MODULE := magiskhide -LOCAL_SRC_FILES := magiskhide.c hide.c list_monitor.c proc_monitor.c util.c -LOCAL_CFLAGS := -DINDEP_BINARY -include $(BUILD_EXECUTABLE) \ No newline at end of file diff --git a/jni/magiskhide/hide.c b/jni/magiskhide/hide.c deleted file mode 100644 index 22685b857..000000000 --- a/jni/magiskhide/hide.c +++ /dev/null @@ -1,78 +0,0 @@ -#include "magiskhide.h" - -int hideMagisk() { - close(pipefd[1]); - - int pid, fd; - char cache_block[256]; - cache_block[0] = '\0'; - - while(1) { - read(pipefd[0], &pid, sizeof(pid)); - // Termination called - if(pid == -1) break; - - manage_selinux(); - - snprintf(buffer, sizeof(buffer), "/proc/%d/ns/mnt", pid); - if((fd = open(buffer, O_RDONLY)) == -1) continue; // Maybe process died.. - if(setns(fd, 0) == -1) { - fprintf(logfile, "MagiskHide: Unable to change namespace for pid=%d\n", pid); - continue; - } - close(fd); - - snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid); - FILE *mount_fp = fopen(buffer, "r"); - if (mount_fp == NULL) { - fprintf(logfile, "MagiskHide: Error opening mount list!\n"); - continue; - } - - int mount_size; - char **mount_list = file_to_str_arr(mount_fp, &mount_size); - - // Find the cache block name if not found yet - if (strlen(cache_block) == 0) { - for(i = 0; i < mount_size; ++i) { - if (strstr(mount_list[i], " /cache ")) { - sscanf(mount_list[i], "%256s", cache_block); - break; - } - } - } - - // First unmount the dummy skeletons, cache mounts, and /sbin links - for(i = mount_size - 1; i >= 0; --i) { - if (strstr(mount_list[i], "tmpfs /system") || strstr(mount_list[i], "tmpfs /vendor") - || strstr(mount_list[i], "tmpfs /sbin") - || (strstr(mount_list[i], cache_block) && strstr(mount_list[i], "/system/")) ) { - sscanf(mount_list[i], "%*s %512s", buffer); - lazy_unmount(buffer); - } - free(mount_list[i]); - } - free(mount_list); - - // Re-read mount infos - fseek(mount_fp, 0, SEEK_SET); - mount_list = file_to_str_arr(mount_fp, &mount_size); - fclose(mount_fp); - - // Unmount loop mounts - for(i = mount_size - 1; i >= 0; --i) { - if (strstr(mount_list[i], "/dev/block/loop") && !strstr(mount_list[i], DUMMYPATH)) { - sscanf(mount_list[i], "%*s %512s", buffer); - lazy_unmount(buffer); - } - free(mount_list[i]); - } - free(mount_list); - - // Send resume signal - kill(pid, SIGCONT); - } - - // Should never go here - return 1; -} diff --git a/jni/magiskhide/hide_daemon.c b/jni/magiskhide/hide_daemon.c new file mode 100644 index 000000000..6283e4ce9 --- /dev/null +++ b/jni/magiskhide/hide_daemon.c @@ -0,0 +1,129 @@ +/* hide_daemon.c - MagiskHide daemon + * + * A dedicated process to join the target namespace, + * and hide all traces in that particular namespace + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "magisk.h" +#include "utils.h" +#include "magiskhide.h" + +static int isMocked = 0; + +static void manage_selinux() { + if (isMocked) return; + char val[1]; + int fd = xopen(ENFORCE_FILE, O_RDONLY); + xxread(fd, val, 1); + close(fd); + // Permissive + if (val[0] == '0') { + LOGI("hide_daemon: Permissive detected, hide the state\n"); + + chmod(ENFORCE_FILE, 0640); + chmod(POLICY_FILE, 0440); + isMocked = 1; + } +} + +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); +} + +void hide_daemon() { + // Fork to a new process + switch(fork()) { + case -1: + PLOGE("fork"); + case 0: + break; + default: + return; + } + + close(pipefd[1]); + strcpy(argv0, "magiskhide_daemon"); + + int pid, fd; + FILE *fp; + char cache_block[256], *line; + struct vector mount_list; + + cache_block[0] = '\0'; + + while(1) { + xxread(pipefd[0], &pid, sizeof(pid)); + // Termination called + if(pid == -1) exit(0); + + snprintf(magiskbuf, BUF_SIZE, "/proc/%d/ns/mnt", pid); + if(access(magiskbuf, F_OK) == -1) continue; // Maybe process died.. + + fd = xopen(magiskbuf, O_RDONLY); + // Switch to its namespace + xsetns(fd, 0); + close(fd); + + manage_selinux(); + + snprintf(magiskbuf, BUF_SIZE, "/proc/%d/mounts", pid); + fp = xfopen(magiskbuf, "r"); + vec_init(&mount_list); + file_to_vector(&mount_list, fp); + + // 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 the dummy skeletons, cache mounts, and /sbin links + vec_for_each_r(&mount_list, line) { + if (strstr(line, "tmpfs /system") || strstr(line, "tmpfs /vendor") || strstr(line, "tmpfs /sbin") + || (strstr(line, cache_block) && strstr(line, "/system/")) ) { + sscanf(line, "%*s %512s", magiskbuf); + lazy_unmount(magiskbuf); + } + free(line); + } + vec_destroy(&mount_list); + + // Re-read mount infos + fseek(fp, 0, SEEK_SET); + vec_init(&mount_list); + file_to_vector(&mount_list, fp); + fclose(fp); + + // Unmount loop mounts + vec_for_each_r(&mount_list, line) { + if (strstr(line, "/dev/block/loop") && !strstr(line, DUMMYPATH)) { + sscanf(line, "%*s %512s", magiskbuf); + lazy_unmount(magiskbuf); + } + free(line); + } + vec_destroy(&mount_list); + + // All done, send resume signal + kill(pid, SIGCONT); + } + + // Should never go here +} diff --git a/jni/magiskhide/list_monitor.c b/jni/magiskhide/list_monitor.c deleted file mode 100644 index 1440f770d..000000000 --- a/jni/magiskhide/list_monitor.c +++ /dev/null @@ -1,56 +0,0 @@ -#include "magiskhide.h" - -void *monitor_list(void *path) { - char* listpath = (char*) path; - signal(SIGQUIT, quit_pthread); - - int inotifyFd = -1; - char str[512]; - - while(1) { - if (inotifyFd == -1 || read(inotifyFd, str, sizeof(str)) == -1) { - close(inotifyFd); - inotifyFd = inotify_init(); - if (inotifyFd == -1) { - fprintf(logfile, "MagiskHide: Unable to watch %s\n", listpath); - exit(1); - } - if (inotify_add_watch(inotifyFd, listpath, IN_CLOSE_WRITE) == -1) { - fprintf(logfile, "MagiskHide: Unable to watch %s\n", listpath); - exit(1); - } - } - update_list(listpath); - } - - return NULL; -} - -void update_list(const char *listpath) { - FILE *hide_fp = fopen(listpath, "r"); - if (hide_fp == NULL) { - fprintf(logfile, "MagiskHide: Error opening hide list\n"); - exit(1); - } - pthread_mutex_lock(&mutex); - if (hide_list) { - // Free memory - for(i = 0; i < list_size; ++i) - free(hide_list[i]); - free(hide_list); - } - hide_list = file_to_str_arr(hide_fp, &list_size); - pthread_mutex_unlock(&mutex); - fclose(hide_fp); - if (list_size) fprintf(logfile, "MagiskHide: Update process/package list:\n"); - for(i = 0; i < list_size; i++) - fprintf(logfile, "MagiskHide: [%s]\n", hide_list[i]); -} - -void quit_pthread(int sig) { - // Free memory - for(i = 0; i < list_size; ++i) - free(hide_list[i]); - free(hide_list); - pthread_exit(NULL); -} diff --git a/jni/magiskhide/magiskhide.c b/jni/magiskhide/magiskhide.c index e8db18c99..e79136171 100644 --- a/jni/magiskhide/magiskhide.c +++ b/jni/magiskhide/magiskhide.c @@ -1,74 +1,56 @@ +/* magiskhide.c - initialize the environment for Magiskhide + */ + +// TODO: Functions to modify hiding list + +#include +#include +#include +#include + +#include "magisk.h" +#include "utils.h" #include "magiskhide.h" -#ifdef INDEP_BINARY -int magiskhide_main(int argc, char *argv[]); -int main(int argc, char *argv[]) { - return magiskhide_main(argc, argv); +int pipefd[2]; +struct vector *hide_list, *new_list; + +static pthread_t proc_monitor_thread; + +void launch_magiskhide() { + /* + * The setns system call do not support multithread processes + * We have to fork a new process, and communicate with pipe + */ + + xpipe(pipefd); + + // Launch the hide daemon + hide_daemon(); + + close(pipefd[0]); + + // Initialize the hide list + hide_list = new_list = malloc(sizeof(*hide_list)); + vec_init(hide_list); + FILE *fp = xfopen(HIDELIST, "r"); + file_to_vector(hide_list, fp); + fclose(fp); + + // Start a new thread to monitor processes + pthread_create(&proc_monitor_thread, NULL, proc_monitor, NULL); } -#else -#include "magisk.h" -#endif -FILE *logfile; -int i, list_size, pipefd[2]; -char **hide_list = NULL, buffer[512]; -pthread_t list_monitor; -pthread_mutex_t mutex; - -static void terminate(int sig) { - // Close the config list monitor - pthread_kill(list_monitor, SIGQUIT); - pthread_mutex_destroy(&mutex); - - // Terminate our children - i = -1; - write(pipefd[1], &i, sizeof(i)); - exit(0); +void stop_magiskhide() { + int kill = -1; + // Terminate hide daemon + xwrite(pipefd[1], &kill, sizeof(kill)); + // Stop process monitor + pthread_kill(proc_monitor_thread, SIGUSR1); + pthread_join(proc_monitor_thread, NULL); } int magiskhide_main(int argc, char *argv[]) { - - if (argc > 1) { - if (strcmp(argv[1], "--daemon") == 0) - run_as_daemon(); - else { - fprintf(stderr, "%s (with no options)\n\tRun magiskhide and output to stdout\n", argv[0]); - fprintf(stderr, "%s --daemon\n\tRun magiskhide as daemon, output to magisk.log\n", argv[0]); - return 1; - } - } else - logfile = stdout; - - - // Handle all killing signals - signal(SIGINT, terminate); - signal(SIGTERM, terminate); - - // Fork a child to handle namespace switches and unmounts - pipe(pipefd); - switch(fork()) { - case -1: - exit(-1); - case 0: - return hideMagisk(); - default: - break; - } - close(pipefd[0]); - - // Start a thread to constantly check the hide list - pthread_mutex_init(&mutex, NULL); - pthread_create(&list_monitor, NULL, monitor_list, HIDELIST); - - // Set main process to the top priority - setpriority(PRIO_PROCESS, 0, -20); - - monitor_proc(); - - terminate(0); - - fprintf(logfile, "MagiskHide: Cannot monitor am_proc_start, abort...\n"); - fclose(logfile); - - return 1; -} \ No newline at end of file + launch_magiskhide(); + return 0; +} diff --git a/jni/magiskhide/magiskhide.h b/jni/magiskhide/magiskhide.h index 3ea477eea..434108c0c 100644 --- a/jni/magiskhide/magiskhide.h +++ b/jni/magiskhide/magiskhide.h @@ -1,53 +1,18 @@ #ifndef MAGISK_HIDE_H #define MAGISK_HIDE_H -#define _GNU_SOURCE -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include -#include -#include - -#define LOGFILE "/cache/magisk.log" -#define HIDELIST "/magisk/.core/magiskhide/hidelist" +#define HIDELIST "/magisk/.core/magiskhide/hidelist" #define DUMMYPATH "/dev/magisk/dummy" #define ENFORCE_FILE "/sys/fs/selinux/enforce" #define POLICY_FILE "/sys/fs/selinux/policy" -#define SEPOLICY_INJECT "/data/magisk/magiskpolicy" -// Main thread -void monitor_proc(); +// Hide daemon +void hide_daemon(); -// Forked process for namespace setting -int hideMagisk(); +// Process monitor +void *proc_monitor(void *args); -// List monitor thread -void update_list(const char *listpath); -void quit_pthread(int sig); -void *monitor_list(void *path); - -// Util functions -char **file_to_str_arr(FILE *fp, int *size); -void read_namespace(const int pid, char* target, const size_t size); -void lazy_unmount(const char* mountpoint); -void run_as_daemon(); -void manage_selinux(); - -// Global variable sharing through process/threads -extern FILE *logfile; -extern int i, list_size, pipefd[2]; -extern char **hide_list, buffer[512]; -extern pthread_t list_monitor; -extern pthread_mutex_t mutex; +extern int pipefd[2]; +extern struct vector *hide_list, *new_list; #endif diff --git a/jni/magiskhide/proc_monitor.c b/jni/magiskhide/proc_monitor.c index 609a9f0cd..0ad50ccfe 100644 --- a/jni/magiskhide/proc_monitor.c +++ b/jni/magiskhide/proc_monitor.c @@ -1,106 +1,133 @@ +/* proc_monitor.c - Monitor am_proc_start events + * + * We monitor the logcat am_proc_start events, pause it, + * and send the target PID to hide daemon ASAP + */ + +#include +#include +#include +#include +#include +#include +#include + +#include "magisk.h" +#include "utils.h" #include "magiskhide.h" -void monitor_proc() { - int pid, badns, i, zygote_num = 0; - char init_ns[32], zygote_ns[2][32]; +/* WTF... the macro in the NDK pthread.h is broken.... */ +#define pthread_cleanup_push_fix(routine, arg) \ +pthread_cleanup_push(routine, arg) } while(0); + +static void read_namespace(const int pid, char* target, const size_t size) { + char path[32]; + snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid); + ssize_t len = readlink(path, target, size); + target[len] = '\0'; +} + +// Workaround for the lack of pthread_cancel +static void quit_pthread(int sig) { + pthread_exit(NULL); +} + +static void cleanup_handler(void *arg) { + vec_deep_destroy(hide_list); + vec_deep_destroy(new_list); + free(hide_list); + free(new_list); + hide_list = new_list = NULL; +} + +void *proc_monitor(void *args) { + // Register the cancel signal + signal(SIGUSR1, quit_pthread); + pthread_cleanup_push_fix(cleanup_handler, NULL); + + int pid, zygote_num = 0; + char init_ns[32], zygote_ns[2][32], buffer[512]; + FILE *p; // Get the mount namespace of init read_namespace(1, init_ns, 32); - - printf("%s\n", init_ns); + LOGI("proc_monitor: init ns=%s\n", init_ns); // Get the mount namespace of zygote - FILE *p = popen("ps | grep zygote | grep -v grep", "r"); + // TODO: Crawl through /proc to get process names + + switch(zygote_num) { + case 1: + LOGI("proc_monitor: zygote ns=%s\n", zygote_ns[0]); + break; + case 2: + LOGI("proc_monitor: zygote (1) ns=%s (2) ns=%s\n", zygote_ns[0], zygote_ns[1]); + break; + } + + // Monitor am_proc_start (the command shall never end) + p = popen("while true; do logcat -b events -c; logcat -b events -v raw -s am_proc_start; sleep 1; done", "r"); + while(fgets(buffer, sizeof(buffer), p)) { - if (zygote_num == 2) break; - sscanf(buffer, "%d", &pid); - do { - usleep(500); - read_namespace(pid, zygote_ns[zygote_num], 32); - } while (strcmp(zygote_ns[zygote_num], init_ns) == 0); - ++zygote_num; - } - pclose(p); + int ret, comma = 0; + char *pos = buffer, *line, processName[256]; + struct vector *temp = NULL; - for (i = 0; i < zygote_num; ++i) - fprintf(logfile, "Zygote(%d) ns=%s ", i, zygote_ns[i]); - fprintf(logfile, "\n"); - - // get a sample line from am_proc_start - p = popen("logcat -b events -v raw -s am_proc_start -t 1", "r"); - - /** - * Format of am_proc_start is (as of Android 5.1 and 6.0) - * UserID, pid, unix uid, processName, hostingType, hostingName - * but sometimes can have 7 fields, with processName as 5th field - */ - fgets(buffer, sizeof(buffer), p); - int commas = 0; - char *s = buffer; - for (i = 0;s[i] != '\0';i++) { - if (s[i] == ',') - commas++; - - } - int numFields = commas + 1; - - pclose(p); - - // Monitor am_proc_start - p = popen("logcat -b events -c; logcat -b events -v raw -s am_proc_start", "r"); - - while(!feof(p)) { - fgets(buffer, sizeof(buffer), p); - - char *pos = buffer; while(1) { pos = strchr(pos, ','); if(pos == NULL) break; pos[0] = ' '; + ++comma; } - char processName[256]; - int ret; - - if (numFields == 7) { + if (comma == 6) ret = sscanf(buffer, "[%*d %d %*d %*d %256s", &pid, processName); - } else { + else ret = sscanf(buffer, "[%*d %d %*d %256s", &pid, processName); - } if(ret != 2) continue; - pthread_mutex_lock(&mutex); - for (i = 0; i < list_size; ++i) { - if(strcmp(processName, hide_list[i]) == 0) { + // Should be thread safe + if (hide_list != new_list) { + temp = hide_list; + hide_list = new_list; + } + + vec_for_each(hide_list, line) { + if (strcmp(processName, line) == 0) { + read_namespace(pid, buffer, 32); while(1) { - badns = 0; - read_namespace(pid, buffer, 32); - for (i = 0; i < zygote_num; ++i) { + ret = 1; + for (int i = 0; i < zygote_num; ++i) { if (strcmp(buffer, zygote_ns[i]) == 0) { usleep(500); - badns = 1; + ret = 0; break; } } - if (!badns) break; + if (ret) break; } // Send pause signal ASAP if (kill(pid, SIGSTOP) == -1) continue; - fprintf(logfile, "MagiskHide: %s(PID=%d ns=%s)\n", processName, pid, buffer); + LOGI("proc_monitor: %s(PID=%d ns=%s)\n", processName, pid, buffer); // Unmount start - write(pipefd[1], &pid, sizeof(pid)); + xwrite(pipefd[1], &pid, sizeof(pid)); break; } } - pthread_mutex_unlock(&mutex); + if (temp) { + vec_deep_destroy(temp); + free(temp); + } } - // Close the logcat monitor + // Should never be here pclose(p); + quit_pthread(SIGUSR1); + return NULL; } diff --git a/jni/magiskhide/util.c b/jni/magiskhide/util.c deleted file mode 100644 index 8c1572a6f..000000000 --- a/jni/magiskhide/util.c +++ /dev/null @@ -1,80 +0,0 @@ -#include "magiskhide.h" - -static int isMocked = 0; - -char **file_to_str_arr(FILE *fp, int *size) { - int allocated = 16; - char *line = NULL, **array; - size_t len = 0; - ssize_t read; - - array = (char **) malloc(sizeof(char*) * allocated); - - *size = 0; - while ((read = getline(&line, &len, fp)) != -1) { - if (*size >= allocated) { - // Double our allocation and re-allocate - allocated *= 2; - array = (char **) realloc(array, sizeof(char*) * allocated); - } - // Remove end newline - if (line[read - 1] == '\n') { - line[read - 1] = '\0'; - } - array[*size] = line; - line = NULL; - ++(*size); - } - return array; -} - -void read_namespace(const int pid, char* target, const size_t size) { - char path[32]; - snprintf(path, sizeof(path), "/proc/%d/ns/mnt", pid); - ssize_t len = readlink(path, target, size); - target[len] = '\0'; -} - -void lazy_unmount(const char* mountpoint) { - if (umount2(mountpoint, MNT_DETACH) != -1) - fprintf(logfile, "MagiskHide: Unmounted (%s)\n", mountpoint); - else - fprintf(logfile, "MagiskHide: Unmount Failed (%s)\n", mountpoint); -} - -void run_as_daemon() { - switch(fork()) { - case -1: - exit(-1); - case 0: - if (setsid() < 0) - exit(-1); - close(STDIN_FILENO); - close(STDOUT_FILENO); - close(STDERR_FILENO); - logfile = fopen(LOGFILE, "a+"); - setbuf(logfile, NULL); - break; - default: - exit(0); - } -} - -void manage_selinux() { - if (isMocked) return; - char val[1]; - int fd = open(ENFORCE_FILE, O_RDONLY); - if (fd < 0) - return; - if (read(fd, val, 1) < 1) - return; - close(fd); - // Permissive - if (val[0] == '0') { - fprintf(logfile, "MagiskHide: Permissive detected, hide the state\n"); - - chmod(ENFORCE_FILE, 0640); - chmod(POLICY_FILE, 0440); - isMocked = 1; - } -} diff --git a/jni/main.c b/jni/main.c index c9238498e..b882208aa 100644 --- a/jni/main.c +++ b/jni/main.c @@ -4,39 +4,44 @@ #include "utils.h" #include "magisk.h" -// Global buffer char magiskbuf[BUF_SIZE]; +char *argv0; void stub(const char *fmt, ...) {} int main(int argc, char *argv[]) { - char * argv0 = strrchr(argv[0], '/'); - if (argv0) argv[0] = argv0 + 1; - if (strcmp(argv[0], "magisk") == 0) { - if (strcmp(argv[1], "--daemon") == 0) { - // Start daemon + argv0 = argv[0]; + char * arg = strrchr(argv[0], '/'); + if (arg) ++arg; + if (strcmp(arg, "magisk") == 0) { + if (strcmp(argv[1], "--post-fs") == 0) { + // TODO: post-fs mode + return 0; + } else if (strcmp(argv[1], "--post-fs-data") == 0) { + // TODO: post-fs-data mode return 0; } else if (strcmp(argv[1], "--install") == 0) { - // Install symlinks + // TODO: Install symlinks return 0; } else { // It's calling applets --argc; ++argv; + arg = argv[0]; } } // Applets - if (strcmp(argv[0], "magiskhide") == 0) { - magiskhide_main(argc, argv); - } else if (strcmp(argv[0], "magiskpolicy") == 0) { - magiskpolicy_main(argc, argv); - } else if (strcmp(argv[0], "resetprop") == 0) { - resetprop_main(argc, argv); - } else if (strcmp(argv[0], "su") == 0) { - su_main(argc, argv); + if (strcmp(arg, "su") == 0) { + return su_main(argc, argv); + } else if (strcmp(arg, "magiskpolicy") == 0) { + return magiskpolicy_main(argc, argv); + } else if (strcmp(arg, "resetprop") == 0) { + return resetprop_main(argc, argv); + } else if (strcmp(arg, "magiskhide") == 0) { + return magiskhide_main(argc, argv); } else { - fprintf(stderr, "Applet \'%s\' not found\n", argv[0]); + fprintf(stderr, "Applet \'%s\' not found\n", arg); } - return 0; + return 1; } \ No newline at end of file diff --git a/jni/utils/log_monitor.c b/jni/utils/log_monitor.c index bc280722c..8c09ddd51 100644 --- a/jni/utils/log_monitor.c +++ b/jni/utils/log_monitor.c @@ -8,6 +8,7 @@ #include #include +#include "magisk.h" #include "utils.h" static void *logger_thread(void *args) { @@ -23,10 +24,8 @@ static void *logger_thread(void *args) { return NULL; } -/* Start a new thread to monitor logcat and dump to file */ +/* Start a new thread to monitor logcat and dump to logfile */ void monitor_logs() { pthread_t log_monitor; pthread_create(&log_monitor, NULL, logger_thread, NULL); - printf("Hello :)\n"); - pthread_join(log_monitor, NULL); } \ No newline at end of file diff --git a/jni/utils/misc.c b/jni/utils/misc.c new file mode 100644 index 000000000..cd92e84c0 --- /dev/null +++ b/jni/utils/misc.c @@ -0,0 +1,36 @@ +/* misc.c - Store all functions that are unable to be catagorized clearly + */ + +#include +#include +#include + +#include "utils.h" + +int check_data() { + FILE *fp = xfopen("/proc/mounts", "r"); + while (fgets(magiskbuf, BUF_SIZE, fp)) { + if (strstr(magiskbuf, " /data ")) { + if (strstr(magiskbuf, "tmpfs")) + return 0; + else + return 1; + } + } + return 0; +} + +/* All the string should be freed manually!! */ +void file_to_vector(struct vector *v, FILE *fp) { + char *line = NULL; + size_t len = 0; + ssize_t read; + + while ((read = getline(&line, &len, fp)) != -1) { + // Remove end newline + if (line[read - 1] == '\n') + line[read - 1] = '\0'; + vec_push_back(v, line); + line = NULL; + } +} diff --git a/jni/utils/utils.h b/jni/utils/utils.h index ba05f4c23..61ac26d6b 100644 --- a/jni/utils/utils.h +++ b/jni/utils/utils.h @@ -9,6 +9,12 @@ // xwrap.c FILE *xfopen(const char *pathname, const char *mode); +int xopen(const char *pathname, int flags); +ssize_t xwrite(int fd, const void *buf, size_t count); +ssize_t xread(int fd, void *buf, size_t count); +ssize_t xxread(int fd, void *buf, size_t count); +int xpipe(int pipefd[2]); +int xsetns(int fd, int nstype); // vector.c @@ -18,4 +24,9 @@ FILE *xfopen(const char *pathname, const char *mode); void monitor_logs(); +// misc.c + +int check_data(); +void file_to_vector(struct vector *v, FILE *fp); + #endif \ No newline at end of file diff --git a/jni/utils/vector.c b/jni/utils/vector.c index 986dae60e..2f19efcf7 100644 --- a/jni/utils/vector.c +++ b/jni/utils/vector.c @@ -25,10 +25,23 @@ void vec_sort(struct vector *v, int (*compar)(const void *, const void *)) { qsort(vec_entry(v), vec_size(v), sizeof(void*), compar); } +/* Will cleanup only the vector itself + * use in cases when each element requires special cleanup + */ void vec_destroy(struct vector *v) { - // Will not free each entry! - // Manually free each entry, then call this function vec_size(v) = 0; vec_cap(v) = 0; - free(v->data); -} \ No newline at end of file + free(vec_entry(v)); + vec_entry(v) = NULL; // Prevent double destroy segfault +} + +/* Will cleanup each element AND the vector itself + * Shall be the general case + */ +void vec_deep_destroy(struct vector *v) { + void *e; + vec_for_each(v, e) { + free(e); + } + vec_destroy(v); +} diff --git a/jni/utils/vector.h b/jni/utils/vector.h index 7f6db9ddd..de0801848 100644 --- a/jni/utils/vector.h +++ b/jni/utils/vector.h @@ -15,6 +15,7 @@ void vec_init(struct vector *v); void vec_push_back(struct vector *v, void *p); void vec_sort(struct vector *v, int (*compar)(const void *, const void *)); void vec_destroy(struct vector *v); +void vec_deep_destroy(struct vector *v); #define vec_size(v) (v)->size #define vec_cap(v) (v)->cap #define vec_entry(v) (v)->data @@ -23,4 +24,8 @@ void vec_destroy(struct vector *v); e = (v)->data[0]; \ for (size_t _ = 0; _ < (v)->size; ++_, e = (v)->data[_]) +#define vec_for_each_r(v, e) \ + e = (v)->data[(v)->size - 1]; \ + for (size_t _ = (v)->size - 1; _ >= 0; --_, e = (v)->data[_]) + #endif \ No newline at end of file diff --git a/jni/utils/xwrap.c b/jni/utils/xwrap.c index c398dd8a8..f048484e3 100644 --- a/jni/utils/xwrap.c +++ b/jni/utils/xwrap.c @@ -6,8 +6,14 @@ * */ +#define _GNU_SOURCE +#include #include #include +#include +#include +#include +#include #include "utils.h" @@ -15,7 +21,54 @@ FILE *xfopen(const char *pathname, const char *mode) { FILE *fp = fopen(pathname, mode); if (fp == NULL) { PLOGE("fopen"); - exit(1); } return fp; -} \ No newline at end of file +} + +int xopen(const char *pathname, int flags) { + int fd = open(pathname, flags); + if (fd < 0) { + PLOGE("open"); + } + return fd; +} + +ssize_t xwrite(int fd, const void *buf, size_t count) { + if (count != write(fd, buf, count)) { + PLOGE("write"); + } + return count; +} + +// Read error other than EOF +ssize_t xread(int fd, void *buf, size_t count) { + int ret = read(fd, buf, count); + if (ret < 0) { + PLOGE("read"); + } + return ret; +} + +// Read exact same size as count +ssize_t xxread(int fd, void *buf, size_t count) { + if (count != read(fd, buf, count)) { + PLOGE("read"); + } + return count; +} + +int xpipe(int pipefd[2]) { + if (pipe(pipefd) == -1) { + PLOGE("pipe"); + exit(1); + } + return 0; +} + +int xsetns(int fd, int nstype) { + if (setns(fd, nstype) == -1) { + PLOGE("setns"); + } + return 0; +} +