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.
This commit is contained in:
topjohnwu 2019-02-16 02:24:35 -05:00
parent 19ee189468
commit f4f2274c60
6 changed files with 123 additions and 50 deletions

View File

@ -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);
}

View File

@ -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 *

View File

@ -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;
}

View File

@ -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();

View File

@ -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;
}

View File

@ -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);