Enhanced denylist app id tracking

This commit is contained in:
vvb2060 2024-01-30 02:58:56 +08:00 committed by John Wu
parent 94d1c66f8a
commit 6aab856de7
5 changed files with 69 additions and 54 deletions

View File

@ -158,6 +158,7 @@ static void handle_request_async(int client, int code, const sock_cred &cred) {
case +RequestCode::ZYGOTE_RESTART:
LOGI("** zygote restarted\n");
prune_su_access();
scan_deny_apps();
reset_zygisk(false);
close(client);
break;

View File

@ -15,8 +15,6 @@
using namespace std;
atomic_flag skip_pkg_rescan;
// For the following data structures:
// If package name == ISOLATED_MAGIC, or app ID == -1, it means isolated service
@ -33,59 +31,48 @@ static pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER;
atomic<bool> denylist_enforced = false;
static void rescan_apps() {
LOGD("denylist: rescanning apps\n");
app_id_to_pkgs.clear();
static int get_app_id(const vector<int> &users, const string &pkg) {
struct stat st{};
char buf[PATH_MAX];
for (const auto &user_id: users) {
ssprintf(buf, sizeof(buf), "%s/%d/%s", APP_DATA_DIR, user_id, pkg.data());
if (stat(buf, &st) == 0) {
return to_app_id(st.st_uid);
}
}
return 0;
}
static void collect_users(vector<int> &users) {
auto data_dir = xopen_dir(APP_DATA_DIR);
if (!data_dir)
return;
dirent *entry;
while ((entry = xreaddir(data_dir.get()))) {
// For each user
int dfd = xopenat(dirfd(data_dir.get()), entry->d_name, O_RDONLY);
if (auto dir = xopen_dir(dfd)) {
while ((entry = xreaddir(dir.get()))) {
struct stat st{};
// For each package
if (xfstatat(dfd, entry->d_name, &st, 0))
continue;
int app_id = to_app_id(st.st_uid);
if (auto it = pkg_to_procs.find(entry->d_name); it != pkg_to_procs.end()) {
app_id_to_pkgs[app_id].insert(it->first);
}
}
} else {
close(dfd);
}
users.emplace_back(parse_int(entry->d_name));
}
}
static void update_pkg_uid(const string &pkg, bool remove) {
auto data_dir = xopen_dir(APP_DATA_DIR);
if (!data_dir)
static int get_app_id(const string &pkg) {
if (pkg == ISOLATED_MAGIC)
return -1;
vector<int> users;
collect_users(users);
return get_app_id(users, pkg);
}
static void update_app_id(int app_id, const string &pkg, bool remove) {
if (app_id <= 0)
return;
dirent *entry;
struct stat st{};
char buf[PATH_MAX] = {0};
// For each user
while ((entry = xreaddir(data_dir.get()))) {
ssprintf(buf, sizeof(buf), "%s/%s", entry->d_name, pkg.data());
if (fstatat(dirfd(data_dir.get()), buf, &st, 0) == 0) {
int app_id = to_app_id(st.st_uid);
if (remove) {
if (auto it = app_id_to_pkgs.find(app_id); it != app_id_to_pkgs.end()) {
it->second.erase(pkg);
if (it->second.empty()) {
app_id_to_pkgs.erase(it);
}
}
} else {
app_id_to_pkgs[app_id].insert(pkg);
if (remove) {
if (auto it = app_id_to_pkgs.find(app_id); it != app_id_to_pkgs.end()) {
it->second.erase(pkg);
if (it->second.empty()) {
app_id_to_pkgs.erase(it);
}
break;
}
} else {
app_id_to_pkgs[app_id].emplace(pkg);
}
}
@ -195,6 +182,34 @@ static bool add_hide_set(const char *pkg, const char *proc) {
return true;
}
void scan_deny_apps() {
if (!app_id_to_pkgs_)
return;
app_id_to_pkgs.clear();
char sql[4096];
vector<int> users;
collect_users(users);
for (auto it = pkg_to_procs.begin(); it != pkg_to_procs.end();) {
if (it->first == ISOLATED_MAGIC) {
it++;
continue;
}
int app_id = get_app_id(users, it->first);
if (app_id == 0) {
LOGI("denylist rm: [%s]\n", it->first.data());
ssprintf(sql, sizeof(sql), "DELETE FROM denylist WHERE package_name='%s'",
it->first.data());
db_err(db_exec(sql));
it = pkg_to_procs.erase(it);
} else {
update_app_id(app_id, it->first, false);
it++;
}
}
}
static void clear_data() {
pkg_to_procs_.reset(nullptr);
app_id_to_pkgs_.reset(nullptr);
@ -214,7 +229,7 @@ static bool ensure_data() {
db_err_cmd(err, goto error)
default_new(app_id_to_pkgs_);
rescan_apps();
scan_deny_apps();
return true;
@ -234,10 +249,13 @@ static int add_list(const char *pkg, const char *proc) {
mutex_guard lock(data_lock);
if (!ensure_data())
return DenyResponse::ERROR;
int app_id = get_app_id(pkg);
if (app_id == 0)
return DenyResponse::INVALID_PKG;
if (!add_hide_set(pkg, proc))
return DenyResponse::ITEM_EXIST;
auto it = pkg_to_procs.find(pkg);
update_pkg_uid(it->first, false);
update_app_id(app_id, it->first, false);
}
// Add to database
@ -266,7 +284,7 @@ static int rm_list(const char *pkg, const char *proc) {
auto it = pkg_to_procs.find(pkg);
if (it != pkg_to_procs.end()) {
if (proc[0] == '\0') {
update_pkg_uid(it->first, true);
update_app_id(get_app_id(pkg), it->first, true);
pkg_to_procs.erase(it);
remove = true;
LOGI("denylist rm: [%s]\n", pkg);
@ -274,7 +292,7 @@ static int rm_list(const char *pkg, const char *proc) {
remove = true;
LOGI("denylist rm: [%s/%s]\n", pkg, proc);
if (it->second.empty()) {
update_pkg_uid(it->first, true);
update_app_id(get_app_id(pkg), it->first, true);
pkg_to_procs.erase(it);
}
}
@ -309,6 +327,7 @@ void ls_list(int client) {
return;
}
scan_deny_apps();
write_int(client,static_cast<int>(DenyResponse::OK));
for (const auto &[pkg, procs] : pkg_to_procs) {
@ -386,9 +405,6 @@ bool is_deny_target(int uid, string_view process) {
if (!ensure_data())
return false;
if (!skip_pkg_rescan.test_and_set())
rescan_apps();
int app_id = to_app_id(uid);
if (app_id >= 90000) {
if (auto it = pkg_to_procs.find(ISOLATED_MAGIC); it != pkg_to_procs.end()) {

View File

@ -86,9 +86,9 @@ void clear_pkg(const char *pkg, int user_id);
[[noreturn]] void install_module(const char *file);
// Denylist
extern std::atomic_flag skip_pkg_rescan;
extern std::atomic<bool> denylist_enforced;
int denylist_cli(int argc, char **argv);
void initialize_denylist();
void scan_deny_apps();
bool is_deny_target(int uid, std::string_view process);
void revert_unmount(int pid = -1) noexcept;

View File

@ -38,7 +38,6 @@ void check_pkg_refresh() {
memcpy(app_ts, &st.st_mtim, sizeof(timespec));
}
skip_mgr_check = false;
skip_pkg_rescan.clear();
}
// app_id = app_no + AID_APP_START

View File

@ -159,8 +159,7 @@ void prune_su_access() {
for (int uid : rm_uids) {
ssprintf(query, sizeof(query), "DELETE FROM policies WHERE uid == %d", uid);
// Don't care about errors
db_exec(query);
db_err(db_exec(query));
}
}