From c28c2cb065d40c12b05f86d6775494892d03afca Mon Sep 17 00:00:00 2001 From: solohsu Date: Sun, 10 Mar 2019 20:03:14 +0800 Subject: [PATCH] Fix inconsistent use_white_list flag Still, app_data_file is not accessible to some process, e.g. bluetooth process on some devices, hence they would get a wrong use_white_list flag. What's worse is that these process cannot know whether they are black/white listed or not. As a workaround we take a black/white list snapshot in zygote. --- .../com/elderdrivers/riru/xposed/Main.java | 7 +- .../proxy/yahfa/BlackWhiteListProxy.java | 30 ++++++-- .../riru/xposed/proxy/yahfa/NormalProxy.java | 4 +- Core/jni/main/inject/config_manager.cpp | 71 +++++++++++++++++-- Core/jni/main/inject/framework_hook.cpp | 4 +- 5 files changed, 99 insertions(+), 17 deletions(-) diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java index 812ae6733..5259aca97 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java @@ -17,6 +17,7 @@ public class Main implements KeepAll { public static String appDataDir = ""; + public static String niceName = ""; public static String appProcessName = ""; public static long closedFdTable = 0; private static String forkAndSpecializePramsStr = ""; @@ -54,13 +55,13 @@ public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugF } } - public static void forkAndSpecializePost(int pid, String appDataDir) { + public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) { if (pid == 0) { Utils.logD(forkAndSpecializePramsStr + " = " + Process.myPid()); if (isBlackWhiteListEnabled()) { - BlackWhiteListProxy.forkAndSpecializePost(pid, appDataDir); + BlackWhiteListProxy.forkAndSpecializePost(pid, appDataDir, niceName); } else { - NormalProxy.forkAndSpecializePost(pid, appDataDir); + NormalProxy.forkAndSpecializePost(pid, appDataDir, niceName); } } else { // in zygote process, res is child zygote pid diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java index 356c830ad..258bba99d 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/BlackWhiteListProxy.java @@ -1,9 +1,13 @@ package com.elderdrivers.riru.xposed.proxy.yahfa; +import android.text.TextUtils; + import com.elderdrivers.riru.xposed.Main; import com.elderdrivers.riru.xposed.config.ConfigManager; import com.elderdrivers.riru.xposed.entry.Router; import com.elderdrivers.riru.xposed.util.PrebuiltMethodsDeopter; +import com.elderdrivers.riru.xposed.util.ProcessUtils; +import com.elderdrivers.riru.xposed.util.Utils; import static com.elderdrivers.riru.xposed.Main.isAppNeedHook; import static com.elderdrivers.riru.xposed.util.FileUtils.getDataPathPrefix; @@ -25,7 +29,7 @@ * * for all child processes of both main zygote and secondary zygote * 1) do the same things pre-forking first child process * 2. Dynamic mode: - * to be continued + * to be continued */ public class BlackWhiteListProxy { @@ -43,8 +47,8 @@ public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugF onForkPreForNonDynamicMode(false); } - public static void forkAndSpecializePost(int pid, String appDataDir) { - onForkPostCommon(false, appDataDir); + public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) { + onForkPostCommon(false, appDataDir, niceName); } public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFlags, @@ -60,7 +64,7 @@ public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFl } public static void forkSystemServerPost(int pid) { - onForkPostCommon(true, getDataPathPrefix() + "android"); + onForkPostCommon(true, getDataPathPrefix() + "android", "system_server"); } /** @@ -79,10 +83,11 @@ private static void onForkPreForNonDynamicMode(boolean isSystemServer) { Router.loadModulesSafely(true); } - private static void onForkPostCommon(boolean isSystemServer, String appDataDir) { + private static void onForkPostCommon(boolean isSystemServer, String appDataDir, String niceName) { Main.appDataDir = appDataDir; + Main.niceName = niceName; Router.onEnterChildProcess(); - if (!isAppNeedHook(Main.appDataDir)) { + if (!checkNeedHook(appDataDir, niceName)) { // if is blacklisted, just stop here return; } @@ -96,4 +101,17 @@ private static void onForkPostCommon(boolean isSystemServer, String appDataDir) Router.loadModulesSafely(false); } } + + private static boolean checkNeedHook(String appDataDir, String niceName) { + boolean needHook; + if (TextUtils.isEmpty(appDataDir)) { + Utils.logE("niceName:" + niceName + ", procName:" + + ProcessUtils.getCurrentProcessName() + ", appDataDir is null, blacklisted!"); + needHook = false; + } else { + // FIXME some process cannot read app_data_file because of MLS, e.g. bluetooth + needHook = isAppNeedHook(appDataDir); + } + return needHook; + } } diff --git a/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java b/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java index 71679a417..51ee8eb7e 100644 --- a/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java +++ b/Bridge/src/main/java/com/elderdrivers/riru/xposed/proxy/yahfa/NormalProxy.java @@ -28,9 +28,10 @@ public static void forkAndSpecializePre(int uid, int gid, int[] gids, int debugF } } - public static void forkAndSpecializePost(int pid, String appDataDir) { + public static void forkAndSpecializePost(int pid, String appDataDir, String niceName) { // TODO consider processes without forkAndSpecializePost called Main.appDataDir = appDataDir; + Main.niceName = niceName; Router.prepare(false); Router.reopenFilesIfNeeded(); Router.onEnterChildProcess(); @@ -58,6 +59,7 @@ public static void forkSystemServerPre(int uid, int gid, int[] gids, int debugFl public static void forkSystemServerPost(int pid) { // in system_server process Main.appDataDir = getDataPathPrefix() + "android"; + Main.niceName = "system_server"; Router.prepare(true); Router.reopenFilesIfNeeded(); Router.onEnterChildProcess(); diff --git a/Core/jni/main/inject/config_manager.cpp b/Core/jni/main/inject/config_manager.cpp index af4476d72..f1e1074fe 100644 --- a/Core/jni/main/inject/config_manager.cpp +++ b/Core/jni/main/inject/config_manager.cpp @@ -3,6 +3,7 @@ // #include +#include #include #include #include @@ -10,10 +11,14 @@ #include #include #include + #include #include +#include #include "config_manager.h" +using namespace std; + #define PRIMARY_INSTALLER_PKG_NAME "com.solohsu.android.edxp.manager" #define SECONDARY_INSTALLER_PKG_NAME "org.meowcat.edxposed.manager" #define LEGACY_INSTALLER_PKG_NAME "de.robv.android.xposed.installer" @@ -22,6 +27,7 @@ static bool use_prot_storage = GetAndroidApiLevel() >= ANDROID_N; static const char *data_path_prefix = use_prot_storage ? "/data/user_de/0/" : "/data/user/0/"; static const char *config_path_tpl = "%s/%s/conf/%s"; static char data_test_path[PATH_MAX]; +static char base_config_path[PATH_MAX]; static char blacklist_path[PATH_MAX]; static char whitelist_path[PATH_MAX]; static char use_whitelist_path[PATH_MAX]; @@ -34,6 +40,10 @@ static bool black_white_list_enabled = false; static bool dynamic_modules_enabled = false; static bool deopt_boot_image_enabled = false; static bool inited = false; +// snapshot at boot +static bool use_white_list_snapshot = false; +static vector white_list_default; +static vector black_list_default; static const char *get_installer_package_name() { snprintf(data_test_path, PATH_MAX, config_path_tpl, data_path_prefix, @@ -61,9 +71,38 @@ static const char *get_installer_package_name() { return PRIMARY_INSTALLER_PKG_NAME; } +static void snapshotBlackWhiteList() { + DIR *dir; + struct dirent *dent; + dir = opendir(whitelist_path); + if (dir != nullptr) { + while ((dent = readdir(dir)) != nullptr) { + if (dent->d_type == DT_REG) { + const char *fileName = dent->d_name; + LOGI("whitelist: %s", fileName); + white_list_default.emplace_back(fileName); + } + } + closedir(dir); + } + dir = opendir(blacklist_path); + if (dir != nullptr) { + while ((dent = readdir(dir)) != nullptr) { + if (dent->d_type == DT_REG) { + const char *fileName = dent->d_name; + LOGI("blacklist: %s", fileName); + black_list_default.emplace_back(fileName); + } + } + closedir(dir); + } +} + static void init_once() { if (!inited) { installer_package_name = get_installer_package_name(); + snprintf(base_config_path, PATH_MAX, config_path_tpl, data_path_prefix, + installer_package_name, ""); snprintf(blacklist_path, PATH_MAX, config_path_tpl, data_path_prefix, installer_package_name, "blacklist/"); snprintf(whitelist_path, PATH_MAX, config_path_tpl, data_path_prefix, @@ -78,9 +117,15 @@ static void init_once() { installer_package_name, "deoptbootimage"); dynamic_modules_enabled = access(dynamic_modules_path, F_OK) == 0; black_white_list_enabled = access(black_white_list_path, F_OK) == 0; + // use_white_list snapshot + use_white_list_snapshot = access(use_whitelist_path, F_OK) == 0; deopt_boot_image_enabled = access(deopt_boot_image_path, F_OK) == 0; - LOGI("black/white list mode: %d", black_white_list_enabled); + LOGI("black/white list mode: %d, using whitelist: %d", black_white_list_enabled, + use_white_list_snapshot); LOGI("dynamic modules mode: %d", dynamic_modules_enabled); + if (black_white_list_enabled) { + snapshotBlackWhiteList(); + } inited = true; } } @@ -92,12 +137,16 @@ bool is_app_need_hook(JNIEnv *env, jclass, jstring appDataDir) { if (!black_white_list_enabled) { return true; } - bool use_white_list = access(use_whitelist_path, F_OK) == 0; - if (!appDataDir) { - LOGE("appDataDir is null"); - return !use_white_list; - } + const char *app_data_dir = env->GetStringUTFChars(appDataDir, nullptr); + bool can_access_app_data = access(base_config_path, F_OK) == 0; + bool use_white_list; + if (can_access_app_data) { + use_white_list = access(use_whitelist_path, F_OK) == 0; + } else { + LOGE("can't access config path, using snapshot use_white_list: %s", app_data_dir); + use_white_list = use_white_list_snapshot; + } int user = 0; if (sscanf(app_data_dir, "/data/%*[^/]/%d/%s", &user, package_name) != 2) { if (sscanf(app_data_dir, "/data/%*[^/]/%s", package_name) != 1) { @@ -115,6 +164,11 @@ bool is_app_need_hook(JNIEnv *env, jclass, jstring appDataDir) { return true; } if (use_white_list) { + if (!can_access_app_data) { + LOGE("can't access config path, using snapshot white list: %s", app_data_dir); + return find(white_list_default.begin(), white_list_default.end(), package_name) != + white_list_default.end(); + } char path[PATH_MAX]; snprintf(path, PATH_MAX, "%s%s", whitelist_path, package_name); bool res = access(path, F_OK) == 0; @@ -122,6 +176,11 @@ bool is_app_need_hook(JNIEnv *env, jclass, jstring appDataDir) { env->ReleaseStringUTFChars(appDataDir, app_data_dir); return res; } else { + if (!can_access_app_data) { + LOGE("can't access config path, using snapshot black list: %s", app_data_dir); + return !(find(black_list_default.begin(), black_list_default.end(), package_name) != + black_list_default.end()); + } char path[PATH_MAX]; snprintf(path, PATH_MAX, "%s%s", blacklist_path, package_name); bool res = access(path, F_OK) != 0; diff --git a/Core/jni/main/inject/framework_hook.cpp b/Core/jni/main/inject/framework_hook.cpp index bd6392d97..5fd8eb6fb 100644 --- a/Core/jni/main/inject/framework_hook.cpp +++ b/Core/jni/main/inject/framework_hook.cpp @@ -11,6 +11,7 @@ static jclass sEntryClass; static jstring sAppDataDir; +static jstring sNiceName; void prepareJavaEnv(JNIEnv *env) { loadDexAndInit(env, INJECT_DEX_PATH); @@ -81,6 +82,7 @@ void onNativeForkAndSpecializePre(JNIEnv *env, jclass clazz, jstring instructionSet, jstring appDataDir) { sAppDataDir = appDataDir; + sNiceName = se_name; bool is_black_white_list_mode = is_black_white_list_enabled(); bool is_dynamic_modules_mode = is_dynamic_modules_enabled(); if (is_black_white_list_mode && is_dynamic_modules_mode) { @@ -98,7 +100,7 @@ void onNativeForkAndSpecializePre(JNIEnv *env, jclass clazz, int onNativeForkAndSpecializePost(JNIEnv *env, jclass clazz, jint res) { if (res == 0) { prepareJavaEnv(env); - findAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;)V", res, sAppDataDir); + findAndCall(env, "forkAndSpecializePost", "(ILjava/lang/String;Ljava/lang/String;)V", res, sAppDataDir, sNiceName); } else { // in zygote process, res is child zygote pid // don't print log here, see https://github.com/RikkaApps/Riru/blob/77adfd6a4a6a81bfd20569c910bc4854f2f84f5e/riru-core/jni/main/jni_native_method.cpp#L55-L66