lazy-update app data path in ConfigManager::IsAppNeedHook()

zygote always starts with `uid == 0` and then fork into a different user.
so we delay the evaluation until we get to the point where it's been hooked already.
this enabled multi-user support, since we can now find the config files!
This commit is contained in:
Victor Tseng 2020-03-24 02:10:30 +08:00 committed by Jim Wu
parent efe0869390
commit db5d51483d
2 changed files with 63 additions and 50 deletions

View File

@ -35,8 +35,7 @@ namespace edxp {
LOGI("using installer %s", kLegacyInstallerPkgName); LOGI("using installer %s", kLegacyInstallerPkgName);
return kLegacyInstallerPkgName; return kLegacyInstallerPkgName;
} }
LOGE("no supported installer app found, using primary as default %s", LOGE("no supported installer app found, using default: %s", kPrimaryInstallerPkgName);
kPrimaryInstallerPkgName);
return kPrimaryInstallerPkgName; return kPrimaryInstallerPkgName;
} }
@ -48,7 +47,7 @@ namespace edxp {
while ((dent = readdir(dir)) != nullptr) { while ((dent = readdir(dir)) != nullptr) {
if (dent->d_type == DT_REG) { if (dent->d_type == DT_REG) {
const char *fileName = dent->d_name; const char *fileName = dent->d_name;
LOGI("whitelist: %s", fileName); LOGI(" whitelist: %s", fileName);
white_list_default_.emplace_back(fileName); white_list_default_.emplace_back(fileName);
} }
} }
@ -59,7 +58,7 @@ namespace edxp {
while ((dent = readdir(dir)) != nullptr) { while ((dent = readdir(dir)) != nullptr) {
if (dent->d_type == DT_REG) { if (dent->d_type == DT_REG) {
const char *fileName = dent->d_name; const char *fileName = dent->d_name;
LOGI("blacklist: %s", fileName); LOGI(" blacklist: %s", fileName);
black_list_default_.emplace_back(fileName); black_list_default_.emplace_back(fileName);
} }
} }
@ -67,39 +66,60 @@ namespace edxp {
} }
} }
void ConfigManager::InitOnce() { void ConfigManager::UpdateConfigPath(const uid_t user) {
if (!initialized_) { if (last_user_ != user) {
use_prot_storage_ = GetAndroidApiLevel() >= ANDROID_N; LOGI("updating config data paths from %u to %u...", last_user_, user);
data_path_prefix_ = use_prot_storage_ ? "/data/user_de/0/" : "/data/user/0/"; last_user_ = user;
}
installer_pkg_name_ = RetrieveInstallerPkgName(); const char *format = use_prot_storage_ ? "/data/user_de/%u/" : "/data/user/%u/";
base_config_path_ = GetConfigPath(""); char buff[PATH_MAX];
blacklist_path_ = GetConfigPath("blacklist/"); snprintf(buff, sizeof(buff), format, last_user_);
whitelist_path_ = GetConfigPath("whitelist/"); data_path_prefix_ = buff;
use_whitelist_path_ = GetConfigPath("usewhitelist");
dynamic_modules_enabled_ = access(GetConfigPath("dynamicmodules").c_str(), F_OK) == 0; installer_pkg_name_ = RetrieveInstallerPkgName();
black_white_list_enabled_ = access(GetConfigPath("blackwhitelist").c_str(), F_OK) == 0; base_config_path_ = GetConfigPath("");
deopt_boot_image_enabled_ = access(GetConfigPath("deoptbootimage").c_str(), F_OK) == 0; blacklist_path_ = GetConfigPath("blacklist/");
resources_hook_enabled_ = access(GetConfigPath("disable_resources").c_str(), F_OK) != 0; whitelist_path_ = GetConfigPath("whitelist/");
no_module_log_enabled_ = access(GetConfigPath("disable_modules_log").c_str(), F_OK) == 0; use_whitelist_path_ = GetConfigPath("usewhitelist");
// use_white_list snapshot dynamic_modules_enabled_ = access(GetConfigPath("dynamicmodules").c_str(), F_OK) == 0;
use_white_list_snapshot_ = access(use_whitelist_path_.c_str(), F_OK) == 0; black_white_list_enabled_ = access(GetConfigPath("blackwhitelist").c_str(), F_OK) == 0;
LOGI("application list mode: %s, using whitelist: %s", deopt_boot_image_enabled_ = access(GetConfigPath("deoptbootimage").c_str(), F_OK) == 0;
BoolToString(black_white_list_enabled_), BoolToString(use_white_list_snapshot_)); resources_hook_enabled_ = access(GetConfigPath("disable_resources").c_str(), F_OK) != 0;
LOGI("dynamic modules mode: %s", BoolToString(dynamic_modules_enabled_)); no_module_log_enabled_ = access(GetConfigPath("disable_modules_log").c_str(), F_OK) == 0;
LOGI("resources hook: %s", BoolToString(resources_hook_enabled_));
LOGI("deopt boot image: %s", BoolToString(deopt_boot_image_enabled_)); // use_white_list snapshot
LOGI("no module log: %s", BoolToString(no_module_log_enabled_)); use_white_list_snapshot_ = access(use_whitelist_path_.c_str(), F_OK) == 0;
if (black_white_list_enabled_) { LOGI("data path prefix: %s", data_path_prefix_.c_str());
SnapshotBlackWhiteList(); LOGI(" application list mode: %s", BoolToString(black_white_list_enabled_));
} LOGI(" using whitelist: %s", BoolToString(use_white_list_snapshot_));
initialized_ = true; LOGI(" dynamic modules mode: %s", BoolToString(dynamic_modules_enabled_));
LOGI(" resources hook: %s", BoolToString(resources_hook_enabled_));
LOGI(" deopt boot image: %s", BoolToString(deopt_boot_image_enabled_));
LOGI(" no module log: %s", BoolToString(no_module_log_enabled_));
if (black_white_list_enabled_) {
SnapshotBlackWhiteList();
} }
} }
bool ConfigManager::IsAppNeedHook(const std::string &app_data_dir) const { bool ConfigManager::IsAppNeedHook(const std::string &app_data_dir) {
// zygote always starts with `uid == 0` and then fork into different user.
// so we have to check if we are the correct user or not.
uid_t user = 0;
char package_name[PATH_MAX];
if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%u/%s", &user, package_name) != 2) {
if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%s", package_name) != 1) {
package_name[0] = '\0';
LOGE("can't parse %s", app_data_dir.c_str());
return false; // default to no hooking for safety
}
}
if (last_user_ != user) {
UpdateConfigPath(user);
}
if (!black_white_list_enabled_) { if (!black_white_list_enabled_) {
return true; return true;
} }
@ -112,15 +132,6 @@ namespace edxp {
app_data_dir.c_str()); app_data_dir.c_str());
use_white_list = use_white_list_snapshot_; use_white_list = use_white_list_snapshot_;
} }
int user = 0;
char package_name[PATH_MAX];
if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%d/%s", &user, package_name) != 2) {
if (sscanf(app_data_dir.c_str(), "/data/%*[^/]/%s", package_name) != 1) {
package_name[0] = '\0';
LOGE("can't parse %s", app_data_dir.c_str());
return !use_white_list;
}
}
if (strcmp(package_name, kPrimaryInstallerPkgName) == 0 if (strcmp(package_name, kPrimaryInstallerPkgName) == 0
|| strcmp(package_name, kLegacyInstallerPkgName) == 0) { || strcmp(package_name, kLegacyInstallerPkgName) == 0) {
// always hook installer apps // always hook installer apps
@ -185,11 +196,9 @@ namespace edxp {
}; };
ConfigManager::ConfigManager() { ConfigManager::ConfigManager() {
InitOnce(); use_prot_storage_ = GetAndroidApiLevel() >= ANDROID_N;
} last_user_ = 0;
UpdateConfigPath(last_user_);
ConfigManager::~ConfigManager() {
initialized_ = false;
} }
} }

