From f4f2274c604431884ee888365b6b0784c2575c5f Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 16 Feb 2019 02:24:35 -0500 Subject: [PATCH] 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. --- native/jni/core/scripting.cpp | 45 ++++++++++++++++----- native/jni/include/daemon.h | 1 + native/jni/magiskhide/hide_utils.cpp | 51 ++++++++++++----------- native/jni/magiskhide/magiskhide.h | 2 +- native/jni/magiskhide/proc_monitor.cpp | 56 +++++++++++++++++++------- native/jni/utils/include/utils.h | 18 +++++++++ 6 files changed, 123 insertions(+), 50 deletions(-) diff --git a/native/jni/core/scripting.cpp b/native/jni/core/scripting.cpp index fe7b8872d..addbaab97 100644 --- a/native/jni/core/scripting.cpp +++ b/native/jni/core/scripting.cpp @@ -72,7 +72,7 @@ void exec_module_script(const char *stage, const vector &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); } diff --git a/native/jni/include/daemon.h b/native/jni/include/daemon.h index 85df78c9b..abd9d2652 100644 --- a/native/jni/include/daemon.h +++ b/native/jni/include/daemon.h @@ -72,6 +72,7 @@ void exec_common_script(const char *stage); void exec_module_script(const char *stage, const std::vector &module_list); void migrate_img(const char *img); void install_apk(const char *apk); +int reinstall_apk(const char *pkg); /************** * MagiskHide * diff --git a/native/jni/magiskhide/hide_utils.cpp b/native/jni/magiskhide/hide_utils.cpp index 4082fc9ab..d36b5f142 100644 --- a/native/jni/magiskhide/hide_utils.cpp +++ b/native/jni/magiskhide/hide_utils.cpp @@ -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; } diff --git a/native/jni/magiskhide/magiskhide.h b/native/jni/magiskhide/magiskhide.h index 1d0a638da..8699c419a 100644 --- a/native/jni/magiskhide/magiskhide.h +++ b/native/jni/magiskhide/magiskhide.h @@ -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(); diff --git a/native/jni/magiskhide/proc_monitor.cpp b/native/jni/magiskhide/proc_monitor.cpp index b89fe3972..599c61d3c 100644 --- a/native/jni/magiskhide/proc_monitor.cpp +++ b/native/jni/magiskhide/proc_monitor.cpp @@ -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 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; } diff --git a/native/jni/utils/include/utils.h b/native/jni/utils/include/utils.h index 22bac5886..181f51022 100644 --- a/native/jni/utils/include/utils.h +++ b/native/jni/utils/include/utils.h @@ -150,6 +150,24 @@ std::vector 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);