Skip to content

Commit

Permalink
Fix inconsistent use_white_list flag
Browse files Browse the repository at this point in the history
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.
  • Loading branch information
solohsu committed Mar 10, 2019
1 parent d5cda2b commit c28c2cb
Show file tree
Hide file tree
Showing 5 changed files with 99 additions and 17 deletions.
7 changes: 4 additions & 3 deletions Bridge/src/main/java/com/elderdrivers/riru/xposed/Main.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 = "";
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand All @@ -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 {

Expand All @@ -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,
Expand All @@ -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");
}

/**
Expand All @@ -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;
}
Expand All @@ -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;
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -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();
Expand Down Expand Up @@ -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();
Expand Down
71 changes: 65 additions & 6 deletions Core/jni/main/inject/config_manager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,22 @@
//

#include <cstdio>
#include <dirent.h>
#include <unistd.h>
#include <jni.h>
#include <cstdlib>
#include <array>
#include <thread>
#include <vector>
#include <string>

#include <include/android_build.h>
#include <include/logging.h>
#include <linux/limits.h>
#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"
Expand All @@ -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];
Expand All @@ -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<string> white_list_default;
static vector<string> black_list_default;

static const char *get_installer_package_name() {
snprintf(data_test_path, PATH_MAX, config_path_tpl, data_path_prefix,
Expand Down Expand Up @@ -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,
Expand All @@ -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;
}
}
Expand All @@ -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) {
Expand All @@ -115,13 +164,23 @@ 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;
LOGD("using whitelist, %s -> %d", app_data_dir, res);
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;
Expand Down
4 changes: 3 additions & 1 deletion Core/jni/main/inject/framework_hook.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@

static jclass sEntryClass;
static jstring sAppDataDir;
static jstring sNiceName;

void prepareJavaEnv(JNIEnv *env) {
loadDexAndInit(env, INJECT_DEX_PATH);
Expand Down Expand Up @@ -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) {
Expand All @@ -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
Expand Down

0 comments on commit c28c2cb

Please sign in to comment.