diff --git a/native/jni/Android.mk b/native/jni/Android.mk index ff5497639..2f2570462 100644 --- a/native/jni/Android.mk +++ b/native/jni/Android.mk @@ -36,7 +36,7 @@ LOCAL_SRC_FILES := \ core/img.cpp \ core/magisk.cpp \ core/daemon.cpp \ - core/log_daemon.cpp \ + core/logcat.cpp \ core/bootstages.cpp \ core/socket.cpp \ core/db.cpp \ diff --git a/native/jni/core/bootstages.cpp b/native/jni/core/bootstages.cpp index a5d0d8d7e..fa2c6298d 100644 --- a/native/jni/core/bootstages.cpp +++ b/native/jni/core/bootstages.cpp @@ -16,14 +16,15 @@ #include #include -#include "magisk.h" -#include "db.h" -#include "utils.h" -#include "img.h" -#include "daemon.h" -#include "resetprop.h" -#include "selinux.h" -#include "flags.h" +#include +#include +#include +#include +#include +#include +#include +#include +#include using namespace std; @@ -685,7 +686,7 @@ void post_fs_data(int client) { unblock_boot_process(); } - start_log_daemon(); + start_logcat(); // Run common scripts LOGI("* Running post-fs-data.d scripts\n"); diff --git a/native/jni/core/daemon.cpp b/native/jni/core/daemon.cpp index 34d66e7c8..d994f40e1 100644 --- a/native/jni/core/daemon.cpp +++ b/native/jni/core/daemon.cpp @@ -86,9 +86,6 @@ static void *request_handler(void *args) { case BOOT_COMPLETE: boot_complete(client); break; - case HANDSHAKE: - /* Do NOT close the client, make it hold */ - break; case SQLITE_CMD: exec_sql(client); close(client); diff --git a/native/jni/core/log_daemon.cpp b/native/jni/core/log_daemon.cpp deleted file mode 100644 index c179cdf91..000000000 --- a/native/jni/core/log_daemon.cpp +++ /dev/null @@ -1,217 +0,0 @@ -/* log_daemon.c - A dedicated daemon to monitor logcat - * - * A universal logcat monitor for many usages. Add listeners to the list, - * and the new log line will be sent through sockets to trigger - * asynchronous events without polling - */ - -#include -#include -#include -#include -#include -#include -#include -#include - -#include "magisk.h" -#include "utils.h" -#include "daemon.h" -#include "flags.h" - -using namespace std; - -bool log_daemon_started = false; -static vector log_cmd, clear_cmd; -static pthread_mutex_t lock = PTHREAD_MUTEX_INITIALIZER; - -enum { - HIDE_EVENT, - LOG_EVENT -}; - -#define EVENT_NUM 2 - -struct log_listener { - int fd; - bool (*filter)(const char *); -}; - -static bool am_proc_start_filter(const char *log) { - return strstr(log, "am_proc_start") != nullptr; -} - -static bool magisk_log_filter(const char *log) { - return !am_proc_start_filter(log); -} - -static struct log_listener events[] = { - { /* HIDE_EVENT */ - .fd = -1, - .filter = am_proc_start_filter - }, - { /* LOG_EVENT */ - .fd = -1, - .filter = magisk_log_filter - } -}; - -static void sigpipe_handler(int) { - close(events[HIDE_EVENT].fd); - events[HIDE_EVENT].fd = -1; -} - -static void *monitor_thread(void *) { - // Block SIGPIPE to prevent interruption - sigset_t block_set; - sigemptyset(&block_set); - sigaddset(&block_set, SIGPIPE); - pthread_sigmask(SIG_SETMASK, &block_set, nullptr); - // Give the main daemon some time before we monitor it - sleep(5); - int fd; - char b; - while (true) { - fd = connect_daemon(); - write_int(fd, HANDSHAKE); - // This should hold unless the daemon is killed - read(fd, &b, sizeof(b)); - // The main daemon crashed, spawn a new one - close(fd); - } -} - -static void *logcat_thread(void *) { - int log_pid; - char line[4096]; - while (true) { - // Start logcat - exec_t exec { - .fd = -1, - .argv = log_cmd.data() - }; - log_pid = exec_command(exec); - FILE *logs = fdopen(exec.fd, "r"); - while (fgets(line, sizeof(line), logs)) { - if (line[0] == '-') - continue; - size_t len = strlen(line); - pthread_mutex_lock(&lock); - for (auto &event : events) { - if (event.fd > 0 && event.filter(line)) - write(event.fd, line, len); - } - pthread_mutex_unlock(&lock); - } - - fclose(logs); - kill(log_pid, SIGTERM); - waitpid(log_pid, nullptr, 0); - - LOGI("magisklogd: logcat output EOF"); - // Clear buffer - exec_command_sync(clear_cmd.data()); - } -} - -static void log_daemon() { - setsid(); - LOGI("Magisk v" xstr(MAGISK_VERSION) "(" xstr(MAGISK_VER_CODE) ") logger started\n"); - strcpy(argv0, "magisklogd"); - - // Set SIGPIPE handler - struct sigaction act; - memset(&act, 0, sizeof(act)); - act.sa_handler = sigpipe_handler; - sigaction(SIGPIPE, &act, nullptr); - - // Setup log dumps - rename(LOGFILE, LOGFILE ".bak"); - events[LOG_EVENT].fd = xopen(LOGFILE, O_CREAT | O_WRONLY | O_TRUNC | O_CLOEXEC | O_APPEND, 0644); - - // Construct cmdline - log_cmd.push_back(MIRRDIR "/system/bin/logcat"); - // Test whether these buffers actually works - const char *b[] = { "main", "events", "crash" }; - for (auto &buffer : b) { - if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-b", buffer, "-d", "-f", "/dev/null") == 0) { - log_cmd.push_back("-b"); - log_cmd.push_back(buffer); - } - } - chmod("/dev/null", 0666); - clear_cmd = log_cmd; - log_cmd.insert(log_cmd.end(), { "-v", "threadtime", "-s", "am_proc_start", "Magisk" }); -#ifdef MAGISK_DEBUG - log_cmd.push_back("*:F"); -#endif - log_cmd.push_back(nullptr); - - clear_cmd.push_back("-c"); - clear_cmd.push_back(nullptr); - - // Start worker threads - pthread_t thread; - pthread_create(&thread, nullptr, monitor_thread, nullptr); - pthread_detach(thread); - xpthread_create(&thread, nullptr, logcat_thread, nullptr); - pthread_detach(thread); - - // Handle socket requests - struct sockaddr_un sun; - socklen_t len = setup_sockaddr(&sun, LOG_SOCKET); - int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - if (xbind(sockfd, (struct sockaddr*) &sun, len)) - exit(1); - xlisten(sockfd, 10); - while(true) { - int fd = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC); - struct ucred credential; - get_client_cred(fd, &credential); - if (credential.uid != 0) { - // Do not allow non root clients - close(fd); - continue; - } - switch(read_int(fd)) { - case HIDE_CONNECT: - pthread_mutex_lock(&lock); - close(events[HIDE_EVENT].fd); - events[HIDE_EVENT].fd = fd; - pthread_mutex_unlock(&lock); - break; - case HANDSHAKE: - write_int(fd, HANDSHAKE); - default: - close(fd); - } - } -} - -bool start_log_daemon() { - if (!log_daemon_started) { - if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-d", "-f", "/dev/null") == 0) { - if (fork_dont_care() == 0) - log_daemon(); - log_daemon_started = true; - // Wait till we can connect to log_daemon and receive ack - int fd = connect_log_daemon(); - write_int(fd, HANDSHAKE); - read_int(fd); - close(fd); - } - chmod("/dev/null", 0666); - } - return log_daemon_started; -} - -int connect_log_daemon() { - if (!log_daemon_started) - return -1; - struct sockaddr_un sun; - socklen_t len = setup_sockaddr(&sun, LOG_SOCKET); - int fd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0); - while (connect(fd, (struct sockaddr*) &sun, len)) - usleep(10000); - return fd; -} diff --git a/native/jni/core/logcat.cpp b/native/jni/core/logcat.cpp new file mode 100644 index 000000000..1df90a10c --- /dev/null +++ b/native/jni/core/logcat.cpp @@ -0,0 +1,125 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +static std::vector log_cmd, clear_cmd; +static pthread_mutex_t event_lock = PTHREAD_MUTEX_INITIALIZER; +bool logcat_started = false; + +struct log_listener { + bool enable = false; + BlockingQueue queue; + bool (*filter)(const char *); +}; + +static struct log_listener events[] = { + { /* HIDE_EVENT */ + .filter = [](auto log) -> bool { return strstr(log, "am_proc_start") != nullptr; } + }, + { /* LOG_EVENT */ + .filter = [](auto log) -> bool { return !strstr(log, "am_proc_start"); } + } +}; + +static void init_args() { + // Construct cmdline + log_cmd.push_back(MIRRDIR "/system/bin/logcat"); + // Test whether these buffers actually works + const char *b[] = { "main", "events", "crash" }; + for (auto &buffer : b) { + if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-b", buffer, "-d", "-f", "/dev/null") == 0) { + log_cmd.push_back("-b"); + log_cmd.push_back(buffer); + } + } + chmod("/dev/null", 0666); + clear_cmd = log_cmd; + log_cmd.insert(log_cmd.end(), { "-v", "threadtime", "-s", "am_proc_start", "Magisk" }); +#ifdef MAGISK_DEBUG + log_cmd.push_back("*:F"); +#endif + log_cmd.push_back(nullptr); + + clear_cmd.push_back("-c"); + clear_cmd.push_back(nullptr); +} + +static void *logcat_gobbler(void *) { + int log_pid; + char line[4096]; + while (true) { + // Start logcat + exec_t exec { + .fd = -1, + .argv = log_cmd.data() + }; + log_pid = exec_command(exec); + FILE *logs = fdopen(exec.fd, "r"); + while (fgets(line, sizeof(line), logs)) { + if (line[0] == '-') + continue; + pthread_mutex_lock(&event_lock); + for (auto &event : events) { + if (event.enable && event.filter(line)) + event.queue.emplace_back(line); + } + pthread_mutex_unlock(&event_lock); + } + + fclose(logs); + kill(log_pid, SIGTERM); + waitpid(log_pid, nullptr, 0); + + LOGI("magisklogd: logcat output EOF"); + // Clear buffer + exec_command_sync(clear_cmd.data()); + } +} + +static void *log_writer(void *) { + rename(LOGFILE, LOGFILE ".bak"); + FILE *log = xfopen(LOGFILE, "ae"); + setbuf(log, nullptr); + auto &queue = start_logging(LOG_EVENT); + while (true) { + fprintf(log, "%s", queue.take().c_str()); + } +} + +BlockingQueue &start_logging(logcat_event event) { + pthread_mutex_lock(&event_lock); + events[event].enable = true; + pthread_mutex_unlock(&event_lock); + return events[event].queue; +} + +void stop_logging(logcat_event event) { + pthread_mutex_lock(&event_lock); + events[event].enable = false; + events[event].queue.clear(); + pthread_mutex_unlock(&event_lock); +} + +bool start_logcat() { + if (logcat_started) + return true; + int test = exec_command_sync(MIRRDIR "/system/bin/logcat", "-d", "-f", "/dev/null"); + chmod("/dev/null", 0666); + if (test != 0) + return false; + init_args(); + pthread_t t; + pthread_create(&t, nullptr, log_writer, nullptr); + pthread_detach(t); + pthread_create(&t, nullptr, logcat_gobbler, nullptr); + pthread_detach(t); + logcat_started = true; + return true; +} + diff --git a/native/jni/core/magisk.cpp b/native/jni/core/magisk.cpp index 1fa3b4d1d..32b1ab064 100644 --- a/native/jni/core/magisk.cpp +++ b/native/jni/core/magisk.cpp @@ -4,12 +4,12 @@ #include #include -#include "utils.h" -#include "magisk.h" -#include "daemon.h" -#include "selinux.h" -#include "db.h" -#include "flags.h" +#include +#include +#include +#include +#include +#include [[noreturn]] static void usage() { fprintf(stderr, @@ -96,6 +96,11 @@ int magisk_main(int argc, char *argv[]) { send_fd(fd, STDOUT_FILENO); return read_int(fd); } - +#if 0 + /* Entry point for testing stuffs */ + else if (strcmp(argv[1], "--test") == 0) { + return 0; + } +#endif usage(); } diff --git a/native/jni/include/daemon.h b/native/jni/include/daemon.h index 21c0f44a7..9ba09f4fe 100644 --- a/native/jni/include/daemon.h +++ b/native/jni/include/daemon.h @@ -19,8 +19,6 @@ enum { LATE_START, BOOT_COMPLETE, MAGISKHIDE, - HIDE_CONNECT, - HANDSHAKE, SQLITE_CMD, }; @@ -37,12 +35,6 @@ enum { int connect_daemon(); int switch_mnt_ns(int pid); -// log_monitor.c - -extern bool log_daemon_started; -int connect_log_daemon(); -bool start_log_daemon(); - // socket.c socklen_t setup_sockaddr(struct sockaddr_un *sun, const char *name); @@ -67,7 +59,6 @@ void write_key_token(int fd, const char *key, int tok); ***************/ void unlock_blocks(); -void startup(); void post_fs_data(int client); void late_start(int client); void boot_complete(int client); diff --git a/native/jni/include/logcat.h b/native/jni/include/logcat.h new file mode 100644 index 000000000..c2ec8df0b --- /dev/null +++ b/native/jni/include/logcat.h @@ -0,0 +1,15 @@ +#pragma once + +#include +#include + +enum logcat_event { + HIDE_EVENT, + LOG_EVENT +}; + +extern bool logcat_started; + +BlockingQueue &start_logging(logcat_event event); +void stop_logging(logcat_event event); +bool start_logcat(); diff --git a/native/jni/magiskhide/hide_utils.cpp b/native/jni/magiskhide/hide_utils.cpp index 18c2a4c01..c6234e362 100644 --- a/native/jni/magiskhide/hide_utils.cpp +++ b/native/jni/magiskhide/hide_utils.cpp @@ -8,12 +8,13 @@ #include #include -#include "magisk.h" -#include "utils.h" -#include "resetprop.h" +#include +#include +#include +#include +#include + #include "magiskhide.h" -#include "daemon.h" -#include "db.h" using namespace std; @@ -282,7 +283,7 @@ int launch_magiskhide(int client) { if (hide_enabled) return HIDE_IS_ENABLED; - if (!log_daemon_started) + if (!logcat_started) return LOGCAT_DISABLED; hide_enabled = true; @@ -327,7 +328,7 @@ int stop_magiskhide() { } void auto_start_magiskhide() { - if (!start_log_daemon()) + if (!start_logcat()) return; db_settings dbs; get_db_settings(&dbs, HIDE_CONFIG); diff --git a/native/jni/magiskhide/proc_monitor.cpp b/native/jni/magiskhide/proc_monitor.cpp index 3893822be..c226aae0d 100644 --- a/native/jni/magiskhide/proc_monitor.cpp +++ b/native/jni/magiskhide/proc_monitor.cpp @@ -18,23 +18,22 @@ #include #include -#include "magisk.h" -#include "daemon.h" -#include "utils.h" +#include +#include +#include + #include "magiskhide.h" using namespace std; -static int sockfd = -1; extern char *system_block, *vendor_block, *magiskloop; // Workaround for the lack of pthread_cancel static void term_thread(int) { LOGD("proc_monitor: running cleanup\n"); + stop_logging(HIDE_EVENT); hide_list.clear(); hide_enabled = false; - close(sockfd); - sockfd = -1; pthread_mutex_destroy(&list_lock); LOGD("proc_monitor: terminating\n"); pthread_exit(nullptr); @@ -124,20 +123,14 @@ void proc_monitor() { term_thread(TERM_THREAD); } - // Connect to the log daemon - sockfd = connect_log_daemon(); - if (sockfd < 0) - pthread_exit(nullptr); - write_int(sockfd, HIDE_CONNECT); - - FILE *log_in = fdopen(sockfd, "r"); - char buf[4096]; - while (fgets(buf, sizeof(buf), log_in)) { + auto &queue = start_logging(HIDE_EVENT); + while (true) { char *log; int pid, ppid; struct stat ns, pns; - if ((log = strchr(buf, '[')) == nullptr) + string line = queue.take(); + if ((log = strchr(&line[0], '[')) == nullptr) continue; // Extract pid @@ -183,5 +176,4 @@ void proc_monitor() { if (fork_dont_care() == 0) hide_daemon(pid); } - pthread_exit(nullptr); } diff --git a/native/jni/utils/include/BlockingQueue.h b/native/jni/utils/include/BlockingQueue.h new file mode 100644 index 000000000..38ba0ad0c --- /dev/null +++ b/native/jni/utils/include/BlockingQueue.h @@ -0,0 +1,80 @@ +#pragma once + +#include +#include + +template +class BlockingQueue { + std::deque deque{}; + pthread_mutex_t lock; + pthread_cond_t cond; +public: + BlockingQueue() : lock(PTHREAD_MUTEX_INITIALIZER), cond(PTHREAD_COND_INITIALIZER) {} + ~BlockingQueue(); + T take(); + T &front(); + T &back(); + void put(const T&); + void put(T&&); + template< class... Args > + void emplace_back(Args&&... args); + void clear(); +}; + +template +BlockingQueue::~BlockingQueue() { + pthread_mutex_destroy(&lock); + pthread_cond_destroy(&cond); +} + +template +T BlockingQueue::take() { + pthread_mutex_lock(&lock); + while (deque.empty()) + pthread_cond_wait(&cond, &lock); + T ret(std::move(deque.front())); + deque.pop_front(); + pthread_mutex_unlock(&lock); + return ret; +} + +template +void BlockingQueue::put(const T &s) { + pthread_mutex_lock(&lock); + deque.push_back(s); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); +} + +template +void BlockingQueue::put(T &&s) { + pthread_mutex_lock(&lock); + deque.push_back(std::move(s)); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); +} + +template +T &BlockingQueue::front() { + return deque.front(); +} + +template +T &BlockingQueue::back() { + return deque.back(); +} + +template +template +void BlockingQueue::emplace_back(Args &&... args) { + pthread_mutex_lock(&lock); + deque.emplace_back(std::forward(args)...); + pthread_cond_signal(&cond); + pthread_mutex_unlock(&lock); +} + +template +void BlockingQueue::clear() { + std::deque t; + deque.swap(t); +}