From a8030c39b11a105b2820bcbc3225b3ce5eafc5a9 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Mon, 2 Jul 2018 22:11:28 +0800 Subject: [PATCH] Separate logging into its own daemon --- native/jni/core/daemon.c | 46 ++++++++----- native/jni/core/log_monitor.c | 97 +++++++++++++++++++++------- native/jni/core/magisk.c | 2 +- native/jni/core/magiskinit.c | 21 +++--- native/jni/core/socket.c | 16 +++-- native/jni/include/daemon.h | 17 ++++- native/jni/include/logging.h | 12 ---- native/jni/include/magisk.h | 3 +- native/jni/magiskhide/proc_monitor.c | 20 +++--- 9 files changed, 153 insertions(+), 81 deletions(-) diff --git a/native/jni/core/daemon.c b/native/jni/core/daemon.c index 79415d658..9714c0fff 100644 --- a/native/jni/core/daemon.c +++ b/native/jni/core/daemon.c @@ -84,6 +84,7 @@ static void *request_handler(void *args) { late_start(client); break; default: + close(client); break; } return NULL; @@ -105,14 +106,16 @@ void auto_start_magiskhide() { free(hide_prop); } -void start_daemon() { +void main_daemon() { setsid(); setcon("u:r:"SEPOL_PROC_DOMAIN":s0"); int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC); - xdup2(fd, STDIN_FILENO); xdup2(fd, STDOUT_FILENO); xdup2(fd, STDERR_FILENO); close(fd); + fd = xopen("/dev/zero", O_RDWR | O_CLOEXEC); + xdup2(fd, STDIN_FILENO); + close(fd); // Block user signals sigset_t block_set; @@ -121,16 +124,15 @@ void start_daemon() { sigaddset(&block_set, SIGUSR2); pthread_sigmask(SIG_SETMASK, &block_set, NULL); + // Start the log monitor + monitor_logs(); + struct sockaddr_un sun; - fd = setup_socket(&sun); + fd = setup_socket(&sun, MAIN_DAEMON); if (xbind(fd, (struct sockaddr*) &sun, sizeof(sun))) exit(1); xlisten(fd, 10); - - // Start the log monitor - monitor_logs(); - LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") daemon started\n"); // Change process name @@ -147,13 +149,11 @@ void start_daemon() { } } -/* Connect the daemon, and return a socketfd */ -int connect_daemon() { +/* Connect the daemon, set sockfd, and return if new daemon is spawned */ +int connect_daemon2(daemon_t d, int *sockfd) { struct sockaddr_un sun; - int fd = setup_socket(&sun); - if (connect(fd, (struct sockaddr*) &sun, sizeof(sun))) { - // If we cannot access the daemon, we start a daemon in the child process if possible - + *sockfd = setup_socket(&sun, d); + if (connect(*sockfd, (struct sockaddr*) &sun, sizeof(sun))) { if (getuid() != UID_ROOT || getgid() != UID_ROOT) { fprintf(stderr, "No daemon is currently running!\n"); exit(1); @@ -161,12 +161,26 @@ int connect_daemon() { if (fork_dont_care() == 0) { LOGD("client: connect fail, try launching new daemon process\n"); - close(fd); - start_daemon(); + close(*sockfd); + switch (d) { + case MAIN_DAEMON: + main_daemon(); + break; + case LOG_DAEMON: + log_daemon(); + break; + } } - while (connect(fd, (struct sockaddr*) &sun, sizeof(sun))) + while (connect(*sockfd, (struct sockaddr*) &sun, sizeof(sun))) usleep(10000); + return 1; } + return 0; +} + +int connect_daemon() { + int fd; + connect_daemon2(MAIN_DAEMON, &fd); return fd; } diff --git a/native/jni/core/log_monitor.c b/native/jni/core/log_monitor.c index 2099b7238..53167f6cb 100644 --- a/native/jni/core/log_monitor.c +++ b/native/jni/core/log_monitor.c @@ -13,9 +13,23 @@ #include "magisk.h" #include "utils.h" -#include "resetprop.h" +#include "daemon.h" int loggable = 1; +static int sockfd; +static pthread_t thread = -1; +static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; + +enum { + HIDE_EVENT, + LOG_EVENT, + DEBUG_EVENT +}; + +struct log_listener { + int fd; + int (*filter) (const char*); +}; static int am_proc_start_filter(const char *log) { return strstr(log, "am_proc_start") != NULL; @@ -30,7 +44,7 @@ static int magisk_debug_log_filter(const char *log) { return strstr(log, "am_proc_start") == NULL; } -struct log_listener log_events[] = { +static struct log_listener log_events[] = { { /* HIDE_EVENT */ .fd = -1, .filter = am_proc_start_filter @@ -58,12 +72,55 @@ static void test_logcat() { waitpid(log_pid, NULL, 0); } -static void *logger_thread(void *args) { +static void sigpipe_handler(int sig) { + close(log_events[HIDE_EVENT].fd); + log_events[HIDE_EVENT].fd = -1; +} + +static void *socket_thread(void *args) { + /* This would block, so separate thread */ + while(1) { + int fd = accept4(sockfd, NULL, NULL, SOCK_CLOEXEC); + switch(read_int(fd)) { + case HIDE_CONNECT: + pthread_mutex_lock(&lock); + log_events[HIDE_EVENT].fd = fd; + pthread_mutex_unlock(&lock); + thread = -1; + return NULL; + default: + close(fd); + break; + } + } +} + +void log_daemon() { + setsid(); + strcpy(argv0, "magisklogd"); + + struct sockaddr_un sun; + sockfd = setup_socket(&sun, LOG_DAEMON); + if (xbind(sockfd, (struct sockaddr*) &sun, sizeof(sun))) + exit(1); + xlisten(sockfd, 1); + LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") logger started\n"); + + struct sigaction act; + memset(&act, 0, sizeof(act)); + act.sa_handler = sigpipe_handler; + sigaction(SIGPIPE, &act, NULL); + + // Setup log dumps + rename(LOGFILE, LOGFILE ".bak"); + log_events[LOG_EVENT].fd = xopen(LOGFILE, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0644); +#ifdef MAGISK_DEBUG + log_events[DEBUG_EVENT].fd = xopen(DEBUG_LOG, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC, 0644); +#endif + int log_fd = -1, log_pid; char line[PIPE_BUF]; - LOGD("log_monitor: logger start"); - while (1) { if (!loggable) { // Disable all services @@ -71,7 +128,7 @@ static void *logger_thread(void *args) { close(log_events[i].fd); log_events[i].fd = -1; } - return NULL; + return; } // Start logcat @@ -86,10 +143,17 @@ static void *logger_thread(void *args) { if (line[0] == '-') continue; size_t len = strlen(line); + pthread_mutex_lock(&lock); for (int i = 0; i < EVENT_NUM; ++i) { if (log_events[i].fd > 0 && log_events[i].filter(line)) - xwrite(log_events[i].fd, line, len); + write(log_events[i].fd, line, len); } + if (thread < 0 && log_events[HIDE_EVENT].fd < 0) { + // New thread to handle connection to main daemon + xpthread_create(&thread, NULL, socket_thread, NULL); + pthread_detach(thread); + } + pthread_mutex_unlock(&lock); if (kill(log_pid, 0)) break; } @@ -101,26 +165,15 @@ static void *logger_thread(void *args) { waitpid(log_pid, NULL, 0); test_logcat(); } - - // Should never be here, but well... - return NULL; } /* Start new threads to monitor logcat and dump to logfile */ void monitor_logs() { - pthread_t thread; - test_logcat(); - if (loggable) { - rename(LOGFILE, LOGFILE ".bak"); - log_events[LOG_EVENT].fd = creat(LOGFILE, 0644); -#ifdef MAGISK_DEBUG - log_events[DEBUG_EVENT].fd = creat(DEBUG_LOG, 0644); -#endif - - // Start logcat monitor - xpthread_create(&thread, NULL, logger_thread, NULL); - pthread_detach(thread); + int fd; + connect_daemon2(LOG_DAEMON, &fd); + write_int(fd, DO_NOTHING); + close(fd); } } diff --git a/native/jni/core/magisk.c b/native/jni/core/magisk.c index 926f3b32f..a4b802639 100644 --- a/native/jni/core/magisk.c +++ b/native/jni/core/magisk.c @@ -98,7 +98,7 @@ int magisk_main(int argc, char *argv[]) { return 0; } else if (strcmp(argv[1], "--daemon") == 0) { int fd = connect_daemon(); - close(fd); + write_int(fd, DO_NOTHING); return 0; } else if (strcmp(argv[1], "--startup") == 0) { startup(); diff --git a/native/jni/core/magiskinit.c b/native/jni/core/magiskinit.c index 59f863866..d5c5cf781 100644 --- a/native/jni/core/magiskinit.c +++ b/native/jni/core/magiskinit.c @@ -57,8 +57,6 @@ extern policydb_t *policydb; int (*init_applet_main[]) (int, char *[]) = { magiskpolicy_main, magiskpolicy_main, NULL }; -static char RAND_SOCKET_NAME[sizeof(SOCKET_NAME)]; -static int SOCKET_OFF = -1; struct cmdline { char skip_initramfs; @@ -345,18 +343,21 @@ static int dump_magiskrc(const char *path, mode_t mode) { static void patch_socket_name(const char *path) { void *buf; + char name[sizeof(MAIN_SOCKET)]; size_t size; mmap_rw(path, &buf, &size); - if (SOCKET_OFF < 0) { - for (int i = 0; i < size; ++i) { - if (memcmp(buf + i, SOCKET_NAME, sizeof(SOCKET_NAME)) == 0) { - SOCKET_OFF = i; - break; - } + for (int i = 0; i < size; ++i) { + if (memcmp(buf + i, MAIN_SOCKET, sizeof(MAIN_SOCKET)) == 0) { + gen_rand_str(name, sizeof(name)); + memcpy(buf + i, name, sizeof(name)); + i += sizeof(name); + } + if (memcmp(buf + i, LOG_SOCKET, sizeof(LOG_SOCKET)) == 0) { + gen_rand_str(name, sizeof(name)); + memcpy(buf + i, name, sizeof(name)); + i += sizeof(name); } } - gen_rand_str(RAND_SOCKET_NAME, sizeof(SOCKET_NAME)); - memcpy(buf + SOCKET_OFF, RAND_SOCKET_NAME, sizeof(SOCKET_NAME)); munmap(buf, size); } diff --git a/native/jni/core/socket.c b/native/jni/core/socket.c index 73861dba0..8c93d78b8 100644 --- a/native/jni/core/socket.c +++ b/native/jni/core/socket.c @@ -8,19 +8,25 @@ #include "utils.h" #include "magisk.h" -static char socket_name[] = SOCKET_NAME; /* Workaround compiler bug pre NDK r13 */ - /* Setup the address and return socket fd */ -int setup_socket(struct sockaddr_un *sun) { +int setup_socket(struct sockaddr_un *sun, daemon_t d) { int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); memset(sun, 0, sizeof(*sun)); sun->sun_family = AF_LOCAL; sun->sun_path[0] = '\0'; - memcpy(sun->sun_path + 1, socket_name, sizeof(SOCKET_NAME)); + const char *name; + switch (d) { + case MAIN_DAEMON: + name = MAIN_SOCKET; + break; + case LOG_DAEMON: + name = LOG_SOCKET; + break; + } + strcpy(sun->sun_path + 1, name); return fd; } - /* * Receive a file descriptor from a Unix socket. * Contributed by @mkasick diff --git a/native/jni/include/daemon.h b/native/jni/include/daemon.h index 53da2a947..49203bd79 100644 --- a/native/jni/include/daemon.h +++ b/native/jni/include/daemon.h @@ -24,7 +24,8 @@ enum { STOP_MAGISKHIDE, ADD_HIDELIST, RM_HIDELIST, - LS_HIDELIST + LS_HIDELIST, + HIDE_CONNECT }; // Return codes for daemon @@ -39,15 +40,25 @@ enum { HIDE_ITEM_NOT_EXIST, }; +typedef enum { + MAIN_DAEMON, + LOG_DAEMON +} daemon_t; + // daemon.c -void start_daemon(); +void main_daemon(); int connect_daemon(); +int connect_daemon2(daemon_t d, int *sockfd); void auto_start_magiskhide(); +// log_monitor.c + +void log_daemon(); + // socket.c -int setup_socket(struct sockaddr_un *sun); +int setup_socket(struct sockaddr_un *sun, daemon_t d); int recv_fd(int sockfd); void send_fd(int sockfd, int fd); int read_int(int fd); diff --git a/native/jni/include/logging.h b/native/jni/include/logging.h index 337ecccbb..bc13a3912 100644 --- a/native/jni/include/logging.h +++ b/native/jni/include/logging.h @@ -46,18 +46,6 @@ #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)) -enum { - HIDE_EVENT, - LOG_EVENT, - DEBUG_EVENT -}; - -struct log_listener { - int fd; - int (*filter) (const char*); -}; - -extern struct log_listener log_events[]; extern int loggable; void monitor_logs(); diff --git a/native/jni/include/magisk.h b/native/jni/include/magisk.h index f154b7d9c..c6bb0b07a 100644 --- a/native/jni/include/magisk.h +++ b/native/jni/include/magisk.h @@ -7,7 +7,8 @@ #include "logging.h" #define MAGISK_VER_STR xstr(MAGISK_VERSION) ":MAGISK" -#define SOCKET_NAME "d30138f2310a9fb9c54a3e0c21f58591" +#define MAIN_SOCKET "d30138f2310a9fb9c54a3e0c21f58591" +#define LOG_SOCKET "5864cd77f2f8c59b3882e2d35dbf51e4" #define JAVA_PACKAGE_NAME "com.topjohnwu.magisk" #ifndef ARG_MAX diff --git a/native/jni/magiskhide/proc_monitor.c b/native/jni/magiskhide/proc_monitor.c index 06c9b79c5..48f5adbf1 100644 --- a/native/jni/magiskhide/proc_monitor.c +++ b/native/jni/magiskhide/proc_monitor.c @@ -16,21 +16,19 @@ #include #include "magisk.h" +#include "daemon.h" #include "utils.h" #include "magiskhide.h" -static int pipefd[2] = { -1, -1 }; +static int sockfd = -1; // Workaround for the lack of pthread_cancel static void term_thread(int sig) { LOGD("proc_monitor: running cleanup\n"); destroy_list(); hideEnabled = 0; - // Unregister listener - log_events[HIDE_EVENT].fd = -1; - close(pipefd[0]); - close(pipefd[1]); - pipefd[0] = pipefd[1] = -1; + close(sockfd); + sockfd = -1; pthread_mutex_destroy(&hide_lock); pthread_mutex_destroy(&file_lock); LOGD("proc_monitor: terminating...\n"); @@ -128,12 +126,12 @@ void proc_monitor() { term_thread(TERM_THREAD); } - // Register our listener to logcat monitor - xpipe2(pipefd, O_CLOEXEC); - log_events[HIDE_EVENT].fd = pipefd[1]; + // Connect to the log daemon + connect_daemon2(LOG_DAEMON, &sockfd); + write_int(sockfd, HIDE_CONNECT); - FILE *logs = fdopen(pipefd[0], "r"); - char log[PIPE_BUF], *line; + FILE *logs = fdopen(sockfd, "r"); + char log[4096], *line; while (1) { /* It might be interrupted */ if (fgets(log, sizeof(log), logs) == NULL)