Commit 7384d2d3 authored by Park Ju Hyung's avatar Park Ju Hyung Committed by John Wu

Completely rework MagiskHide

Previous MagiskHide detects new app launches via listening through logcat
and filtering launch info messages.

This is extremely inefficient and prone to cause multiple issues both
theoratically and practically.

Rework this by using inotify to detect open() syscalls to target APKs.

This also solves issues related to Zygote-forked caching mechanisms such as
OnePlus OxygenOS' embryo.
Signed-off-by: 's avatarPark Ju Hyung <qkrwngud825@gmail.com>
parent e5940168
...@@ -35,7 +35,6 @@ LOCAL_SRC_FILES := \ ...@@ -35,7 +35,6 @@ LOCAL_SRC_FILES := \
core/applets.cpp \ core/applets.cpp \
core/magisk.cpp \ core/magisk.cpp \
core/daemon.cpp \ core/daemon.cpp \
core/logcat.cpp \
core/bootstages.cpp \ core/bootstages.cpp \
core/socket.cpp \ core/socket.cpp \
core/db.cpp \ core/db.cpp \
......
...@@ -22,7 +22,6 @@ ...@@ -22,7 +22,6 @@
#include <daemon.h> #include <daemon.h>
#include <resetprop.h> #include <resetprop.h>
#include <selinux.h> #include <selinux.h>
#include <logcat.h>
#include <flags.h> #include <flags.h>
using namespace std; using namespace std;
...@@ -699,8 +698,6 @@ void post_fs_data(int client) { ...@@ -699,8 +698,6 @@ void post_fs_data(int client) {
unblock_boot_process(); unblock_boot_process();
} }
start_logcat();
LOGI("* Running post-fs-data.d scripts\n"); LOGI("* Running post-fs-data.d scripts\n");
exec_common_script("post-fs-data"); exec_common_script("post-fs-data");
......
#include <sys/wait.h>
#include <sys/types.h>
#include <signal.h>
#include <time.h>
#include <vector>
#include <logcat.h>
#include <utils.h>
#include <logging.h>
#include <magisk.h>
static std::vector<const char *> log_cmd;
static pthread_mutex_t event_lock = PTHREAD_MUTEX_INITIALIZER;
static time_t LAST_TIMESTAMP = 0;
bool logcat_started = false;
struct log_listener {
bool enable = false;
bool (*filter)(const char *);
BlockingQueue<std::string> queue;
};
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 *buffers[] = { "main", "events", "crash" };
for (auto b : buffers) {
if (exec_command_sync(MIRRDIR "/system/bin/logcat", "-b", b, "-d", "-f", "/dev/null") == 0) {
log_cmd.push_back("-b");
log_cmd.push_back(b);
}
}
chmod("/dev/null", 0666);
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);
}
static bool test_logcat() {
int test = exec_command_sync(MIRRDIR "/system/bin/logcat", "-d", "-f", "/dev/null");
chmod("/dev/null", 0666);
return test == 0;
}
static void *logcat_gobbler(void *) {
int log_pid;
char line[4096];
struct tm tm{};
time_t prev;
// Set tm year info
time_t now = time(nullptr);
localtime_r(&now, &tm);
while (true) {
prev = 0;
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;
// Parse timestamp
strptime(line, "%m-%d %H:%M:%S", &tm);
now = mktime(&tm);
if (now < prev) {
/* Log timestamps should be monotonic increasing, if this happens,
* it means that we occur the super rare case: crossing year boundary
* (e.g 2019 -> 2020). Reset and reparse timestamp */
now = time(nullptr);
localtime_r(&now, &tm);
strptime(line, "%m-%d %H:%M:%S", &tm);
now = mktime(&tm);
}
// Skip old logs
if (now < LAST_TIMESTAMP)
continue;
LAST_TIMESTAMP = prev = now;
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("logcat: unexpected output EOF");
// Wait a few seconds and retry
sleep(2);
if (!test_logcat()) {
// Cancel all events and terminate
logcat_started = false;
for (auto &event : events)
event.queue.cancel();
return nullptr;
}
}
}
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<std::string> &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;
if (!test_logcat())
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;
}
#pragma once
#include <string>
#include <BlockingQueue.h>
enum logcat_event {
HIDE_EVENT,
LOG_EVENT
};
extern bool logcat_started;
BlockingQueue<std::string> &start_logging(logcat_event event);
void stop_logging(logcat_event event);
bool start_logcat();
...@@ -12,7 +12,6 @@ ...@@ -12,7 +12,6 @@
#include <utils.h> #include <utils.h>
#include <resetprop.h> #include <resetprop.h>
#include <db.h> #include <db.h>
#include <logcat.h>
#include "magiskhide.h" #include "magiskhide.h"
...@@ -197,6 +196,10 @@ int add_list(int client) { ...@@ -197,6 +196,10 @@ int add_list(int client) {
char *proc = read_string(client); char *proc = read_string(client);
int ret = add_list(proc); int ret = add_list(proc);
free(proc); free(proc);
// Update inotify list
update_apk_list();
return ret; return ret;
} }
...@@ -230,6 +233,10 @@ int rm_list(int client) { ...@@ -230,6 +233,10 @@ int rm_list(int client) {
char *proc = read_string(client); char *proc = read_string(client);
int ret = rm_list(proc); int ret = rm_list(proc);
free(proc); free(proc);
// Update inotify list
update_apk_list();
return ret; return ret;
} }
...@@ -283,9 +290,6 @@ int launch_magiskhide(int client) { ...@@ -283,9 +290,6 @@ int launch_magiskhide(int client) {
if (hide_enabled) if (hide_enabled)
return HIDE_IS_ENABLED; return HIDE_IS_ENABLED;
if (!logcat_started)
return LOGCAT_DISABLED;
hide_enabled = true; hide_enabled = true;
set_hide_config(); set_hide_config();
LOGI("* Starting MagiskHide\n"); LOGI("* Starting MagiskHide\n");
...@@ -328,8 +332,6 @@ int stop_magiskhide() { ...@@ -328,8 +332,6 @@ int stop_magiskhide() {
} }
void auto_start_magiskhide() { void auto_start_magiskhide() {
if (!start_logcat())
return;
db_settings dbs; db_settings dbs;
get_db_settings(&dbs, HIDE_CONFIG); get_db_settings(&dbs, HIDE_CONFIG);
if (dbs[HIDE_CONFIG]) { if (dbs[HIDE_CONFIG]) {
......
...@@ -110,9 +110,6 @@ int magiskhide_main(int argc, char *argv[]) { ...@@ -110,9 +110,6 @@ int magiskhide_main(int argc, char *argv[]) {
switch (code) { switch (code) {
case DAEMON_SUCCESS: case DAEMON_SUCCESS:
break; break;
case LOGCAT_DISABLED:
fprintf(stderr, "Logcat is disabled, cannot start MagiskHide\n");
break;
case HIDE_NOT_ENABLED: case HIDE_NOT_ENABLED:
fprintf(stderr, "MagiskHide is not enabled\n"); fprintf(stderr, "MagiskHide is not enabled\n");
break; break;
......
...@@ -16,6 +16,9 @@ int add_list(int client); ...@@ -16,6 +16,9 @@ int add_list(int client);
int rm_list(int client); int rm_list(int client);
void ls_list(int client); void ls_list(int client);
// Update APK list for inotify
void update_apk_list();
// Process monitor // Process monitor
void proc_monitor(); void proc_monitor();
...@@ -42,8 +45,7 @@ enum { ...@@ -42,8 +45,7 @@ enum {
}; };
enum { enum {
LOGCAT_DISABLED = DAEMON_LAST, HIDE_IS_ENABLED = DAEMON_LAST,
HIDE_IS_ENABLED,
HIDE_NOT_ENABLED, HIDE_NOT_ENABLED,
HIDE_ITEM_EXIST, HIDE_ITEM_EXIST,
HIDE_ITEM_NOT_EXIST HIDE_ITEM_NOT_EXIST
......
This diff is collapsed.
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment