mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-12-24 20:07:39 +00:00
Prune unused UIDs from su policies
This commit is contained in:
parent
e11508f84d
commit
975b1a5e36
@ -23,6 +23,7 @@ LOCAL_SRC_FILES := \
|
||||
core/bootstages.cpp \
|
||||
core/socket.cpp \
|
||||
core/db.cpp \
|
||||
core/package.cpp \
|
||||
core/cert.cpp \
|
||||
core/scripting.cpp \
|
||||
core/restorecon.cpp \
|
||||
|
@ -128,7 +128,7 @@ static bool magisk_env() {
|
||||
unlink(stub_path.data());
|
||||
|
||||
string pkg;
|
||||
get_manager(&pkg);
|
||||
get_manager(0, &pkg);
|
||||
|
||||
sprintf(buf, "%s/0/%s/install", APP_DATA_DIR,
|
||||
pkg.empty() ? "xxx" /* Ensure non-exist path */ : pkg.data());
|
||||
@ -376,7 +376,7 @@ void boot_complete(int client) {
|
||||
xmkdir(SECURE_DIR, 0700);
|
||||
|
||||
if (stub_fd > 0) {
|
||||
if (!get_manager()) {
|
||||
if (get_manager() < 0) {
|
||||
// Install stub
|
||||
struct stat st{};
|
||||
fstat(stub_fd, &st);
|
||||
|
@ -359,48 +359,6 @@ int get_db_strings(db_strings &str, int key) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
bool get_manager(int user_id, std::string *pkg, struct stat *st) {
|
||||
db_strings str;
|
||||
get_db_strings(str, SU_MANAGER);
|
||||
char app_path[128];
|
||||
|
||||
if (!str[SU_MANAGER].empty()) {
|
||||
// App is repackaged
|
||||
sprintf(app_path, "%s/%d/%s", APP_DATA_DIR, user_id, str[SU_MANAGER].data());
|
||||
if (stat(app_path, st) == 0) {
|
||||
if (pkg)
|
||||
pkg->swap(str[SU_MANAGER]);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// Check the official package name
|
||||
sprintf(app_path, "%s/%d/" JAVA_PACKAGE_NAME, APP_DATA_DIR, user_id);
|
||||
if (stat(app_path, st) == 0) {
|
||||
if (pkg)
|
||||
*pkg = JAVA_PACKAGE_NAME;
|
||||
return true;
|
||||
} else {
|
||||
LOGE("su: cannot find manager\n");
|
||||
memset(st, 0, sizeof(*st));
|
||||
if (pkg)
|
||||
pkg->clear();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool get_manager(string *pkg) {
|
||||
struct stat st;
|
||||
return get_manager(0, pkg, &st);
|
||||
}
|
||||
|
||||
int get_manager_app_id() {
|
||||
struct stat st;
|
||||
if (get_manager(0, nullptr, &st))
|
||||
return to_app_id(st.st_uid);
|
||||
return -1;
|
||||
}
|
||||
|
||||
void exec_sql(int client) {
|
||||
run_finally f([=]{ close(client); });
|
||||
string sql = read_string(client);
|
||||
|
114
native/jni/core/package.cpp
Normal file
114
native/jni/core/package.cpp
Normal file
@ -0,0 +1,114 @@
|
||||
#include <base.hpp>
|
||||
#include <magisk.hpp>
|
||||
#include <daemon.hpp>
|
||||
#include <db.hpp>
|
||||
|
||||
using namespace std;
|
||||
|
||||
// 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.
|
||||
|
||||
static atomic<ino_t> pkg_xml_ino = 0;
|
||||
|
||||
// pkg_lock protects mgr_app_id and mgr_pkg
|
||||
static pthread_mutex_t pkg_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static int mgr_app_id = -1;
|
||||
static string *mgr_pkg;
|
||||
|
||||
bool need_pkg_refresh() {
|
||||
struct stat st{};
|
||||
stat("/data/system/packages.xml", &st);
|
||||
ino_t ino = st.st_ino;
|
||||
if (pkg_xml_ino.compare_exchange_strong(ino, st.st_ino)) {
|
||||
// Packages have not changed
|
||||
return false;
|
||||
} else {
|
||||
mutex_guard g(pkg_lock);
|
||||
mgr_app_id = -1;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
// app_id = app_no + AID_APP_START
|
||||
// app_no range: [0, 9999]
|
||||
vector<bool> get_app_no_list() {
|
||||
vector<bool> list;
|
||||
auto data_dir = xopen_dir(APP_DATA_DIR);
|
||||
if (!data_dir)
|
||||
return list;
|
||||
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()))) {
|
||||
// For each package
|
||||
struct stat st{};
|
||||
xfstatat(dfd, entry->d_name, &st, 0);
|
||||
int app_id = to_app_id(st.st_uid);
|
||||
if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
|
||||
int app_no = app_id - AID_APP_START;
|
||||
if (list.size() <= app_no) {
|
||||
list.resize(app_no + 1);
|
||||
}
|
||||
list[app_no] = true;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
close(dfd);
|
||||
}
|
||||
}
|
||||
return list;
|
||||
}
|
||||
|
||||
int get_manager(int user_id, std::string *pkg) {
|
||||
mutex_guard g(pkg_lock);
|
||||
|
||||
char app_path[128];
|
||||
struct stat st{};
|
||||
if (mgr_pkg == nullptr)
|
||||
default_new(mgr_pkg);
|
||||
|
||||
int app_id = mgr_app_id;
|
||||
if (app_id > 0) {
|
||||
// Just need to check whether the app is installed in the user
|
||||
snprintf(app_path, sizeof(app_path), "%s/%d/%s", APP_DATA_DIR, user_id, mgr_pkg->data());
|
||||
if (access(app_path, F_OK) == 0) {
|
||||
if (pkg) *pkg = *mgr_pkg;
|
||||
return user_id * AID_USER_OFFSET + app_id;
|
||||
} else {
|
||||
goto not_found;
|
||||
}
|
||||
} else {
|
||||
db_strings str;
|
||||
get_db_strings(str, SU_MANAGER);
|
||||
|
||||
if (!str[SU_MANAGER].empty()) {
|
||||
// App is repackaged
|
||||
snprintf(app_path, sizeof(app_path),
|
||||
"%s/%d/%s", APP_DATA_DIR, user_id, str[SU_MANAGER].data());
|
||||
if (stat(app_path, &st) == 0) {
|
||||
mgr_pkg->swap(str[SU_MANAGER]);
|
||||
}
|
||||
} else {
|
||||
// Check the original package name
|
||||
snprintf(app_path, sizeof(app_path), "%s/%d/" JAVA_PACKAGE_NAME, APP_DATA_DIR, user_id);
|
||||
if (stat(app_path, &st) == 0) {
|
||||
*mgr_pkg = JAVA_PACKAGE_NAME;
|
||||
} else {
|
||||
goto not_found;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
mgr_app_id = to_app_id(st.st_uid);
|
||||
if (pkg) *pkg = *mgr_pkg;
|
||||
return st.st_uid;
|
||||
|
||||
not_found:
|
||||
LOGE("su: cannot find manager\n");
|
||||
if (pkg)
|
||||
pkg->clear();
|
||||
return -1;
|
||||
}
|
@ -9,6 +9,10 @@
|
||||
|
||||
#include <socket.hpp>
|
||||
|
||||
#define AID_APP_START 10000
|
||||
#define AID_APP_END 19999
|
||||
#define AID_USER_OFFSET 100000
|
||||
|
||||
// Daemon command codes
|
||||
namespace MainRequest {
|
||||
enum : int {
|
||||
@ -81,6 +85,11 @@ void denylist_handler(int client, const sock_cred *cred);
|
||||
void su_daemon_handler(int client, const sock_cred *cred);
|
||||
void zygisk_handler(int client, const sock_cred *cred);
|
||||
|
||||
// Package
|
||||
bool need_pkg_refresh();
|
||||
std::vector<bool> get_app_no_list();
|
||||
int get_manager(int user_id = 0, std::string *pkg = nullptr);
|
||||
|
||||
// Denylist
|
||||
void initialize_denylist();
|
||||
int denylist_cli(int argc, char **argv);
|
||||
|
@ -125,9 +125,6 @@ using db_row_cb = std::function<bool(db_row&)>;
|
||||
|
||||
int get_db_settings(db_settings &cfg, int key = -1);
|
||||
int get_db_strings(db_strings &str, int key = -1);
|
||||
bool get_manager(int user_id, std::string *pkg, struct stat *st);
|
||||
bool get_manager(std::string *pkg = nullptr);
|
||||
int get_manager_app_id();
|
||||
void exec_sql(int client);
|
||||
char *db_exec(const char *sql);
|
||||
char *db_exec(const char *sql, const db_row_cb &fn);
|
||||
|
@ -205,7 +205,7 @@ int app_request(const su_context &ctx) {
|
||||
strcpy(fifo, "/dev/socket/");
|
||||
gen_rand_str(fifo + 12, 32, true);
|
||||
mkfifo(fifo, 0600);
|
||||
chown(fifo, ctx.info->mgr_st.st_uid, ctx.info->mgr_st.st_gid);
|
||||
chown(fifo, ctx.info->mgr_uid, ctx.info->mgr_uid);
|
||||
setfilecon(fifo, "u:object_r:" SEPOL_FILE_TYPE ":s0");
|
||||
|
||||
// Send request
|
||||
|
@ -23,7 +23,7 @@ public:
|
||||
db_settings cfg;
|
||||
su_access access;
|
||||
std::string mgr_pkg;
|
||||
struct stat mgr_st;
|
||||
int mgr_uid;
|
||||
void check_db();
|
||||
|
||||
// These should be guarded with global cache lock
|
||||
|
@ -20,7 +20,7 @@ static pthread_mutex_t cache_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||
static shared_ptr<su_info> cached;
|
||||
|
||||
su_info::su_info(int uid) :
|
||||
uid(uid), eval_uid(-1), access(DEFAULT_SU_ACCESS), mgr_st{},
|
||||
uid(uid), eval_uid(-1), access(DEFAULT_SU_ACCESS), mgr_uid(-1),
|
||||
timestamp(0), _lock(PTHREAD_MUTEX_INITIALIZER) {}
|
||||
|
||||
su_info::~su_info() {
|
||||
@ -82,7 +82,7 @@ void su_info::check_db() {
|
||||
|
||||
// We need to check our manager
|
||||
if (access.log || access.notify)
|
||||
get_manager(to_user_id(eval_uid), &mgr_pkg, &mgr_st);
|
||||
mgr_uid = get_manager(to_user_id(eval_uid), &mgr_pkg);
|
||||
}
|
||||
|
||||
bool uid_granted_root(int uid) {
|
||||
@ -137,6 +137,32 @@ bool uid_granted_root(int uid) {
|
||||
return granted;
|
||||
}
|
||||
|
||||
static void prune_su_access() {
|
||||
vector<bool> app_no_list = get_app_no_list();
|
||||
vector<int> rm_uids;
|
||||
char query[256], *err;
|
||||
strlcpy(query, "SELECT uid FROM policies", sizeof(query));
|
||||
err = db_exec(query, [&](db_row &row) -> bool {
|
||||
int uid = parse_int(row["uid"]);
|
||||
int app_id = to_app_id(uid);
|
||||
if (app_id >= AID_APP_START && app_id <= AID_APP_END) {
|
||||
int app_no = app_id - AID_APP_START;
|
||||
if (app_no >= app_no_list.size() || !app_no_list[app_no]) {
|
||||
// The app_id is no longer installed
|
||||
rm_uids.push_back(uid);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
});
|
||||
db_err_cmd(err, return);
|
||||
|
||||
for (int uid : rm_uids) {
|
||||
snprintf(query, sizeof(query), "DELETE FROM policies WHERE uid == %d", uid);
|
||||
// Don't care about errors
|
||||
db_exec(query);
|
||||
}
|
||||
}
|
||||
|
||||
static shared_ptr<su_info> get_su_info(unsigned uid) {
|
||||
LOGD("su: request from uid=[%d]\n", uid);
|
||||
|
||||
@ -144,6 +170,10 @@ static shared_ptr<su_info> get_su_info(unsigned uid) {
|
||||
|
||||
{
|
||||
mutex_guard lock(cache_lock);
|
||||
if (need_pkg_refresh()) {
|
||||
cached.reset();
|
||||
prune_su_access();
|
||||
}
|
||||
if (!cached || cached->uid != uid || !cached->is_fresh())
|
||||
cached = make_shared<su_info>(uid);
|
||||
cached->refresh();
|
||||
@ -157,7 +187,7 @@ static shared_ptr<su_info> get_su_info(unsigned uid) {
|
||||
info->check_db();
|
||||
|
||||
// If it's root or the manager, allow it silently
|
||||
if (info->uid == UID_ROOT || to_app_id(info->uid) == to_app_id(info->mgr_st.st_uid)) {
|
||||
if (info->uid == UID_ROOT || to_app_id(info->uid) == to_app_id(info->mgr_uid)) {
|
||||
info->access = SILENT_SU_ACCESS;
|
||||
return info;
|
||||
}
|
||||
@ -189,7 +219,7 @@ static shared_ptr<su_info> get_su_info(unsigned uid) {
|
||||
return info;
|
||||
|
||||
// If still not determined, check if manager exists
|
||||
if (info->mgr_pkg.empty()) {
|
||||
if (info->mgr_uid < 0) {
|
||||
info->access = NO_SU_ACCESS;
|
||||
return info;
|
||||
}
|
||||
|
@ -47,8 +47,6 @@ void ls_list(int client);
|
||||
|
||||
// Utility functions
|
||||
bool is_deny_target(int uid, std::string_view process);
|
||||
|
||||
void revert_unmount();
|
||||
|
||||
extern std::atomic<bool> denylist_enforced;
|
||||
extern std::atomic<int> cached_manager_app_id;
|
||||
|
@ -32,23 +32,13 @@ atomic<bool> denylist_enforced = false;
|
||||
|
||||
#define do_kill (zygisk_enabled && denylist_enforced)
|
||||
|
||||
static unsigned long long pkg_xml_ino = 0;
|
||||
|
||||
static void rescan_apps() {
|
||||
{
|
||||
struct stat st{};
|
||||
stat("/data/system/packages.xml", &st);
|
||||
if (pkg_xml_ino == st.st_ino) {
|
||||
// Packages has not changed, do not rescan
|
||||
return;
|
||||
}
|
||||
pkg_xml_ino = st.st_ino;
|
||||
}
|
||||
if (!need_pkg_refresh())
|
||||
return;
|
||||
|
||||
LOGD("denylist: rescanning apps\n");
|
||||
|
||||
app_id_to_pkgs.clear();
|
||||
cached_manager_app_id = -1;
|
||||
|
||||
auto data_dir = xopen_dir(APP_DATA_DIR);
|
||||
if (!data_dir)
|
||||
|
@ -7,7 +7,6 @@
|
||||
#include <base.hpp>
|
||||
#include <daemon.hpp>
|
||||
#include <magisk.hpp>
|
||||
#include <db.hpp>
|
||||
|
||||
#include "zygisk.hpp"
|
||||
#include "module.hpp"
|
||||
@ -313,8 +312,6 @@ static void magiskd_passthrough(int client) {
|
||||
send_fd(client, is_64_bit ? app_process_64 : app_process_32);
|
||||
}
|
||||
|
||||
atomic<int> cached_manager_app_id = -1;
|
||||
|
||||
extern bool uid_granted_root(int uid);
|
||||
static void get_process_info(int client, const sock_cred *cred) {
|
||||
int uid = read_int(client);
|
||||
@ -322,19 +319,10 @@ static void get_process_info(int client, const sock_cred *cred) {
|
||||
|
||||
uint32_t flags = 0;
|
||||
|
||||
// This function is called on every single zygote process specialization,
|
||||
// so performance is critical. get_manager_app_id() is expensive as it goes
|
||||
// through a SQLite query and potentially multiple filesystem stats, so we
|
||||
// really want to cache its app ID value.
|
||||
|
||||
if (is_deny_target(uid, process)) {
|
||||
flags |= PROCESS_ON_DENYLIST;
|
||||
}
|
||||
int manager_app_id = cached_manager_app_id;
|
||||
if (manager_app_id < 0) {
|
||||
manager_app_id = get_manager_app_id();
|
||||
cached_manager_app_id = manager_app_id;
|
||||
}
|
||||
int manager_app_id = get_manager();
|
||||
if (to_app_id(uid) == manager_app_id) {
|
||||
flags |= PROCESS_IS_MAGISK_APP;
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user