mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-27 20:15:29 +00:00
Introduce a single general purpose logcat monitor
This commit is contained in:
parent
03c8d716cc
commit
3942858ccd
@ -28,10 +28,6 @@ static int seperate_vendor = 0;
|
||||
|
||||
extern char **environ;
|
||||
|
||||
#ifdef MAGISK_DEBUG
|
||||
static int debug_log_pid, debug_log_fd;
|
||||
#endif
|
||||
|
||||
/******************
|
||||
* Node structure *
|
||||
******************/
|
||||
@ -599,15 +595,8 @@ void post_fs_data(int client) {
|
||||
if (!check_data())
|
||||
goto unblock;
|
||||
|
||||
// Start log monitor
|
||||
monitor_logs();
|
||||
|
||||
#ifdef MAGISK_DEBUG
|
||||
// Log everything initially
|
||||
debug_log_fd = xopen(DEBUG_LOG, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644);
|
||||
xwrite(debug_log_fd, "Boot logs:\n", 11);
|
||||
debug_log_pid = exec_command(0, &debug_log_fd, NULL, "logcat", "-v", "thread", NULL);
|
||||
#endif
|
||||
// Start the debug log
|
||||
start_debug_full_log();
|
||||
|
||||
LOGI("** post-fs-data mode running\n");
|
||||
|
||||
@ -804,12 +793,5 @@ core_only:
|
||||
buf = buf2 = NULL;
|
||||
vec_deep_destroy(&module_list);
|
||||
|
||||
#ifdef MAGISK_DEBUG
|
||||
// Stop recording the boot logcat after every boot task is done
|
||||
kill(debug_log_pid, SIGTERM);
|
||||
waitpid(debug_log_pid, NULL, 0);
|
||||
// Then start to log Magisk verbosely
|
||||
xwrite(debug_log_fd, "\nVerbose logs:\n", 15);
|
||||
debug_log_pid = exec_command(0, &debug_log_fd, NULL, "logcat", "-v", "thread", "-s", "Magisk", NULL);
|
||||
#endif
|
||||
stop_debug_full_log();
|
||||
}
|
||||
|
@ -123,6 +123,9 @@ void start_daemon() {
|
||||
xdup2(fd, STDERR_FILENO);
|
||||
close(fd);
|
||||
|
||||
// Start the log monitor
|
||||
monitor_logs();
|
||||
|
||||
// Patch selinux with medium patch before we do anything
|
||||
load_policydb(SELINUX_POLICY);
|
||||
sepol_med_rules();
|
||||
|
@ -1,8 +1,8 @@
|
||||
/* log_monitor.c - New thread to monitor logcat
|
||||
*
|
||||
* Open a new thread to call logcat and get logs with tag "Magisk"
|
||||
* Also, write the logs to a log file for debugging purpose
|
||||
*
|
||||
* A universal logcat monitor for many usages. Add listeners to the list,
|
||||
* and the pointer of the new log line will be sent through pipes to trigger
|
||||
* asynchronous events without polling
|
||||
*/
|
||||
|
||||
#include <stdio.h>
|
||||
@ -13,33 +13,150 @@
|
||||
|
||||
#include "magisk.h"
|
||||
#include "utils.h"
|
||||
#include "daemon.h"
|
||||
|
||||
int logcat_events[] = { -1, -1, -1 };
|
||||
|
||||
static int is_restart = 0;
|
||||
|
||||
#ifdef MAGISK_DEBUG
|
||||
static int debug_log_pid, debug_log_fd;
|
||||
#endif
|
||||
|
||||
static void *logger_thread(void *args) {
|
||||
// Setup error handler
|
||||
err_handler = exit_thread;
|
||||
|
||||
rename(LOGFILE, LASTLOG);
|
||||
int log_fd, log_pid;
|
||||
|
||||
log_fd = xopen(LOGFILE, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644);
|
||||
int log_fd = -1, log_pid;
|
||||
char line[4096];
|
||||
|
||||
while (1) {
|
||||
// Clear buffer
|
||||
exec_command_sync("logcat", "-b", "all", "-c", NULL);
|
||||
// Start logcat
|
||||
log_pid = exec_command(0, &log_fd, NULL, "logcat", "-v", "thread", "Magisk:I", "*:S", NULL);
|
||||
if (log_pid > 0)
|
||||
waitpid(log_pid, NULL, 0);
|
||||
// For some reason it went here, clear buffer and restart
|
||||
exec_command_sync("logcat", "-c", NULL);
|
||||
log_pid = exec_command(0, &log_fd, NULL, "logcat", "-b", "events", "-b", "default", "-s", "am_proc_start", "Magisk", NULL);
|
||||
while (fdgets(line, sizeof(line), log_fd)) {
|
||||
for (int i = 0; i < (sizeof(logcat_events) / sizeof(int)); ++i) {
|
||||
if (logcat_events[i] > 0) {
|
||||
char *s = strdup(line);
|
||||
xwrite(logcat_events[i], &s, sizeof(s));
|
||||
}
|
||||
}
|
||||
if (kill(log_pid, 0))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Should never be here, but well...
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Start a new thread to monitor logcat and dump to logfile */
|
||||
static void *magisk_log_thread(void *args) {
|
||||
// Setup error handler
|
||||
err_handler = exit_thread;
|
||||
|
||||
int have_data = 0;
|
||||
|
||||
// Temp buffer for logs before we have data access
|
||||
struct vector logs;
|
||||
vec_init(&logs);
|
||||
|
||||
FILE *log;
|
||||
int pipefd[2];
|
||||
if (xpipe2(pipefd, O_CLOEXEC) == -1)
|
||||
return NULL;
|
||||
|
||||
// Register our listener
|
||||
logcat_events[LOG_EVENT] = pipefd[1];
|
||||
|
||||
for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line)) {
|
||||
char *ss;
|
||||
if ((ss = strstr(line, " Magisk")) && (ss[-1] != 'D') && (ss[-1] != 'V')) {
|
||||
if (!have_data) {
|
||||
if ((have_data = check_data())) {
|
||||
// Dump buffered logs to file
|
||||
if (!is_restart)
|
||||
rename(LOGFILE, LASTLOG);
|
||||
log = xfopen(LOGFILE, "a");
|
||||
setbuf(log, NULL);
|
||||
char *tmp;
|
||||
vec_for_each(&logs, tmp) {
|
||||
fprintf(log, "%s", tmp);
|
||||
free(tmp);
|
||||
}
|
||||
vec_destroy(&logs);
|
||||
} else {
|
||||
vec_push_back(&logs, line);
|
||||
}
|
||||
}
|
||||
if (have_data)
|
||||
fprintf(log, "%s", line);
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void *debug_magisk_log_thread(void *args) {
|
||||
// Setup error handler
|
||||
err_handler = exit_thread;
|
||||
|
||||
FILE *log = xfopen(DEBUG_LOG, "a");
|
||||
setbuf(log, NULL);
|
||||
int pipefd[2];
|
||||
if (xpipe2(pipefd, O_CLOEXEC) == -1)
|
||||
return NULL;
|
||||
|
||||
// Register our listener
|
||||
logcat_events[DEBUG_EVENT] = pipefd[1];
|
||||
|
||||
for (char *line; xxread(pipefd[0], &line, sizeof(line)) > 0; free(line)) {
|
||||
char *ss;
|
||||
if ((ss = strstr(line, "Magisk")))
|
||||
fprintf(log, "%s", line);
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Start new threads to monitor logcat and dump to logfile */
|
||||
void monitor_logs() {
|
||||
pthread_t thread;
|
||||
xpthread_create(&thread, NULL, logger_thread, NULL);
|
||||
|
||||
is_restart = check_data();
|
||||
|
||||
// Start log file dumper before monitor
|
||||
xpthread_create(&thread, NULL, magisk_log_thread, NULL);
|
||||
pthread_detach(thread);
|
||||
|
||||
#ifdef MAGISK_DEBUG
|
||||
if (is_restart) {
|
||||
// Restart debug logs
|
||||
xpthread_create(&thread, NULL, debug_magisk_log_thread, NULL);
|
||||
pthread_detach(thread);
|
||||
}
|
||||
#endif
|
||||
|
||||
// Start logcat monitor
|
||||
xpthread_create(&thread, NULL, logger_thread, NULL);
|
||||
pthread_detach(thread);
|
||||
|
||||
}
|
||||
|
||||
void start_debug_full_log() {
|
||||
#ifdef MAGISK_DEBUG
|
||||
// Log everything initially
|
||||
debug_log_fd = xopen(DEBUG_LOG, O_WRONLY | O_CREAT | O_CLOEXEC | O_TRUNC, 0644);
|
||||
debug_log_pid = exec_command(0, &debug_log_fd, NULL, "logcat", NULL);
|
||||
close(debug_log_fd);
|
||||
#endif
|
||||
}
|
||||
|
||||
void stop_debug_full_log() {
|
||||
#ifdef MAGISK_DEBUG
|
||||
// Stop recording the boot logcat after every boot task is done
|
||||
kill(debug_log_pid, SIGTERM);
|
||||
waitpid(debug_log_pid, NULL, 0);
|
||||
pthread_t thread;
|
||||
// Start debug thread
|
||||
xpthread_create(&thread, NULL, debug_magisk_log_thread, NULL);
|
||||
pthread_detach(thread);
|
||||
#endif
|
||||
}
|
||||
|
@ -50,10 +50,6 @@ void write_int(int fd, int val);
|
||||
char* read_string(int fd);
|
||||
void write_string(int fd, const char* val);
|
||||
|
||||
// log_monitor.c
|
||||
|
||||
void monitor_logs();
|
||||
|
||||
/***************
|
||||
* Boot Stages *
|
||||
***************/
|
||||
|
@ -34,6 +34,17 @@ static inline void do_nothing() {}
|
||||
|
||||
#define PLOGE(fmt, args...) { LOGE(fmt " failed with %d: %s", ##args, errno, strerror(errno)); err_handler(); }
|
||||
|
||||
enum {
|
||||
HIDE_EVENT,
|
||||
LOG_EVENT,
|
||||
DEBUG_EVENT
|
||||
};
|
||||
extern int logcat_events[];
|
||||
|
||||
void monitor_logs();
|
||||
void start_debug_full_log();
|
||||
void stop_debug_full_log();
|
||||
|
||||
#else // IS_DAEMON
|
||||
|
||||
#include <stdio.h>
|
||||
|
@ -90,6 +90,7 @@ void fclone_attr(const int sourcefd, const int targetfd);
|
||||
void clone_attr(const char *source, const char *target);
|
||||
void get_client_cred(int fd, struct ucred *cred);
|
||||
int switch_mnt_ns(int pid);
|
||||
int fork_dont_care();
|
||||
|
||||
// img.c
|
||||
|
||||
|
@ -19,27 +19,20 @@
|
||||
#include "utils.h"
|
||||
#include "magiskhide.h"
|
||||
|
||||
static int zygote_num;
|
||||
static char init_ns[32], zygote_ns[2][32], cache_block[256];
|
||||
static int log_pid, log_fd, target_pid, has_cache = 1;
|
||||
static char *buffer;
|
||||
static int zygote_num, has_cache = 1, pipefd[2] = { -1, -1 };
|
||||
|
||||
// Workaround for the lack of pthread_cancel
|
||||
static void quit_pthread(int sig) {
|
||||
err_handler = do_nothing;
|
||||
LOGD("proc_monitor: running cleanup\n");
|
||||
destroy_list();
|
||||
free(buffer);
|
||||
hideEnabled = 0;
|
||||
// Kill the logging if needed
|
||||
if (log_pid > 0) {
|
||||
kill(log_pid, SIGTERM);
|
||||
waitpid(log_pid, NULL, 0);
|
||||
close(log_fd);
|
||||
}
|
||||
// Resume process if possible
|
||||
if (target_pid > 0)
|
||||
kill(target_pid, SIGCONT);
|
||||
// Unregister listener
|
||||
logcat_events[HIDE_EVENT] = -1;
|
||||
close(pipefd[0]);
|
||||
close(pipefd[1]);
|
||||
pipefd[0] = pipefd[1] = -1;
|
||||
pthread_mutex_destroy(&hide_lock);
|
||||
pthread_mutex_destroy(&file_lock);
|
||||
LOGD("proc_monitor: terminating...\n");
|
||||
@ -47,7 +40,7 @@ static void quit_pthread(int sig) {
|
||||
}
|
||||
|
||||
static void proc_monitor_err() {
|
||||
LOGD("proc_monitor: error occured, stopping magiskhide services\n");
|
||||
LOGE("proc_monitor: error occured, stopping magiskhide services\n");
|
||||
quit_pthread(SIGUSR1);
|
||||
}
|
||||
|
||||
@ -77,25 +70,24 @@ static void lazy_unmount(const char* mountpoint) {
|
||||
}
|
||||
|
||||
static void hide_daemon_err() {
|
||||
LOGD("hide_daemon: error occured, stopping magiskhide services\n");
|
||||
_exit(-1);
|
||||
LOGE("hide_daemon: error occured\n");
|
||||
}
|
||||
|
||||
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
|
||||
// When an error occurs, report its failure
|
||||
err_handler = hide_daemon_err;
|
||||
|
||||
char *line;
|
||||
char *line, buffer[PATH_MAX];
|
||||
struct vector mount_list;
|
||||
|
||||
manage_selinux();
|
||||
clean_magisk_props();
|
||||
|
||||
if (switch_mnt_ns(pid))
|
||||
return;
|
||||
goto exit;
|
||||
|
||||
snprintf(buffer, PATH_MAX, "/proc/%d/mounts", pid);
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
||||
vec_init(&mount_list);
|
||||
file_to_vector(buffer, &mount_list);
|
||||
|
||||
@ -132,7 +124,7 @@ static void hide_daemon(int pid) {
|
||||
vec_destroy(&mount_list);
|
||||
|
||||
// Re-read mount infos
|
||||
snprintf(buffer, PATH_MAX, "/proc/%d/mounts", pid);
|
||||
snprintf(buffer, sizeof(buffer), "/proc/%d/mounts", pid);
|
||||
vec_init(&mount_list);
|
||||
file_to_vector(buffer, &mount_list);
|
||||
|
||||
@ -145,8 +137,12 @@ static void hide_daemon(int pid) {
|
||||
free(line);
|
||||
}
|
||||
|
||||
// Free uo memory
|
||||
exit:
|
||||
// Send resume signal
|
||||
kill(pid, SIGCONT);
|
||||
// Free up memory
|
||||
vec_destroy(&mount_list);
|
||||
_exit(0);
|
||||
}
|
||||
|
||||
void proc_monitor() {
|
||||
@ -158,9 +154,7 @@ void proc_monitor() {
|
||||
|
||||
// The error handler should stop magiskhide services
|
||||
err_handler = proc_monitor_err;
|
||||
log_pid = target_pid = -1;
|
||||
|
||||
buffer = xmalloc(PATH_MAX);
|
||||
cache_block[0] = '\0';
|
||||
|
||||
// Get the mount namespace of init
|
||||
@ -188,20 +182,15 @@ void proc_monitor() {
|
||||
break;
|
||||
}
|
||||
|
||||
while (1) {
|
||||
// Clear previous logcat buffer
|
||||
exec_command_sync("logcat", "-b", "events", "-c", NULL);
|
||||
// Register our listener to logcat monitor
|
||||
xpipe2(pipefd, O_CLOEXEC);
|
||||
logcat_events[HIDE_EVENT] = pipefd[1];
|
||||
|
||||
// Monitor am_proc_start
|
||||
log_fd = -1;
|
||||
log_pid = exec_command(0, &log_fd, NULL, "logcat", "-b", "events", "-v", "raw", "-s", "am_proc_start", NULL);
|
||||
|
||||
if (log_pid < 0) continue;
|
||||
if (kill(log_pid, 0)) continue;
|
||||
|
||||
while(fdgets(buffer, PATH_MAX, log_fd)) {
|
||||
for (char *log, *line; xxread(pipefd[0], &log, sizeof(log)) > 0; free(log)) {
|
||||
char *ss;
|
||||
if ((ss = strstr(log, "am_proc_start")) && (ss = strchr(ss, '['))) {
|
||||
int pid, ret, comma = 0;
|
||||
char *pos = buffer, *line, processName[256];
|
||||
char *pos = ss, processName[256], ns[32];
|
||||
|
||||
while(1) {
|
||||
pos = strchr(pos, ',');
|
||||
@ -212,9 +201,9 @@ void proc_monitor() {
|
||||
}
|
||||
|
||||
if (comma == 6)
|
||||
ret = sscanf(buffer, "[%*d %d %*d %*d %256s", &pid, processName);
|
||||
ret = sscanf(ss, "[%*d %d %*d %*d %256s", &pid, processName);
|
||||
else
|
||||
ret = sscanf(buffer, "[%*d %d %*d %256s", &pid, processName);
|
||||
ret = sscanf(ss, "[%*d %d %*d %256s", &pid, processName);
|
||||
|
||||
if(ret != 2)
|
||||
continue;
|
||||
@ -225,12 +214,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(target_pid, buffer, 32);
|
||||
if (strcmp(buffer, zygote_ns[i]) == 0) {
|
||||
read_namespace(pid, ns, sizeof(ns));
|
||||
if (strcmp(ns, zygote_ns[i]) == 0) {
|
||||
usleep(50);
|
||||
ret = 0;
|
||||
break;
|
||||
@ -240,43 +228,21 @@ void proc_monitor() {
|
||||
}
|
||||
|
||||
// Send pause signal ASAP
|
||||
if (kill(target_pid, SIGSTOP) == -1) continue;
|
||||
if (kill(pid, SIGSTOP) == -1) continue;
|
||||
|
||||
LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, target_pid, buffer);
|
||||
LOGI("proc_monitor: %s (PID=%d ns=%s)\n", processName, pid, ns);
|
||||
|
||||
/*
|
||||
* 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;
|
||||
}
|
||||
if (fork_dont_care() == 0)
|
||||
hide_daemon(pid);
|
||||
|
||||
// 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);
|
||||
}
|
||||
|
||||
// For some reason it went here, restart logging
|
||||
kill(log_pid, SIGTERM);
|
||||
waitpid(log_pid, NULL, 0);
|
||||
close(log_fd);
|
||||
}
|
||||
}
|
||||
|
@ -408,3 +408,14 @@ int switch_mnt_ns(int pid) {
|
||||
close(fd);
|
||||
return ret;
|
||||
}
|
||||
|
||||
int fork_dont_care() {
|
||||
int pid = fork();
|
||||
if (pid) {
|
||||
waitpid(pid, NULL, 0);
|
||||
return pid;
|
||||
} else if ((pid = fork())) {
|
||||
exit(0);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user