Commit f4f2274c authored by topjohnwu's avatar topjohnwu

Auto reinstall system apps on hide list

Since we are parsing through /data/app/ to find target APKs for
monitoring, system apps will not be covered in this case.
Automatically reinstall system apps as if they received an update
and refresh the monitor target after it's done.

As a bonus, use RAII idioms for locking pthread_mutex_t.
parent 19ee1894
......@@ -72,7 +72,7 @@ void exec_module_script(const char *stage, const vector<string> &module_list) {
}
static const char migrate_script[] =
"IMG=%s;"
"IMG=/data/adb/tmp.img;"
"MNT=/dev/img_mnt;"
"e2fsck -yf $IMG;"
"mkdir -p $MNT;"
......@@ -91,27 +91,54 @@ static const char migrate_script[] =
void migrate_img(const char *img) {
LOGI("* Migrating %s\n", img);
exec_t exec { .pre_exec = set_path };
char cmds[sizeof(migrate_script) + 32];
sprintf(cmds, migrate_script, img);
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
rename(img, "/data/adb/tmp.img");
exec_command_sync(exec, "/system/bin/sh", "-c", migrate_script);
}
static const char install_script[] =
"APK=%s;"
"while true; do"
" OUT=`pm install -r $APK`;"
" OUT=`pm install -r $APK 2>&1`;"
" log -t Magisk \"apk_install: $OUT\";"
" if echo \"$OUT\" | grep -q 'Error:'; then"
" if echo \"$OUT\" | grep -qE \"Can't|Error:\"; then"
" sleep 5;"
" continue;"
" fi;"
" break;"
"done";
"done;"
"rm -f $APK";
void install_apk(const char *apk) {
setfilecon(apk, "u:object_r:" SEPOL_FILE_DOMAIN ":s0");
LOGI("apk_install: %s\n", apk);
exec_t exec { .pre_exec = set_mirror_path };
char cmds[sizeof(install_script) + 4096];
sprintf(cmds, "APK=%s;%s;rm -f $APK", apk, install_script);
exec_command_sync(exec, "/system/bin/sh", "-c", cmds);
sprintf(cmds, install_script, apk);
exec_command_sync(exec, MIRRDIR "/system/bin/sh", "-c", cmds);
}
static const char reinstall_script[] =
"PKG=%s;"
"while true; do"
" OUT=`pm path $PKG 2>&1`;"
" [ -z $OUT ] && exit 1;"
" if echo \"$OUT\" | grep -qE \"Can't|Error:\"; then"
" sleep 5;"
" continue;"
" fi;"
" APK=`echo $OUT | cut -d':' -f2`;"
" log -t Magisk \"apk_install: $APK\";"
" OUT=`pm install -r $APK`;"
" [ $? -eq 0 ] || exit 1;"
" log -t Magisk \"apk_install: $OUT\";"
" break;"
"done;"
"exit 0";
// Reinstall system apps to data
int reinstall_apk(const char *pkg) {
exec_t exec { .pre_exec = set_mirror_path };
char cmds[sizeof(reinstall_script) + 256];
sprintf(cmds, reinstall_script, pkg);
return exec_command_sync(exec, MIRRDIR "/system/bin/sh", "-c", cmds);
}
......@@ -72,6 +72,7 @@ void exec_common_script(const char *stage);
void exec_module_script(const char *stage, const std::vector<std::string> &module_list);
void migrate_img(const char *img);
void install_apk(const char *apk);
int reinstall_apk(const char *pkg);
/**************
* MagiskHide *
......
......@@ -188,10 +188,12 @@ int add_list(const char *pkg) {
LOGI("hide_list add: [%s]\n", pkg);
// Critical region
pthread_mutex_lock(&list_lock);
hide_list.emplace_back(pkg);
int uid = add_pkg_uid(pkg);
pthread_mutex_unlock(&list_lock);
int uid;
{
MutexGuard lock(list_lock);
hide_list.emplace_back(pkg);
uid = add_pkg_uid(pkg);
}
kill_process(uid);
return DAEMON_SUCCESS;
......@@ -207,36 +209,33 @@ int add_list(int client) {
static int rm_list(const char *pkg) {
// Critical region
bool remove = false;
pthread_mutex_lock(&list_lock);
for (auto it = hide_list.begin(); it != hide_list.end(); ++it) {
if (*it == pkg) {
remove = true;
LOGI("hide_list rm: [%s]\n", pkg);
hide_list.erase(it);
break;
{
MutexGuard lock(list_lock);
bool remove = false;
for (auto it = hide_list.begin(); it != hide_list.end(); ++it) {
if (*it == pkg) {
remove = true;
LOGI("hide_list rm: [%s]\n", pkg);
hide_list.erase(it);
break;
}
}
if (!remove)
return HIDE_ITEM_NOT_EXIST;
}
if (remove)
refresh_uid();
pthread_mutex_unlock(&list_lock);
if (remove) {
char sql[4096];
snprintf(sql, sizeof(sql), "DELETE FROM hidelist WHERE process='%s'", pkg);
char *err = db_exec(sql);
db_err(err);
return DAEMON_SUCCESS;
} else {
return HIDE_ITEM_NOT_EXIST;
}
char sql[4096];
snprintf(sql, sizeof(sql), "DELETE FROM hidelist WHERE process='%s'", pkg);
char *err = db_exec(sql);
db_err(err);
return DAEMON_SUCCESS;
}
int rm_list(int client) {
char *pkg = read_string(client);
int ret = rm_list(pkg);
free(pkg);
update_inotify_mask();
if (ret == DAEMON_SUCCESS)
update_inotify_mask(true);
return ret;
}
......
......@@ -26,7 +26,7 @@ int rm_list(int client);
void ls_list(int client);
// Update APK list for inotify
void update_inotify_mask();
void update_inotify_mask(bool refresh = false);
// Process monitor
void proc_monitor();
......
......@@ -205,6 +205,8 @@ static char *append_path(char *eof, const char *name) {
#define DATA_APP "/data/app"
static int new_inotify;
static int data_app_wd;
static vector<bool> app_in_data;
static void find_apks(char *path, char *eof) {
DIR *dir = opendir(path);
if (dir == nullptr)
......@@ -225,11 +227,12 @@ static void find_apks(char *path, char *eof) {
if ((dash = strchr(path, '-')) == nullptr)
continue;
*dash = '\0';
for (auto &s : hide_list) {
if (s == path + sizeof(DATA_APP)) {
for (int i = 0; i < hide_list.size(); ++i) {
if (hide_list[i] == path + sizeof(DATA_APP)) {
*dash = '-';
append_path(eof, entry->d_name);
xinotify_add_watch(new_inotify, path, IN_OPEN | IN_DELETE);
app_in_data[i] = true;
break;
}
}
......@@ -241,7 +244,7 @@ static void find_apks(char *path, char *eof) {
}
// Iterate through /data/app and search all .apk files
void update_inotify_mask() {
void update_inotify_mask(bool refresh) {
char buf[4096];
new_inotify = inotify_init();
......@@ -252,12 +255,41 @@ void update_inotify_mask() {
LOGI("proc_monitor: Updating inotify list\n");
strcpy(buf, DATA_APP);
pthread_mutex_lock(&list_lock);
find_apks(buf, buf + sizeof(DATA_APP) - 1);
pthread_mutex_unlock(&list_lock);
app_in_data.clear();
bool reinstall = false;
{
MutexGuard lock(list_lock);
app_in_data.resize(hide_list.size(), false);
find_apks(buf, buf + sizeof(DATA_APP) - 1);
// Stop monitoring /data/app
if (inotify_fd >= 0)
inotify_rm_watch(inotify_fd, data_app_wd);
// All apps on the hide list should be installed in data
auto it = hide_list.begin();
for (bool in_data : app_in_data) {
if (!in_data) {
if (reinstall_apk(it->c_str()) != 0) {
// Reinstallation failed, remove from hide list
hide_list.erase(it);
refresh = true;
continue;
}
reinstall = true;
}
it++;
}
if (refresh && !reinstall)
refresh_uid();
}
if (reinstall) {
// Rerun detection
close(new_inotify);
update_inotify_mask(refresh);
return;
}
// Add /data/app itself to the watch list to detect app (un)installations/updates
xinotify_add_watch(new_inotify, DATA_APP, IN_CLOSE_WRITE | IN_MOVED_TO | IN_DELETE);
data_app_wd = xinotify_add_watch(new_inotify, DATA_APP, IN_CLOSE_WRITE | IN_MOVED_TO | IN_DELETE);
int tmp = inotify_fd;
inotify_fd = new_inotify;
......@@ -289,15 +321,11 @@ void proc_monitor() {
if (event->mask & IN_OPEN) {
// Since we're just watching files,
// extracting file name is not possible from querying event
pthread_mutex_lock(&list_lock);
MutexGuard lock(list_lock);
crawl_procfs(process_pid);
pthread_mutex_unlock(&list_lock);
} else {
} else if (!(event->mask & IN_IGNORED)) {
LOGI("proc_monitor: inotify: /data/app change detected\n");
pthread_mutex_lock(&list_lock);
refresh_uid();
pthread_mutex_unlock(&list_lock);
update_inotify_mask();
update_inotify_mask(true);
break;
}
......
......@@ -150,6 +150,24 @@ std::vector<std::string> file_to_vector(const char *filename);
// misc.cpp
class MutexGuard {
public:
explicit MutexGuard(pthread_mutex_t &m): mutex(&m) {
pthread_mutex_lock(mutex);
}
explicit MutexGuard(pthread_mutex_t *m): mutex(m) {
pthread_mutex_lock(mutex);
}
~MutexGuard() {
pthread_mutex_unlock(mutex);
}
private:
pthread_mutex_t *mutex;
};
int new_daemon_thread(void *(*start_routine) (void *), void *arg = nullptr,
const pthread_attr_t *attr = nullptr);
......
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