diff --git a/native/jni/core/core.hpp b/native/jni/core/core.hpp index 3be449a30..ae9d7cc32 100644 --- a/native/jni/core/core.hpp +++ b/native/jni/core/core.hpp @@ -35,4 +35,5 @@ void exec_common_scripts(const char *stage); void exec_module_scripts(const char *stage, const std::vector &modules); void install_apk(const char *apk); void uninstall_pkg(const char *pkg); +void clear_pkg(const char *pkg, int user_id); [[noreturn]] void install_module(const char *file); diff --git a/native/jni/core/package.cpp b/native/jni/core/package.cpp index 5ce48474c..6c0585f46 100644 --- a/native/jni/core/package.cpp +++ b/native/jni/core/package.cpp @@ -8,6 +8,8 @@ using namespace std; +#define ENFORCE_SIGNATURE (!MAGISK_DEBUG) + // These functions will be called on every single zygote process specialization and su request, // so performance is absolutely critical. Most operations should either have its result cached // or simply skipped unless necessary. @@ -100,6 +102,24 @@ int get_manager(int user_id, string *pkg, bool install) { if (mgr_cert == nullptr) default_new(mgr_cert); + auto check_dyn = [&](int u) -> bool { + snprintf(app_path, sizeof(app_path), + "%s/%d/%s/dyn/current.apk", APP_DATA_DIR, u, mgr_pkg->data()); + int dyn = open(app_path, O_RDONLY | O_CLOEXEC); + if (dyn < 0) + return false; + bool mismatch = default_cert && read_certificate(dyn) != *default_cert; + close(dyn); + if (mismatch) { + LOGE("pkg: dyn APK signature mismatch: %s\n", app_path); +#if ENFORCE_SIGNATURE + clear_pkg(mgr_pkg->data(), u); + return false; +#endif + } + return true; + }; + if (skip_check.test_and_set()) { if (mgr_app_id < 0) { goto not_found; @@ -108,6 +128,9 @@ int get_manager(int user_id, string *pkg, bool install) { const char *name = mgr_pkg->empty() ? JAVA_PACKAGE_NAME : mgr_pkg->data(); snprintf(app_path, sizeof(app_path), "%s/%d/%s", APP_DATA_DIR, user_id, name); if (access(app_path, F_OK) == 0) { + // Always check dyn signature for repackaged app + if (!mgr_pkg->empty() && !check_dyn(user_id)) + goto not_found; if (pkg) *pkg = name; return user_id * AID_USER_OFFSET + mgr_app_id; } else { @@ -161,6 +184,7 @@ int get_manager(int user_id, string *pkg, bool install) { LOGE("pkg: repackaged APK signature invalid: %s\n", apk.data()); uninstall_pkg(mgr_pkg->data()); invalid = true; + install = true; return false; } } @@ -174,6 +198,8 @@ int get_manager(int user_id, string *pkg, bool install) { }; if (check_pkg(user_id)) { + if (!check_dyn(user_id)) + goto not_found; if (pkg) *pkg = *mgr_pkg; return st.st_uid; } @@ -209,7 +235,7 @@ int get_manager(int user_id, string *pkg, bool install) { if (default_cert && cert != *default_cert) { // Found APK with invalid signature, force replace with stub LOGE("pkg: APK signature mismatch: %s\n", apk.data()); -#if !MAGISK_DEBUG +#if ENFORCE_SIGNATURE uninstall_pkg(JAVA_PACKAGE_NAME); invalid = true; install = true; diff --git a/native/jni/core/scripting.cpp b/native/jni/core/scripting.cpp index a70c1a13b..e5223ceb9 100644 --- a/native/jni/core/scripting.cpp +++ b/native/jni/core/scripting.cpp @@ -152,8 +152,8 @@ void exec_module_scripts(const char *stage, const vector &modules) constexpr char install_script[] = R"EOF( APK=%s -log -t Magisk "apk_install: $APK" -log -t Magisk "apk_install: $(pm install -r $APK 2>&1)" +log -t Magisk "pm_install: $APK" +log -t Magisk "pm_install: $(pm install -r $APK 2>&1)" rm -f $APK )EOF"; @@ -169,8 +169,8 @@ void install_apk(const char *apk) { constexpr char uninstall_script[] = R"EOF( PKG=%s -log -t Magisk "apk_uninstall: $PKG" -log -t Magisk "apk_uninstall: $(pm uninstall $PKG 2>&1)" +log -t Magisk "pm_uninstall: $PKG" +log -t Magisk "pm_uninstall: $(pm uninstall $PKG 2>&1)" )EOF"; void uninstall_pkg(const char *pkg) { @@ -182,6 +182,22 @@ void uninstall_pkg(const char *pkg) { exec_command_sync(exec, "/system/bin/sh", "-c", cmds); } +constexpr char clear_script[] = R"EOF( +PKG=%s +USER=%d +log -t Magisk "pm_clear: $PKG (user=$USER)" +log -t Magisk "pm_clear: $(pm clear --user $USER $PKG 2>&1)" +)EOF"; + +void clear_pkg(const char *pkg, int user_id) { + exec_t exec { + .fork = fork_no_orphan + }; + char cmds[sizeof(clear_script) + 288]; + snprintf(cmds, sizeof(cmds), clear_script, pkg, user_id); + exec_command_sync(exec, "/system/bin/sh", "-c", cmds); +} + [[noreturn]] __printflike(2, 3) static void abort(FILE *fp, const char *fmt, ...) { va_list valist;