Several MagiskHide improvements
- Directly get UID instead of traversing /data/data everytime - Use /data/user_de/0 instead of /data/data on Android 7.0+ - Update hide_uid set incrementally when adding/initializing targets - Guard hide_uid set with the same lock as hide_list vector - Do not add GMS package into database; only add to in-memory list
This commit is contained in:
parent
24da3485bd
commit
c66cabd80f
@ -17,8 +17,13 @@
|
||||
|
||||
using namespace std;
|
||||
|
||||
vector<string> hide_list;
|
||||
// Protect access to both hide_list and hide_uid
|
||||
pthread_mutex_t list_lock;
|
||||
vector<string> hide_list;
|
||||
set<uid_t> hide_uid;
|
||||
|
||||
// Treat GMS separately as we're only interested in one component
|
||||
int gms_uid = -1;
|
||||
|
||||
static pthread_t proc_monitor_thread;
|
||||
|
||||
@ -157,6 +162,24 @@ static void kill_process(const char *name) {
|
||||
*slash = '/';
|
||||
}
|
||||
|
||||
static int add_pkg_uid(const char *proc) {
|
||||
char path[4096];
|
||||
struct stat st;
|
||||
const char *data = SDK_INT >= 24 ? "/data/user_de/0" : "/data/data";
|
||||
sprintf(path, "%s/%s", data, proc);
|
||||
if (xstat(path, &st) == 0) {
|
||||
hide_uid.insert(st.st_uid);
|
||||
return st.st_uid;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
void refresh_uid() {
|
||||
hide_uid.clear();
|
||||
for (auto &s : hide_list)
|
||||
add_pkg_uid(s.c_str());
|
||||
}
|
||||
|
||||
void clean_magisk_props() {
|
||||
LOGD("hide_utils: Cleaning magisk props\n");
|
||||
getprop([](const char *name, auto, auto) -> void {
|
||||
@ -167,25 +190,25 @@ void clean_magisk_props() {
|
||||
|
||||
int add_list(const char *proc) {
|
||||
for (auto &s : hide_list) {
|
||||
// They should be unique
|
||||
if (s == proc)
|
||||
return HIDE_ITEM_EXIST;
|
||||
}
|
||||
|
||||
LOGI("hide_list add: [%s]\n", proc);
|
||||
|
||||
// Add to database
|
||||
char sql[4096];
|
||||
snprintf(sql, sizeof(sql), "INSERT INTO hidelist (process) VALUES('%s')", proc);
|
||||
char *err = db_exec(sql);
|
||||
db_err_cmd(err, return DAEMON_ERROR);
|
||||
|
||||
LOGI("hide_list add: [%s]\n", proc);
|
||||
|
||||
// Critical region
|
||||
pthread_mutex_lock(&list_lock);
|
||||
hide_list.emplace_back(proc);
|
||||
kill_process(proc);
|
||||
add_pkg_uid(proc);
|
||||
pthread_mutex_unlock(&list_lock);
|
||||
|
||||
kill_process(proc);
|
||||
return DAEMON_SUCCESS;
|
||||
}
|
||||
|
||||
@ -193,29 +216,27 @@ int add_list(int client) {
|
||||
char *proc = read_string(client);
|
||||
int ret = add_list(proc);
|
||||
free(proc);
|
||||
|
||||
// Update inotify list
|
||||
update_apk_list();
|
||||
|
||||
update_inotify_mask();
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int rm_list(const char *proc) {
|
||||
// Update list in critical region
|
||||
bool do_rm = false;
|
||||
// Critical region
|
||||
bool remove = false;
|
||||
pthread_mutex_lock(&list_lock);
|
||||
for (auto it = hide_list.begin(); it != hide_list.end(); ++it) {
|
||||
if (*it == proc) {
|
||||
do_rm = true;
|
||||
remove = true;
|
||||
LOGI("hide_list rm: [%s]\n", proc);
|
||||
hide_list.erase(it);
|
||||
kill_process(proc);
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (remove)
|
||||
refresh_uid();
|
||||
pthread_mutex_unlock(&list_lock);
|
||||
|
||||
if (do_rm) {
|
||||
if (remove) {
|
||||
char sql[4096];
|
||||
snprintf(sql, sizeof(sql), "DELETE FROM hidelist WHERE process='%s'", proc);
|
||||
char *err = db_exec(sql);
|
||||
@ -230,26 +251,30 @@ int rm_list(int client) {
|
||||
char *proc = read_string(client);
|
||||
int ret = rm_list(proc);
|
||||
free(proc);
|
||||
|
||||
// Update inotify list
|
||||
update_apk_list();
|
||||
|
||||
update_inotify_mask();
|
||||
return ret;
|
||||
}
|
||||
|
||||
int init_list(void *, int, char **data, char**) {
|
||||
LOGI("hide_list init: [%s]\n", *data);
|
||||
hide_list.emplace_back(*data);
|
||||
kill_process(*data);
|
||||
int uid = add_pkg_uid(*data);
|
||||
if (strcmp(*data, SAFETYNET_PKG) == 0)
|
||||
gms_uid = uid;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void init_list(const char *proc) {
|
||||
init_list(nullptr, 0, (char **) &proc, nullptr);
|
||||
}
|
||||
|
||||
#define LEGACY_LIST MODULEROOT "/.core/hidelist"
|
||||
|
||||
static int collect_list(void *, int, char **data, char**) {
|
||||
LOGI("hide_list: [%s]\n", data[0]);
|
||||
hide_list.push_back(data[0]);
|
||||
kill_process(data[0]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool init_list() {
|
||||
LOGD("hide_list: initialize\n");
|
||||
|
||||
char *err = db_exec("SELECT process FROM hidelist", collect_list);
|
||||
char *err = db_exec("SELECT process FROM hidelist", init_list);
|
||||
db_err_cmd(err, return false);
|
||||
|
||||
// Migrate old hide list into database
|
||||
@ -260,6 +285,12 @@ bool init_list() {
|
||||
unlink(LEGACY_LIST);
|
||||
}
|
||||
|
||||
// Add SafetyNet by default
|
||||
rm_list(SAFETYNET_PROCESS);
|
||||
rm_list(SAFETYNET_COMPONENT);
|
||||
init_list(SAFETYNET_PKG);
|
||||
|
||||
update_inotify_mask();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -300,11 +331,6 @@ int launch_magiskhide(int client) {
|
||||
if (!init_list())
|
||||
goto error;
|
||||
|
||||
// Add SafetyNet by default
|
||||
rm_list(SAFETYNET_PROCESS);
|
||||
rm_list(SAFETYNET_COMPONENT);
|
||||
add_list(SAFETYNET_PKG);
|
||||
|
||||
// Get thread reference
|
||||
proc_monitor_thread = pthread_self();
|
||||
if (client >= 0) {
|
||||
|
@ -4,6 +4,7 @@
|
||||
#include <pthread.h>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <set>
|
||||
|
||||
#include "daemon.h"
|
||||
|
||||
@ -21,7 +22,7 @@ int rm_list(int client);
|
||||
void ls_list(int client);
|
||||
|
||||
// Update APK list for inotify
|
||||
void update_apk_list();
|
||||
void update_inotify_mask();
|
||||
|
||||
// Process monitor
|
||||
void proc_monitor();
|
||||
@ -30,14 +31,13 @@ void proc_monitor();
|
||||
void manage_selinux();
|
||||
void hide_sensitive_props();
|
||||
void clean_magisk_props();
|
||||
|
||||
// List managements
|
||||
int add_list(const char *proc);
|
||||
bool init_list();
|
||||
void refresh_uid();
|
||||
|
||||
extern bool hide_enabled;
|
||||
extern pthread_mutex_t list_lock;
|
||||
extern std::vector<std::string> hide_list;
|
||||
extern std::set<uid_t> hide_uid;
|
||||
extern int gms_uid;
|
||||
|
||||
enum {
|
||||
LAUNCH_MAGISKHIDE,
|
||||
|
@ -22,7 +22,6 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <set>
|
||||
|
||||
#include <magisk.h>
|
||||
#include <utils.h>
|
||||
@ -33,15 +32,21 @@ using namespace std;
|
||||
|
||||
extern char *system_block, *vendor_block, *data_block;
|
||||
|
||||
static int inotify_fd = -1;
|
||||
|
||||
#define EVENT_SIZE sizeof(struct inotify_event)
|
||||
#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
|
||||
#define __ALIGN_EVENT __attribute__ ((aligned(__alignof__(struct inotify_event))))
|
||||
|
||||
// Workaround for the lack of pthread_cancel
|
||||
static void term_thread(int) {
|
||||
LOGD("proc_monitor: running cleanup\n");
|
||||
hide_list.clear();
|
||||
hide_uid.clear();
|
||||
hide_enabled = false;
|
||||
pthread_mutex_destroy(&list_lock);
|
||||
close(inotify_fd);
|
||||
inotify_fd = -1;
|
||||
LOGD("proc_monitor: terminating\n");
|
||||
pthread_exit(nullptr);
|
||||
}
|
||||
@ -164,21 +169,16 @@ static inline int fast_atoi(const char *str) {
|
||||
static DIR *dfd;
|
||||
// Use unordered map with pid and namespace inode number to avoid time-consuming GC
|
||||
static unordered_map<int, uint64_t> pid_ns_map;
|
||||
// Use set for slow insertion but fast searching(which we'd encounter a lot more)
|
||||
static set<uid_t> hide_uid;
|
||||
// Treat GMS separately as we're only interested in one component
|
||||
static int gms_uid = -1;
|
||||
|
||||
static void detect_new_processes() {
|
||||
struct dirent *dp;
|
||||
struct stat ns, pns;
|
||||
int pid, ppid;
|
||||
bool hide;
|
||||
uid_t uid;
|
||||
unordered_map<int, uint64_t>::const_iterator pos;
|
||||
|
||||
// Iterate through /proc and get a process that reads the target APK
|
||||
rewinddir(dfd);
|
||||
pthread_mutex_lock(&list_lock);
|
||||
while ((dp = readdir(dfd))) {
|
||||
if (!isdigit(dp->d_name[0]))
|
||||
continue;
|
||||
@ -191,23 +191,16 @@ static void detect_new_processes() {
|
||||
continue;
|
||||
|
||||
uid = get_uid(pid) % 100000; // Handle multiuser
|
||||
if (hide_uid.find(uid) != hide_uid.end()) {
|
||||
bool is_target = hide_uid.count(uid) != 0;
|
||||
if (is_target) {
|
||||
// Make sure our target is alive
|
||||
if ((ppid = parse_ppid(pid)) < 0 || read_ns(ppid, &pns) || read_ns(pid, &ns))
|
||||
continue;
|
||||
|
||||
// Check if it's a process we haven't already hijacked
|
||||
hide = false;
|
||||
pos = pid_ns_map.find(pid);
|
||||
if (pos == pid_ns_map.end()) {
|
||||
hide = true;
|
||||
pid_ns_map.insert(pair<int, uint64_t>(pid, ns.st_ino));
|
||||
} else if (pos->second != ns.st_ino) {
|
||||
hide = true;
|
||||
pid_ns_map[pos->first] = ns.st_ino;
|
||||
}
|
||||
|
||||
if (hide) {
|
||||
auto pos = pid_ns_map.find(pid);
|
||||
if (pos == pid_ns_map.end() || pos->second != ns.st_ino) {
|
||||
pid_ns_map[pid] = ns.st_ino;
|
||||
if (uid == gms_uid) {
|
||||
// Check /proc/uid/cmdline to see if it's SAFETYNET_PROCESS
|
||||
if (!is_pid_safetynet_process(pid))
|
||||
@ -231,9 +224,9 @@ static void detect_new_processes() {
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&list_lock);
|
||||
}
|
||||
|
||||
static int inotify_fd = 0;
|
||||
static void listdir_apk(const char *name) {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
@ -260,9 +253,9 @@ static void listdir_apk(const char *name) {
|
||||
// Compare with (path + 10) to trim "/data/app/"
|
||||
if (strncmp(path + 10, s.c_str(), s.length()) == 0) {
|
||||
if (inotify_add_watch(inotify_fd, path, IN_OPEN | IN_DELETE) > 0) {
|
||||
LOGI("proc_monitor: Monitoring %s\n", path, inotify_fd);
|
||||
LOGI("proc_monitor: Monitoring %s\n", path);
|
||||
} else {
|
||||
LOGE("proc_monitor: Failed to monitor %s: %s\n", strerror(errno));
|
||||
LOGE("proc_monitor: Failed to monitor %s: %s\n", path, strerror(errno));
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -275,58 +268,12 @@ static void listdir_apk(const char *name) {
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
static void update_pkg_list() {
|
||||
DIR *dir;
|
||||
struct dirent *entry;
|
||||
struct stat st;
|
||||
char path[4096];
|
||||
const char* target;
|
||||
const char data_path[] = "/data/data";
|
||||
|
||||
if (!(dir = opendir(data_path)))
|
||||
return;
|
||||
|
||||
pthread_mutex_lock(&list_lock);
|
||||
for (auto &s : hide_list)
|
||||
LOGD("proc_monitor: hide_list: %s\n", s.c_str());
|
||||
pthread_mutex_unlock(&list_lock);
|
||||
|
||||
hide_uid.clear();
|
||||
|
||||
while ((entry = readdir(dir)) != NULL) {
|
||||
snprintf(path, sizeof(path), "%s/%s", data_path,
|
||||
entry->d_name);
|
||||
|
||||
if (entry->d_type == DT_DIR) {
|
||||
pthread_mutex_lock(&list_lock);
|
||||
for (auto &s : hide_list) {
|
||||
target = s.c_str();
|
||||
if (strcmp(entry->d_name, target) == 0) {
|
||||
if (stat(path, &st) == -1)
|
||||
continue;
|
||||
|
||||
LOGI("proc_monitor: %s UID is %d\n", target, st.st_uid);
|
||||
hide_uid.insert(st.st_uid);
|
||||
|
||||
if (strcmp(entry->d_name, SAFETYNET_PKG) == 0) {
|
||||
LOGI("proc_monitor: Got GMS: %d\n", st.st_uid);
|
||||
gms_uid = st.st_uid;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&list_lock);
|
||||
}
|
||||
}
|
||||
|
||||
closedir(dir);
|
||||
}
|
||||
|
||||
// Iterate through /data/app and search all .apk files
|
||||
void update_apk_list() {
|
||||
void update_inotify_mask() {
|
||||
// Setup inotify
|
||||
const char data_app[] = "/data/app";
|
||||
|
||||
if (inotify_fd)
|
||||
if (inotify_fd >= 0)
|
||||
close(inotify_fd);
|
||||
|
||||
inotify_fd = inotify_init();
|
||||
@ -344,9 +291,6 @@ void update_apk_list() {
|
||||
} else {
|
||||
LOGE("proc_monitor: Failed to monitor %s: %s\n", strerror(errno));
|
||||
}
|
||||
|
||||
// Update pkg_uid_map by reading from /data/data
|
||||
update_pkg_list();
|
||||
}
|
||||
|
||||
void proc_monitor() {
|
||||
@ -366,8 +310,6 @@ void proc_monitor() {
|
||||
term_thread(TERM_THREAD);
|
||||
}
|
||||
|
||||
update_apk_list();
|
||||
|
||||
if ((dfd = opendir("/proc")) == NULL) {
|
||||
LOGE("proc_monitor: Unable to open /proc\n");
|
||||
term_thread(TERM_THREAD);
|
||||
@ -380,11 +322,11 @@ void proc_monitor() {
|
||||
struct inotify_event *event;
|
||||
ssize_t len;
|
||||
char *p;
|
||||
char buffer[EVENT_BUF_LEN] __attribute__ ((aligned(__alignof__(struct inotify_event))));
|
||||
char buffer[EVENT_BUF_LEN] __ALIGN_EVENT;
|
||||
for (;;) {
|
||||
len = read(inotify_fd, buffer, EVENT_BUF_LEN);
|
||||
if (len == -1) {
|
||||
LOGE("proc_monitor: failed to read from inotify: %s\n", strerror(errno));
|
||||
PLOGE("proc_monitor: read inotify");
|
||||
sleep(1);
|
||||
continue;
|
||||
}
|
||||
@ -399,7 +341,10 @@ void proc_monitor() {
|
||||
detect_new_processes();
|
||||
} else {
|
||||
LOGI("proc_monitor: inotify: /data/app change detected\n");
|
||||
update_apk_list();
|
||||
pthread_mutex_lock(&list_lock);
|
||||
refresh_uid();
|
||||
pthread_mutex_unlock(&list_lock);
|
||||
update_inotify_mask();
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -385,7 +385,7 @@ void write_zero(int fd, size_t size) {
|
||||
}
|
||||
|
||||
vector<string> file_to_vector(const char *filename) {
|
||||
auto arr = vector<string>();
|
||||
vector<string> arr;
|
||||
if (access(filename, R_OK) != 0)
|
||||
return arr;
|
||||
char *line = nullptr;
|
||||
|
Loading…
Reference in New Issue
Block a user