Integrate MagiskHide into Magisk Daemon

This commit is contained in:
topjohnwu 2017-04-09 07:25:10 +08:00
parent 054a1e5ea4
commit 144ff5e716
12 changed files with 297 additions and 75 deletions

View File

@ -37,7 +37,7 @@ LOCAL_SRC_FILES := \
# su/utils.c \
# su/pts.c
LOCAL_CFLAGS := -Wno-implicit-exception-spec-mismatch
LOCAL_CFLAGS := -Wno-implicit-exception-spec-mismatch -DDEBUG
LOCAL_LDLIBS := -llog
include $(BUILD_EXECUTABLE)

View File

@ -8,6 +8,7 @@
#include <unistd.h>
#include <fcntl.h>
#include <string.h>
#include <errno.h>
#include <sys/un.h>
#include <sys/types.h>
#include <sys/socket.h>
@ -18,12 +19,33 @@
#include "daemon.h"
static void request_handler(int client) {
/* TODO: Put all function entrypoints here
it'll currently just log the input string */
char *s = read_string(client);
client_request req = read_int(client);
char *s;
int pid, status, code;
switch (req) {
case LAUNCH_MAGISKHIDE:
launch_magiskhide(client);
break;
case STOP_MAGISKHIDE:
stop_magiskhide(client);
break;
case ADD_HIDELIST:
// TODO: Add hidelist
break;
case RM_HIDELIST:
// TODO: Remove hidelist
break;
case SUPERUSER:
// TODO: Run su
break;
case TEST:
s = read_string(client);
LOGI("%s\n", s);
free(s);
write_int(client, 0);
break;
}
close(client);
LOGI("%s\n", s);
free(s);
}
/* Setup the address and return socket fd */
@ -39,10 +61,14 @@ static int setup_socket(struct sockaddr_un *sun) {
return fd;
}
static void do_nothing() {}
void start_daemon() {
// Launch the daemon, create new session, set proper context
if (getuid() != AID_ROOT || getgid() != AID_ROOT) {
PLOGE("daemon requires root. uid/gid not root");
fprintf(stderr, "Starting daemon requires root: %s\n", strerror(errno));
PLOGE("start daemon");
}
switch (fork()) {
case -1:
@ -63,6 +89,12 @@ void start_daemon() {
// Change process name
strcpy(argv0, "magisk_daemon");
// The root daemon should not do anything if an error occurs
// It should stay intact in any circumstances
err_handler = do_nothing;
// Start log monitor
monitor_logs();
// Loop forever to listen to requests
while(1) {

View File

@ -1,7 +1,24 @@
/* daemon.h - Utility functions for daemon-client communication
*/
// Commands require connecting to daemon
typedef enum {
LAUNCH_MAGISKHIDE,
STOP_MAGISKHIDE,
ADD_HIDELIST,
RM_HIDELIST,
SUPERUSER,
TEST
} client_request;
// daemon.c
void start_daemon();
int connect_daemon();
// socket_trans.c
int recv_fd(int sockfd);
void send_fd(int sockfd, int fd);
int read_int(int fd);

View File

@ -9,6 +9,7 @@
#include <errno.h>
#include <string.h>
#include <pthread.h>
#include <android/log.h>
#define AID_SHELL (get_shell_uid())
@ -21,6 +22,13 @@
#define LOG_TAG "Magisk"
// Global handler for PLOGE
extern __thread void (*err_handler)(void);
// Two common error handlers
void exit_proc();
void exit_thread();
#ifdef DEBUG
#define LOGD(...) __android_log_print(ANDROID_LOG_DEBUG, LOG_TAG, __VA_ARGS__)
#else
@ -30,14 +38,14 @@
#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)); exit(1)
#define PLOGEV(fmt, err, args...) LOGE(fmt " failed with %d: %s", ##args, err, strerror(err)); exit(1)
#define PLOGE(fmt, args...) LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno)); err_handler()
void stub(const char *fmt, ...);
// 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
@ -53,19 +61,12 @@ int resetprop_main(int argc, char *argv[]);
}
#endif
/*****************
* Magisk Daemon *
*****************/
void start_daemon();
int connect_daemon();
/**************
* MagiskHide *
**************/
void launch_magiskhide();
void stop_magiskhide();
void launch_magiskhide(int client);
void stop_magiskhide(int client);
#endif

View File

@ -18,7 +18,7 @@
#include "utils.h"
#include "magiskhide.h"
static int isMocked = 0;
static int isMocked = 0, pid;
static void manage_selinux() {
if (isMocked) return;
@ -43,23 +43,36 @@ static void lazy_unmount(const char* mountpoint) {
LOGI("hide_daemon: Unmount Failed (%s)\n", mountpoint);
}
void hide_daemon() {
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
switch(fork()) {
hide_pid = fork();
switch(hide_pid) {
case -1:
PLOGE("fork");
return 1;
case 0:
break;
default:
return;
return 0;
}
close(pipefd[1]);
close(sv[0]);
// Set the process name
strcpy(argv0, "magiskhide_daemon");
// When an error occurs, report its failure to main process
err_handler = hide_daemon_err;
int pid, fd;
int fd;
FILE *fp;
char cache_block[256], *line;
struct vector mount_list;
@ -67,9 +80,12 @@ void hide_daemon() {
cache_block[0] = '\0';
while(1) {
xxread(pipefd[0], &pid, sizeof(pid));
xxread(sv[1], &pid, sizeof(pid));
// Termination called
if(pid == -1) exit(0);
if(pid == -1) {
LOGD("hide_daemon: received termination request\n");
_exit(0);
}
snprintf(magiskbuf, BUF_SIZE, "/proc/%d/ns/mnt", pid);
if(access(magiskbuf, F_OK) == -1) continue; // Maybe process died..
@ -95,7 +111,7 @@ void hide_daemon() {
}
}
}
// 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")
@ -125,6 +141,10 @@ void hide_daemon() {
// 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

View File

@ -8,38 +8,67 @@
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include <string.h>
#include <sys/wait.h>
#include <sys/types.h>
#include "magisk.h"
#include "utils.h"
#include "magiskhide.h"
#include "daemon.h"
int pipefd[2];
int sv[2], hide_pid;
struct vector *hide_list, *new_list;
int isEnabled = 0;
static pthread_t proc_monitor_thread;
static void kill_proc(int pid) {
void kill_proc(int pid) {
kill(pid, SIGTERM);
}
void launch_magiskhide() {
static void usage(char *arg0) {
fprintf(stderr,
"%s [--options [arguments...] ]\n\n"
"Options:\n"
" --enable: Start the magiskhide daemon\n"
" --disable: Stop the magiskhide daemon\n"
" --add <process name>: Add <process name> to the list\n"
" --rm <process name>: Remove <process name> from the list\n"
" --ls: Print out the current hide list\n"
, arg0);
exit(1);
}
void launch_magiskhide(int client) {
if (isEnabled) {
write_int(client, 0);
return;
}
/*
* The setns system call do not support multithread processes
* We have to fork a new process, and communicate with pipe
*/
xpipe(pipefd);
LOGI("* Starting MagiskHide\n");
if (socketpair(AF_LOCAL, SOCK_STREAM, 0, sv) == -1)
goto error;
// Launch the hide daemon
hide_daemon();
if (hide_daemon())
goto error;
close(pipefd[0]);
close(sv[1]);
// Initialize the hide list
hide_list = new_list = malloc(sizeof(*hide_list));
hide_list = new_list = xmalloc(sizeof(*hide_list));
if (hide_list == NULL)
goto error;
vec_init(hide_list);
FILE *fp = xfopen(HIDELIST, "r");
if (fp == NULL)
goto error;
file_to_vector(hide_list, fp);
fclose(fp);
char *line;
@ -49,20 +78,66 @@ void launch_magiskhide() {
}
// Start a new thread to monitor processes
pthread_create(&proc_monitor_thread, NULL, proc_monitor, NULL);
pthread_join(proc_monitor_thread, NULL);
if (xpthread_create(&proc_monitor_thread, NULL, proc_monitor, NULL))
goto error;
isEnabled = 1;
write_int(client, 0);
return;
error:
write_int(client, 1);
return;
}
void stop_magiskhide() {
void stop_magiskhide(int client) {
if (!isEnabled)
return;
LOGI("* Stopping MagiskHide\n");
int kill = -1;
// Terminate hide daemon
xwrite(pipefd[1], &kill, sizeof(kill));
write(sv[0], &kill, sizeof(kill));
close(sv[0]);
waitpid(hide_pid, NULL, 0);
// Stop process monitor
pthread_kill(proc_monitor_thread, SIGUSR1);
pthread_join(proc_monitor_thread, NULL);
isEnabled = 0;
write_int(client, 0);
}
int magiskhide_main(int argc, char *argv[]) {
launch_magiskhide();
return 0;
if (argc < 2) {
usage(argv[0]);
}
client_request req;
if (strcmp(argv[1], "--enable") == 0) {
req = LAUNCH_MAGISKHIDE;
} else if (strcmp(argv[1], "--disable") == 0) {
req = STOP_MAGISKHIDE;
} else if (strcmp(argv[1], "--add") == 0 && argc > 2) {
req = ADD_HIDELIST;
} else if (strcmp(argv[1], "--rm") == 0 && argc > 2) {
req = RM_HIDELIST;
} else if (strcmp(argv[1], "--ls") == 0) {
FILE *fp = xfopen(HIDELIST, "r");
while (fgets(magiskbuf, BUF_SIZE, fp)) {
printf("%s", magiskbuf);
}
fclose(fp);
return 0;
}
int fd = connect_daemon();
write_int(fd, req);
if (req == ADD_HIDELIST || req == RM_HIDELIST) {
write_string(fd, argv[2]);
}
int code = read_int(fd);
close(fd);
if (code) {
fprintf(stderr, "Error occured in MagiskHide daemon\n");
}
return code;
}

View File

@ -6,13 +6,16 @@
#define ENFORCE_FILE "/sys/fs/selinux/enforce"
#define POLICY_FILE "/sys/fs/selinux/policy"
// Kill process
void kill_proc(int pid);
// Hide daemon
void hide_daemon();
int hide_daemon();
// Process monitor
void *proc_monitor(void *args);
extern int pipefd[2];
extern int sv[2], hide_pid, isEnabled;
extern struct vector *hide_list, *new_list;
#endif

View File

@ -11,15 +11,12 @@
#include <signal.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/wait.h>
#include "magisk.h"
#include "utils.h"
#include "magiskhide.h"
/* 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 int zygote_num = 0;
static char init_ns[32], zygote_ns[2][32];
@ -32,15 +29,21 @@ static void read_namespace(const int pid, char* target, const size_t size) {
// Workaround for the lack of pthread_cancel
static void quit_pthread(int sig) {
pthread_exit(NULL);
}
static void cleanup_handler(void *arg) {
LOGD("proc_monitor: running cleanup\n");
char *line;
vec_for_each(hide_list, line) {
ps_filter_proc_name(line, kill_proc);
}
vec_deep_destroy(hide_list);
vec_deep_destroy(new_list);
free(hide_list);
free(new_list);
if (new_list != hide_list) {
vec_deep_destroy(new_list);
free(new_list);
}
hide_list = new_list = NULL;
isEnabled = 0;
LOGD("proc_monitor: terminating...\n");
pthread_exit(NULL);
}
static void store_zygote_ns(int pid) {
@ -51,10 +54,21 @@ static void store_zygote_ns(int pid) {
++zygote_num;
}
static void proc_monitor_err() {
LOGD("proc_monitor: error occured, stopping magiskhide services\n");
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);
quit_pthread(SIGUSR1);
}
void *proc_monitor(void *args) {
// Register the cancel signal
signal(SIGUSR1, quit_pthread);
pthread_cleanup_push_fix(cleanup_handler, NULL);
// The error handler should only exit the thread, not the whole process
err_handler = proc_monitor_err;
int pid;
char buffer[512];
@ -106,6 +120,8 @@ void *proc_monitor(void *args) {
hide_list = new_list;
}
ret = 0;
vec_for_each(hide_list, line) {
if (strcmp(processName, line) == 0) {
read_namespace(pid, buffer, 32);
@ -121,13 +137,19 @@ void *proc_monitor(void *args) {
if (ret) break;
}
ret = 0;
// Send pause signal ASAP
if (kill(pid, SIGSTOP) == -1) continue;
LOGI("proc_monitor: %s(PID=%d ns=%s)\n", processName, pid, buffer);
// Unmount start
xwrite(pipefd[1], &pid, sizeof(pid));
xwrite(sv[0], &pid, sizeof(pid));
// Get the hide daemon return code
xxread(sv[0], &ret, sizeof(ret));
LOGD("proc_monitor: hide daemon response code: %d\n", ret);
break;
}
}
@ -135,10 +157,15 @@ void *proc_monitor(void *args) {
vec_deep_destroy(temp);
free(temp);
}
if (ret) {
// Wait hide process to kill itself
waitpid(hide_pid, NULL, 0);
quit_pthread(SIGUSR1);
}
}
// Should never be here
pclose(p);
quit_pthread(SIGUSR1);
pthread_exit(NULL);
return NULL;
}

View File

@ -1,6 +1,9 @@
/* main.c - The entry point, should be multi-call
*/
#include <stdlib.h>
#include <pthread.h>
#include "utils.h"
#include "magisk.h"
#include "daemon.h"
@ -10,8 +13,22 @@ char *argv0;
void stub(const char *fmt, ...) {}
// Global error hander function
// Should be changed each thread/process
__thread void (*err_handler)(void);
void exit_proc() {
exit(-1);
}
void exit_thread() {
pthread_exit(NULL);
}
int main(int argc, char *argv[]) {
argv0 = argv[0];
// Exit the whole app if error occurs by default
err_handler = exit_proc;
char * arg = strrchr(argv[0], '/');
if (arg) ++arg;
if (strcmp(arg, "magisk") == 0) {
@ -27,8 +44,9 @@ int main(int argc, char *argv[]) {
} else if (strcmp(argv[1], "--test") == 0) {
// Temporary testing entry
int fd = connect_daemon();
write_int(fd, TEST);
write_string(fd, argv[2]);
return 0;
return read_int(fd);
} else {
// It's calling applets
--argc;

View File

@ -12,8 +12,8 @@
#include "utils.h"
static void *logger_thread(void *args) {
rename("/cache/magisk.log", "/cache/last_magisk.log");
FILE *logfile = xfopen("/cache/magisk.log", "w");
// rename("/cache/magisk.log", "/cache/last_magisk.log");
FILE *logfile = xfopen("/cache/magisk_test.log", "w");
// Disable buffering
setbuf(logfile, NULL);
// Start logcat

View File

@ -6,6 +6,7 @@
#include <stdio.h>
#include <dirent.h>
#include <pthread.h>
#include <sys/types.h>
#include <sys/socket.h>
@ -34,6 +35,9 @@ void *xcalloc(size_t nmemb, size_t size);
void *xrealloc(void *ptr, size_t size);
ssize_t xsendmsg(int sockfd, const struct msghdr *msg, int flags);
ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags);
int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg);
int xsocketpair(int domain, int type, int protocol, int sv[2]);
// log_monitor.c
@ -48,4 +52,4 @@ ssize_t fdreadline(int fd, char *buf, size_t size);
void ps(void (*func)(int));
void ps_filter_proc_name(const char *filter, void (*func)(int));
#endif
#endif

View File

@ -39,10 +39,11 @@ int xopen(const char *pathname, int flags) {
}
ssize_t xwrite(int fd, const void *buf, size_t count) {
if (count != write(fd, buf, count)) {
int ret = write(fd, buf, count);
if (count != ret) {
PLOGE("write");
}
return count;
return ret;
}
// Read error other than EOF
@ -56,24 +57,27 @@ ssize_t xread(int fd, void *buf, size_t count) {
// Read exact same size as count
ssize_t xxread(int fd, void *buf, size_t count) {
if (count != read(fd, buf, count)) {
int ret = read(fd, buf, count);
if (count != ret) {
PLOGE("read");
}
return count;
return ret;
}
int xpipe(int pipefd[2]) {
if (pipe(pipefd) == -1) {
int ret = pipe(pipefd);
if (ret == -1) {
PLOGE("pipe");
}
return 0;
return ret;
}
int xsetns(int fd, int nstype) {
if (setns(fd, nstype) == -1) {
int ret = setns(fd, nstype);
if (ret == -1) {
PLOGE("setns");
}
return 0;
return ret;
}
DIR *xopendir(const char *name) {
@ -102,10 +106,11 @@ pid_t xsetsid() {
}
int xsetcon(char *context) {
if (setcon(context) == -1) {
int ret = setcon(context);
if (ret == -1) {
PLOGE("setcon: %s", context);
}
return 0;
return ret;
}
int xsocket(int domain, int type, int protocol) {
@ -117,24 +122,27 @@ int xsocket(int domain, int type, int protocol) {
}
int xbind(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
if (bind(sockfd, addr, addrlen) == -1) {
int ret = bind(sockfd, addr, addrlen);
if (ret == -1) {
PLOGE("bind");
}
return 0;
return ret;
}
int xconnect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) {
if (connect(sockfd, addr, addrlen) == -1) {
int ret = connect(sockfd, addr, addrlen);
if (ret == -1) {
PLOGE("bind");
}
return 0;
return ret;
}
int xlisten(int sockfd, int backlog) {
if (listen(sockfd, backlog) == -1) {
int ret = listen(sockfd, backlog);
if (ret == -1) {
PLOGE("listen");
}
return 0;
return ret;
}
int xaccept(int sockfd, struct sockaddr *addr, socklen_t *addrlen) {
@ -185,4 +193,21 @@ ssize_t xrecvmsg(int sockfd, struct msghdr *msg, int flags) {
return rec;
}
int xpthread_create(pthread_t *thread, const pthread_attr_t *attr,
void *(*start_routine) (void *), void *arg) {
errno = pthread_create(thread, attr, start_routine, arg);
if (errno) {
PLOGE("pthread_create");
}
return errno;
}
int xsocketpair(int domain, int type, int protocol, int sv[2]) {
int ret = socketpair(domain, type, protocol, sv);
if (ret == -1) {
PLOGE("socketpair");
}
return ret;
}