View File

@ -22,20 +22,26 @@ namespace edxp {
} }
bool IsBlackWhiteListEnabled() const; bool IsBlackWhiteListEnabled() const;
bool IsDynamicModulesEnabled() const; bool IsDynamicModulesEnabled() const;
bool IsResourcesHookEnabled() const; bool IsResourcesHookEnabled() const;
bool IsDeoptBootImageEnabled() const; bool IsDeoptBootImageEnabled() const;
bool IsNoModuleLogEnabled() const; bool IsNoModuleLogEnabled() const;
std::string GetInstallerPackageName() const; std::string GetInstallerPackageName() const;
std::string GetDataPathPrefix() const; std::string GetDataPathPrefix() const;
std::string GetConfigPath(const std::string &suffix) const; std::string GetConfigPath(const std::string &suffix) const;
bool IsAppNeedHook(const std::string &app_data_dir) const; bool IsAppNeedHook(const std::string &app_data_dir);
private: private:
inline static ConfigManager *instance_; inline static ConfigManager *instance_;
bool initialized_ = false; uid_t last_user_ = false;
bool use_prot_storage_ = true; bool use_prot_storage_ = true;
std::string data_path_prefix_; std::string data_path_prefix_;
std::string installer_pkg_name_; std::string installer_pkg_name_;
@ -55,9 +61,7 @@ namespace edxp {
ConfigManager(); ConfigManager();
~ConfigManager(); void UpdateConfigPath(const uid_t user);
void InitOnce();
void SnapshotBlackWhiteList(); void SnapshotBlackWhiteList();