From db590091b3d45cb8c369d50aff82920dfc6733c9 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 18 Sep 2021 02:38:53 -0700 Subject: [PATCH] Propagate Zygisk state to Magisk app --- .../java/com/topjohnwu/magisk/core/Info.kt | 7 ++- .../topjohnwu/magisk/ui/log/LogViewModel.kt | 7 ++- .../magisk/ui/settings/SettingsItems.kt | 16 ++++- .../magisk/ui/settings/SettingsViewModel.kt | 24 +++++--- .../main/res/layout/include_home_magisk.xml | 61 ++++++------------- app/src/main/res/values/strings.xml | 1 + native/jni/core/db.cpp | 7 +++ native/jni/include/db.hpp | 1 + native/jni/zygisk/entry.cpp | 36 ++++++----- native/jni/zygisk/hook.cpp | 15 +++-- native/jni/zygisk/inject.hpp | 9 ++- 11 files changed, 99 insertions(+), 85 deletions(-) diff --git a/app/src/main/java/com/topjohnwu/magisk/core/Info.kt b/app/src/main/java/com/topjohnwu/magisk/core/Info.kt index 8e3198c37..821253f5f 100644 --- a/app/src/main/java/com/topjohnwu/magisk/core/Info.kt +++ b/app/src/main/java/com/topjohnwu/magisk/core/Info.kt @@ -28,9 +28,10 @@ object Info { // Device state @JvmStatic val env by lazy { loadState() } - @JvmField var isSAR = false - @JvmField var isAB = false - @JvmField val isVirtualAB = getProperty("ro.virtual_ab.enabled", "false") == "true" + @JvmStatic var isSAR = false + var isAB = false + val isVirtualAB = getProperty("ro.virtual_ab.enabled", "false") == "true" + @JvmField val isZygiskEnabled = System.getenv("ZYGISK_ENABLED") == "1" @JvmStatic val isFDE get() = crypto == "block" @JvmField var ramdisk = false @JvmField var hasGMS = true diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt index bee42cad3..b4a23aab5 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/log/LogViewModel.kt @@ -62,7 +62,12 @@ class LogViewModel( val filename = "magisk_log_%s.log".format(now.toTime(timeFormatStandard)) val logFile = MediaStoreUtils.getFile(filename, true) logFile.uri.outputStream().bufferedWriter().use { file -> - file.write("---System Properties---\n\n") + file.write("---Detected Device Info---\n\n") + file.write("isAB=${Info.isAB}\n") + file.write("isSAR=${Info.isSAR}\n") + file.write("ramdisk=${Info.ramdisk}\n") + + file.write("\n\n---System Properties---\n\n") ProcessBuilder("getprop").start() .inputStream.reader().use { it.copyTo(file) } diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt index 3a75266e0..ca51108a0 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsItems.kt @@ -236,20 +236,30 @@ object Magisk : BaseSettingsItem.Section() { object Zygisk : BaseSettingsItem.Toggle() { override val title = R.string.zygisk.asText() - override val description = R.string.settings_zygisk_summary.asText() + override val description get() = + if (mismatch) R.string.reboot_apply_change.asText() + else R.string.settings_zygisk_summary.asText() override var value = Config.zygisk set(value) = setV(value, field, { field = it }) { Config.zygisk = it DenyList.isEnabled = it DenyListConfig.isEnabled = it + DenyList.notifyPropertyChanged(BR.description) } + val mismatch get() = value != Info.isZygiskEnabled } object DenyList : BaseSettingsItem.Toggle() { override val title = R.string.settings_denylist_title.asText() override val description get() = - if (isEnabled) R.string.settings_denylist_summary.asText() - else R.string.settings_denylist_error.asText(R.string.zygisk.asText()) + if (isEnabled) { + if (Zygisk.mismatch) + R.string.reboot_apply_change.asText() + else + R.string.settings_denylist_summary.asText() + } else { + R.string.settings_denylist_error.asText(R.string.zygisk.asText()) + } override var value = Config.denyList set(value) = setV(value, field, { field = it }) { diff --git a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt index 8afc4ba22..7f3c363c9 100644 --- a/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt +++ b/app/src/main/java/com/topjohnwu/magisk/ui/settings/SettingsViewModel.kt @@ -18,6 +18,7 @@ import com.topjohnwu.magisk.databinding.itemBindingOf import com.topjohnwu.magisk.di.AppContext import com.topjohnwu.magisk.events.AddHomeIconEvent import com.topjohnwu.magisk.events.RecreateEvent +import com.topjohnwu.magisk.events.SnackbarEvent import com.topjohnwu.magisk.events.dialog.BiometricEvent import com.topjohnwu.magisk.ktx.activity import com.topjohnwu.magisk.utils.Utils @@ -97,15 +98,19 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Callback { return list } - override fun onItemPressed(view: View, item: BaseSettingsItem, callback: () -> Unit) = when (item) { - is DownloadPath -> withExternalRW(callback) - is Biometrics -> authenticate(callback) - is Theme -> SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate() - is DenyListConfig -> SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate() - is SystemlessHosts -> createHosts() - is Restore -> HideAPK.restore(view.activity) - is AddShortcut -> AddHomeIconEvent().publish() - else -> callback() + override fun onItemPressed(view: View, item: BaseSettingsItem, callback: () -> Unit) { + when (item) { + is DownloadPath -> withExternalRW(callback) + is Biometrics -> authenticate(callback) + is Theme -> + SettingsFragmentDirections.actionSettingsFragmentToThemeFragment().navigate() + is DenyListConfig -> + SettingsFragmentDirections.actionSettingsFragmentToDenyFragment().navigate() + is SystemlessHosts -> createHosts() + is Restore -> HideAPK.restore(view.activity) + is AddShortcut -> AddHomeIconEvent().publish() + else -> callback() + } } override fun onItemChanged(view: View, item: BaseSettingsItem) { @@ -113,6 +118,7 @@ class SettingsViewModel : BaseViewModel(), BaseSettingsItem.Callback { is Language -> RecreateEvent().publish() is UpdateChannel -> openUrlIfNecessary(view) is Hide -> viewModelScope.launch { HideAPK.hide(view.activity, item.value) } + is Zygisk -> if (Zygisk.mismatch) SnackbarEvent(R.string.reboot_apply_change).publish() else -> Unit } } diff --git a/app/src/main/res/layout/include_home_magisk.xml b/app/src/main/res/layout/include_home_magisk.xml index 20eeec4bd..343d869b8 100644 --- a/app/src/main/res/layout/include_home_magisk.xml +++ b/app/src/main/res/layout/include_home_magisk.xml @@ -127,11 +127,28 @@ + + + + + + + + + app:layout_constraintTop_toBottomOf="@+id/home_device_details_zygisk"> - - - - - - - - - - - - - - - - - - diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 144aba5bf..0088fa32f 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -242,5 +242,6 @@ Add shortcut to home screen After hiding this app, its name and icon might become difficult to recognize. Do you want to add a pretty shortcut to the home screen? No application found to handle this action + Reboot to apply changes diff --git a/native/jni/core/db.cpp b/native/jni/core/db.cpp index 3e7bbda98..4949538f9 100644 --- a/native/jni/core/db.cpp +++ b/native/jni/core/db.cpp @@ -376,6 +376,13 @@ bool get_manager(string *pkg) { return get_manager(0, pkg, &st); } +int get_manager_app_id() { + struct stat st; + if (get_manager(0, nullptr, &st)) + return to_app_id(st.st_uid); + return -1; +} + void exec_sql(int client) { run_finally f([=]{ close(client); }); string sql = read_string(client); diff --git a/native/jni/include/db.hpp b/native/jni/include/db.hpp index ca7f4ee3b..3491382df 100644 --- a/native/jni/include/db.hpp +++ b/native/jni/include/db.hpp @@ -128,6 +128,7 @@ int get_db_strings(db_strings &str, int key = -1); int get_uid_policy(su_access &su, int uid); bool get_manager(int user_id, std::string *pkg, struct stat *st); bool get_manager(std::string *pkg = nullptr); +int get_manager_app_id(); void exec_sql(int client); char *db_exec(const char *sql); char *db_exec(const char *sql, const db_row_cb &fn); diff --git a/native/jni/zygisk/entry.cpp b/native/jni/zygisk/entry.cpp index 609a2872a..26a38e892 100644 --- a/native/jni/zygisk/entry.cpp +++ b/native/jni/zygisk/entry.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include "inject.hpp" #include "../deny/deny.hpp" @@ -205,21 +206,17 @@ static int zygisk_log(int prio, const char *fmt, va_list ap) { return ret; } -bool remote_check_denylist(int uid, const char *process) { +void remote_get_app_info(int uid, const char *process, AppInfo *info) { if (int fd = connect_daemon(); fd >= 0) { write_int(fd, ZYGISK_REQUEST); - write_int(fd, ZYGISK_CHECK_DENYLIST); + write_int(fd, ZYGISK_GET_APPINFO); + + write_int(fd, uid); + write_string(fd, process); + xxread(fd, info, sizeof(*info)); - int ret = -1; - if (read_int(fd) == 0) { - write_int(fd, uid); - write_string(fd, process); - ret = read_int(fd); - } close(fd); - return ret >= 0 && ret; } - return false; } int remote_request_unmount() { @@ -254,15 +251,16 @@ static void setup_files(int client, ucred *cred) { write_string(client, path); } -static void check_denylist(int client) { - if (!denylist_enabled) { - write_int(client, DENY_NOT_ENFORCED); - return; - } - write_int(client, 0); +static void get_app_info(int client) { + AppInfo info{}; int uid = read_int(client); string process = read_string(client); - write_int(client, is_deny_target(uid, process)); + if (to_app_id(uid) == get_manager_app_id()) { + info.is_magisk_app = true; + } else if (denylist_enabled) { + info.on_denylist = is_deny_target(uid, process); + } + xwrite(client, &info, sizeof(info)); } static void do_unmount(int client, ucred *cred) { @@ -290,8 +288,8 @@ void zygisk_handler(int client, ucred *cred) { case ZYGISK_SETUP: setup_files(client, cred); break; - case ZYGISK_CHECK_DENYLIST: - check_denylist(client); + case ZYGISK_GET_APPINFO: + get_app_info(client); break; case ZYGISK_UNMOUNT: do_unmount(client, cred); diff --git a/native/jni/zygisk/hook.cpp b/native/jni/zygisk/hook.cpp index 529e77f50..61c6c48af 100644 --- a/native/jni/zygisk/hook.cpp +++ b/native/jni/zygisk/hook.cpp @@ -43,8 +43,9 @@ struct HookContext { const char *process; int pid; bitset flags; + AppInfo info; - HookContext() : pid(-1) {} + HookContext() : pid(-1), info{} {} static void close_fds(); @@ -139,7 +140,7 @@ DCL_HOOK_FUNC(int, fork) { // This is the latest point where we can still connect to the magiskd main socket DCL_HOOK_FUNC(int, selinux_android_setcontext, uid_t uid, int isSystemServer, const char *seinfo, const char *pkgname) { - if (g_ctx && g_ctx->flags[DENY_FLAG]) { + if (g_ctx && g_ctx->info.on_denylist) { if (remote_request_unmount() == 0) { LOGD("zygisk: mount namespace cleaned up\n"); } @@ -241,9 +242,10 @@ void HookContext::nativeSpecializeAppProcess_pre() { VLOG("zygisk: pre specialize [%s]\n", process); } + remote_get_app_info(args->uid, process, &info); + /* TODO: Handle MOUNT_EXTERNAL_NONE */ - if (args->mount_external != 0 && remote_check_denylist(args->uid, process)) { - flags[DENY_FLAG] = true; + if (args->mount_external != 0 && info.on_denylist) { LOGI("zygisk: [%s] is on the denylist\n", process); } else { run_modules_pre(); @@ -258,11 +260,14 @@ void HookContext::nativeSpecializeAppProcess_post() { } env->ReleaseStringUTFChars(args->nice_name, process); - if (flags[DENY_FLAG]) { + if (info.on_denylist) { self_unload(); } else { run_modules_post(); } + if (info.is_magisk_app) { + setenv("ZYGISK_ENABLED", "1", 1); + } g_ctx = nullptr; } diff --git a/native/jni/zygisk/inject.hpp b/native/jni/zygisk/inject.hpp index e33f9cc59..e88d4fee6 100644 --- a/native/jni/zygisk/inject.hpp +++ b/native/jni/zygisk/inject.hpp @@ -8,7 +8,7 @@ enum : int { ZYGISK_SETUP, - ZYGISK_CHECK_DENYLIST, + ZYGISK_GET_APPINFO, ZYGISK_UNMOUNT, ZYGISK_GET_LOG_PIPE, }; @@ -22,8 +22,13 @@ uintptr_t get_function_off(int pid, uintptr_t addr, char *lib); // Get function address, given library name + offset uintptr_t get_function_addr(int pid, const char *lib, uintptr_t off); +struct AppInfo { + bool is_magisk_app; + bool on_denylist; +}; + void self_unload(); void hook_functions(); bool unhook_functions(); -bool remote_check_denylist(int uid, const char *process); +void remote_get_app_info(int uid, const char *process, AppInfo *info); int remote_request_unmount();