mirror of
https://github.com/topjohnwu/Magisk.git
synced 2025-07-16 22:18:33 +00:00
Add Zygisk API getFlags()
This commit is contained in:
parent
76ddfeb93a
commit
bb7a74e4b4
@ -11,10 +11,13 @@
|
|||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
typedef struct sqlite3 sqlite3;
|
struct sqlite3;
|
||||||
|
|
||||||
static sqlite3 *mDB = nullptr;
|
static sqlite3 *mDB = nullptr;
|
||||||
|
|
||||||
|
#define DBLOGV(...)
|
||||||
|
//#define DBLOGV(...) LOGD("magiskdb: " __VA_ARGS__)
|
||||||
|
|
||||||
// SQLite APIs
|
// SQLite APIs
|
||||||
|
|
||||||
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
|
#define SQLITE_OPEN_READWRITE 0x00000002 /* Ok for sqlite3_open_v2() */
|
||||||
@ -294,7 +297,7 @@ int get_db_settings(db_settings &cfg, int key) {
|
|||||||
char *err;
|
char *err;
|
||||||
auto settings_cb = [&](db_row &row) -> bool {
|
auto settings_cb = [&](db_row &row) -> bool {
|
||||||
cfg[row["key"]] = parse_int(row["value"]);
|
cfg[row["key"]] = parse_int(row["value"]);
|
||||||
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
|
DBLOGV("query %s=[%s]\n", row["key"].data(), row["value"].data());
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
if (key >= 0) {
|
if (key >= 0) {
|
||||||
@ -312,7 +315,7 @@ int get_db_strings(db_strings &str, int key) {
|
|||||||
char *err;
|
char *err;
|
||||||
auto string_cb = [&](db_row &row) -> bool {
|
auto string_cb = [&](db_row &row) -> bool {
|
||||||
str[row["key"]] = row["value"];
|
str[row["key"]] = row["value"];
|
||||||
LOGD("magiskdb: query %s=[%s]\n", row["key"].data(), row["value"].data());
|
DBLOGV("query %s=[%s]\n", row["key"].data(), row["value"].data());
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
if (key >= 0) {
|
if (key >= 0) {
|
||||||
@ -326,21 +329,6 @@ int get_db_strings(db_strings &str, int key) {
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
int get_uid_policy(su_access &su, int uid) {
|
|
||||||
char query[256], *err;
|
|
||||||
sprintf(query, "SELECT policy, logging, notification FROM policies "
|
|
||||||
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
|
|
||||||
err = db_exec(query, [&](db_row &row) -> bool {
|
|
||||||
su.policy = (policy_t) parse_int(row["policy"]);
|
|
||||||
su.log = parse_int(row["logging"]);
|
|
||||||
su.notify = parse_int(row["notification"]);
|
|
||||||
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n", su.policy, su.log, su.notify);
|
|
||||||
return true;
|
|
||||||
});
|
|
||||||
db_err_cmd(err, return 1);
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool get_manager(int user_id, std::string *pkg, struct stat *st) {
|
bool get_manager(int user_id, std::string *pkg, struct stat *st) {
|
||||||
db_strings str;
|
db_strings str;
|
||||||
get_db_strings(str, SU_MANAGER);
|
get_db_strings(str, SU_MANAGER);
|
||||||
|
@ -125,7 +125,6 @@ using db_row_cb = std::function<bool(db_row&)>;
|
|||||||
|
|
||||||
int get_db_settings(db_settings &cfg, int key = -1);
|
int get_db_settings(db_settings &cfg, int key = -1);
|
||||||
int get_db_strings(db_strings &str, int key = -1);
|
int get_db_strings(db_strings &str, int key = -1);
|
||||||
int get_uid_policy(su_access &su, int uid);
|
|
||||||
bool get_manager(int user_id, std::string *pkg, struct stat *st);
|
bool get_manager(int user_id, std::string *pkg, struct stat *st);
|
||||||
bool get_manager(std::string *pkg = nullptr);
|
bool get_manager(std::string *pkg = nullptr);
|
||||||
int get_manager_app_id();
|
int get_manager_app_id();
|
||||||
|
@ -64,14 +64,81 @@ static void database_check(const shared_ptr<su_info> &info) {
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (uid > 0)
|
su_access &su = info->access;
|
||||||
get_uid_policy(info->access, uid);
|
|
||||||
|
if (uid > 0) {
|
||||||
|
char query[256], *err;
|
||||||
|
sprintf(query,
|
||||||
|
"SELECT policy, logging, notification FROM policies "
|
||||||
|
"WHERE uid=%d AND (until=0 OR until>%li)", uid, time(nullptr));
|
||||||
|
err = db_exec(query, [&](db_row &row) -> bool {
|
||||||
|
su.policy = (policy_t) parse_int(row["policy"]);
|
||||||
|
su.log = parse_int(row["logging"]);
|
||||||
|
su.notify = parse_int(row["notification"]);
|
||||||
|
LOGD("magiskdb: query policy=[%d] log=[%d] notify=[%d]\n",
|
||||||
|
su.policy, su.log, su.notify);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
db_err_cmd(err, return);
|
||||||
|
}
|
||||||
|
|
||||||
// We need to check our manager
|
// We need to check our manager
|
||||||
if (info->access.log || info->access.notify)
|
if (su.log || su.notify)
|
||||||
get_manager(to_user_id(uid), &info->mgr_pkg, &info->mgr_st);
|
get_manager(to_user_id(uid), &info->mgr_pkg, &info->mgr_st);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool uid_granted_root(int uid) {
|
||||||
|
if (uid == UID_ROOT)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
db_settings cfg;
|
||||||
|
get_db_settings(cfg);
|
||||||
|
|
||||||
|
// Check user root access settings
|
||||||
|
switch (cfg[ROOT_ACCESS]) {
|
||||||
|
case ROOT_ACCESS_DISABLED:
|
||||||
|
return false;
|
||||||
|
case ROOT_ACCESS_APPS_ONLY:
|
||||||
|
if (uid == UID_SHELL)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case ROOT_ACCESS_ADB_ONLY:
|
||||||
|
if (uid != UID_SHELL)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case ROOT_ACCESS_APPS_AND_ADB:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check multiuser settings
|
||||||
|
switch (cfg[SU_MULTIUSER_MODE]) {
|
||||||
|
case MULTIUSER_MODE_OWNER_ONLY:
|
||||||
|
if (to_user_id(uid) != 0)
|
||||||
|
return false;
|
||||||
|
break;
|
||||||
|
case MULTIUSER_MODE_OWNER_MANAGED:
|
||||||
|
uid = to_app_id(uid);
|
||||||
|
break;
|
||||||
|
case MULTIUSER_MODE_USER:
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool granted = false;
|
||||||
|
|
||||||
|
char query[256], *err;
|
||||||
|
snprintf(query, sizeof(query),
|
||||||
|
"SELECT policy FROM policies WHERE uid=%d AND (until=0 OR until>%li)",
|
||||||
|
uid, time(nullptr));
|
||||||
|
err = db_exec(query, [&](db_row &row) -> bool {
|
||||||
|
granted = parse_int(row["policy"]) == ALLOW;
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
db_err_cmd(err, return false);
|
||||||
|
|
||||||
|
return granted;
|
||||||
|
}
|
||||||
|
|
||||||
static shared_ptr<su_info> get_su_info(unsigned uid) {
|
static shared_ptr<su_info> get_su_info(unsigned uid) {
|
||||||
LOGD("su: request from uid=[%d]\n", uid);
|
LOGD("su: request from uid=[%d]\n", uid);
|
||||||
|
|
||||||
|
@ -138,20 +138,25 @@ enum Option : int {
|
|||||||
// Setting this option only makes sense in preAppSpecialize.
|
// Setting this option only makes sense in preAppSpecialize.
|
||||||
// The actual unmounting happens during app process specialization.
|
// The actual unmounting happens during app process specialization.
|
||||||
//
|
//
|
||||||
// Processes added to Magisk's denylist will have all Magisk and its modules' files unmounted
|
// Set this option to force all Magisk and modules' files to be unmounted from the
|
||||||
// from its mount namespace. In addition, all Zygisk code will be unloaded from memory, which
|
// mount namespace of the process, regardless of the denylist enforcement status.
|
||||||
// also implies that no Zygisk modules (including yours) are loaded.
|
|
||||||
//
|
|
||||||
// However, if for any reason your module still wants the unmount part of the denylist
|
|
||||||
// operation to be enabled EVEN IF THE PROCESS IS NOT ON THE DENYLIST, set this option.
|
|
||||||
FORCE_DENYLIST_UNMOUNT = 0,
|
FORCE_DENYLIST_UNMOUNT = 0,
|
||||||
|
|
||||||
// When this option is set, your module's library will be dlclose-ed after post[XXX]Specialize.
|
// When this option is set, your module's library will be dlclose-ed after post[XXX]Specialize.
|
||||||
// Be aware that after dlclose-ing your module, all of your code will be unmapped.
|
// Be aware that after dlclose-ing your module, all of your code will be unmapped from memory.
|
||||||
// YOU SHOULD NOT ENABLE THIS OPTION AFTER HOOKING ANY FUNCTION IN THE PROCESS.
|
// YOU MUST NOT ENABLE THIS OPTION AFTER HOOKING ANY FUNCTIONS IN THE PROCESS.
|
||||||
DLCLOSE_MODULE_LIBRARY = 1,
|
DLCLOSE_MODULE_LIBRARY = 1,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Bit masks of the return value of Api::getFlags()
|
||||||
|
enum StateFlag : uint32_t {
|
||||||
|
// The user has granted root access to the current process
|
||||||
|
PROCESS_GRANTED_ROOT = (1u << 0),
|
||||||
|
|
||||||
|
// The current process was added on the denylist
|
||||||
|
PROCESS_ON_DENYLIST = (1u << 1),
|
||||||
|
};
|
||||||
|
|
||||||
// All API functions will stop working after post[XXX]Specialize as Zygisk will be unloaded
|
// All API functions will stop working after post[XXX]Specialize as Zygisk will be unloaded
|
||||||
// from the specialized process afterwards.
|
// from the specialized process afterwards.
|
||||||
struct Api {
|
struct Api {
|
||||||
@ -188,6 +193,10 @@ struct Api {
|
|||||||
// Check zygisk::Option for the full list of options available.
|
// Check zygisk::Option for the full list of options available.
|
||||||
void setOption(Option opt);
|
void setOption(Option opt);
|
||||||
|
|
||||||
|
// Get information about the current process.
|
||||||
|
// Returns bitwise-or'd zygisk::StateFlag values.
|
||||||
|
uint32_t getFlags();
|
||||||
|
|
||||||
// Hook JNI native methods for a class
|
// Hook JNI native methods for a class
|
||||||
//
|
//
|
||||||
// Lookup all registered JNI native methods and replace it with your own functions.
|
// Lookup all registered JNI native methods and replace it with your own functions.
|
||||||
@ -272,6 +281,7 @@ struct api_table {
|
|||||||
int (*connectCompanion)(void * /* _this */);
|
int (*connectCompanion)(void * /* _this */);
|
||||||
void (*setOption)(void * /* _this */, Option);
|
void (*setOption)(void * /* _this */, Option);
|
||||||
int (*getModuleDir)(void * /* _this */);
|
int (*getModuleDir)(void * /* _this */);
|
||||||
|
uint32_t (*getFlags)(void * /* _this */);
|
||||||
};
|
};
|
||||||
|
|
||||||
template <class T>
|
template <class T>
|
||||||
@ -295,6 +305,9 @@ inline int Api::getModuleDir() {
|
|||||||
inline void Api::setOption(Option opt) {
|
inline void Api::setOption(Option opt) {
|
||||||
if (impl->setOption) impl->setOption(impl->_this, opt);
|
if (impl->setOption) impl->setOption(impl->_this, opt);
|
||||||
}
|
}
|
||||||
|
inline uint32_t Api::getFlags() {
|
||||||
|
return impl->getFlags ? impl->getFlags(impl->_this) : 0;
|
||||||
|
}
|
||||||
inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) {
|
inline void Api::hookJniNativeMethods(JNIEnv *env, const char *className, JNINativeMethod *methods, int numMethods) {
|
||||||
if (impl->hookJniNativeMethods) impl->hookJniNativeMethods(env, className, methods, numMethods);
|
if (impl->hookJniNativeMethods) impl->hookJniNativeMethods(env, className, methods, numMethods);
|
||||||
}
|
}
|
||||||
|
@ -51,7 +51,7 @@ void denylist_handler(int client, const sock_cred *cred) {
|
|||||||
ls_list(client);
|
ls_list(client);
|
||||||
return;
|
return;
|
||||||
case DENY_STATUS:
|
case DENY_STATUS:
|
||||||
res = (zygisk_enabled && denylist_enabled) ? DENY_IS_ENFORCED : DENY_NOT_ENFORCED;
|
res = (zygisk_enabled && denylist_enforced) ? DENY_IS_ENFORCED : DENY_NOT_ENFORCED;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -22,7 +22,7 @@ bool is_deny_target(int uid, std::string_view process);
|
|||||||
|
|
||||||
void revert_unmount();
|
void revert_unmount();
|
||||||
|
|
||||||
extern std::atomic<bool> denylist_enabled;
|
extern std::atomic<bool> denylist_enforced;
|
||||||
extern std::atomic<int> cached_manager_app_id;
|
extern std::atomic<int> cached_manager_app_id;
|
||||||
|
|
||||||
enum : int {
|
enum : int {
|
||||||
|
@ -21,9 +21,9 @@ static int inotify_fd = -1;
|
|||||||
// Locks the variables above
|
// Locks the variables above
|
||||||
static pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER;
|
static pthread_mutex_t data_lock = PTHREAD_MUTEX_INITIALIZER;
|
||||||
|
|
||||||
atomic<bool> denylist_enabled = false;
|
atomic<bool> denylist_enforced = false;
|
||||||
|
|
||||||
#define do_kill (zygisk_enabled && denylist_enabled)
|
#define do_kill (zygisk_enabled && denylist_enforced)
|
||||||
|
|
||||||
static void rebuild_map() {
|
static void rebuild_map() {
|
||||||
app_id_proc_map->clear();
|
app_id_proc_map->clear();
|
||||||
@ -317,13 +317,13 @@ static bool str_ends_safe(string_view s, string_view ss) {
|
|||||||
static void update_deny_config() {
|
static void update_deny_config() {
|
||||||
char sql[64];
|
char sql[64];
|
||||||
sprintf(sql, "REPLACE INTO settings (key,value) VALUES('%s',%d)",
|
sprintf(sql, "REPLACE INTO settings (key,value) VALUES('%s',%d)",
|
||||||
DB_SETTING_KEYS[DENYLIST_CONFIG], denylist_enabled.load());
|
DB_SETTING_KEYS[DENYLIST_CONFIG], denylist_enforced.load());
|
||||||
char *err = db_exec(sql);
|
char *err = db_exec(sql);
|
||||||
db_err(err);
|
db_err(err);
|
||||||
}
|
}
|
||||||
|
|
||||||
int enable_deny() {
|
int enable_deny() {
|
||||||
if (denylist_enabled) {
|
if (denylist_enforced) {
|
||||||
return DAEMON_SUCCESS;
|
return DAEMON_SUCCESS;
|
||||||
} else {
|
} else {
|
||||||
mutex_guard lock(data_lock);
|
mutex_guard lock(data_lock);
|
||||||
@ -338,10 +338,10 @@ int enable_deny() {
|
|||||||
|
|
||||||
LOGI("* Enable DenyList\n");
|
LOGI("* Enable DenyList\n");
|
||||||
|
|
||||||
denylist_enabled = true;
|
denylist_enforced = true;
|
||||||
|
|
||||||
if (!ensure_data()) {
|
if (!ensure_data()) {
|
||||||
denylist_enabled = false;
|
denylist_enforced = false;
|
||||||
return DAEMON_ERROR;
|
return DAEMON_ERROR;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -358,8 +358,8 @@ int enable_deny() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
int disable_deny() {
|
int disable_deny() {
|
||||||
if (denylist_enabled) {
|
if (denylist_enforced) {
|
||||||
denylist_enabled = false;
|
denylist_enforced = false;
|
||||||
LOGI("* Disable DenyList\n");
|
LOGI("* Disable DenyList\n");
|
||||||
|
|
||||||
mutex_guard lock(data_lock);
|
mutex_guard lock(data_lock);
|
||||||
@ -370,7 +370,7 @@ int disable_deny() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void initialize_denylist() {
|
void initialize_denylist() {
|
||||||
if (!denylist_enabled) {
|
if (!denylist_enforced) {
|
||||||
db_settings dbs;
|
db_settings dbs;
|
||||||
get_db_settings(dbs, DENYLIST_CONFIG);
|
get_db_settings(dbs, DENYLIST_CONFIG);
|
||||||
if (dbs[DENYLIST_CONFIG])
|
if (dbs[DENYLIST_CONFIG])
|
||||||
|
@ -9,6 +9,7 @@
|
|||||||
#include <db.hpp>
|
#include <db.hpp>
|
||||||
|
|
||||||
#include "zygisk.hpp"
|
#include "zygisk.hpp"
|
||||||
|
#include "module.hpp"
|
||||||
#include "deny/deny.hpp"
|
#include "deny/deny.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -166,7 +167,7 @@ static int zygisk_log(int prio, const char *fmt, va_list ap) {
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<int> remote_get_info(int uid, const char *process, AppInfo *info) {
|
std::vector<int> remote_get_info(int uid, const char *process, uint32_t *flags) {
|
||||||
vector<int> fds;
|
vector<int> fds;
|
||||||
if (int fd = connect_daemon(); fd >= 0) {
|
if (int fd = connect_daemon(); fd >= 0) {
|
||||||
write_int(fd, ZYGISK_REQUEST);
|
write_int(fd, ZYGISK_REQUEST);
|
||||||
@ -174,8 +175,8 @@ std::vector<int> remote_get_info(int uid, const char *process, AppInfo *info) {
|
|||||||
|
|
||||||
write_int(fd, uid);
|
write_int(fd, uid);
|
||||||
write_string(fd, process);
|
write_string(fd, process);
|
||||||
xxread(fd, info, sizeof(*info));
|
xxread(fd, flags, sizeof(*flags));
|
||||||
if (!info->on_denylist) {
|
if ((*flags & UNMOUNT_MASK) != UNMOUNT_MASK) {
|
||||||
fds = recv_fds(fd);
|
fds = recv_fds(fd);
|
||||||
}
|
}
|
||||||
close(fd);
|
close(fd);
|
||||||
@ -314,11 +315,13 @@ static void magiskd_passthrough(int client) {
|
|||||||
|
|
||||||
atomic<int> cached_manager_app_id = -1;
|
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) {
|
static void get_process_info(int client, const sock_cred *cred) {
|
||||||
AppInfo info{};
|
|
||||||
int uid = read_int(client);
|
int uid = read_int(client);
|
||||||
string process = read_string(client);
|
string process = read_string(client);
|
||||||
|
|
||||||
|
uint32_t flags = 0;
|
||||||
|
|
||||||
// This function is called on every single zygote process specialization,
|
// This function is called on every single zygote process specialization,
|
||||||
// so performance is critical. get_manager_app_id() is expensive as it goes
|
// so performance is critical. get_manager_app_id() is expensive as it goes
|
||||||
// through a SQLite query and potentially multiple filesystem stats, so we
|
// through a SQLite query and potentially multiple filesystem stats, so we
|
||||||
@ -334,15 +337,22 @@ static void get_process_info(int client, const sock_cred *cred) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (to_app_id(uid) == manager_app_id) {
|
if (to_app_id(uid) == manager_app_id) {
|
||||||
info.is_magisk_app = true;
|
flags |= PROCESS_IS_MAGISK_APP;
|
||||||
} else if (denylist_enabled) {
|
}
|
||||||
info.on_denylist = is_deny_target(uid, process);
|
if (denylist_enforced) {
|
||||||
|
flags |= DENYLIST_ENFORCING;
|
||||||
|
}
|
||||||
|
if (is_deny_target(uid, process)) {
|
||||||
|
flags |= PROCESS_ON_DENYLIST;
|
||||||
|
}
|
||||||
|
if (uid_granted_root(uid)) {
|
||||||
|
flags |= PROCESS_GRANTED_ROOT;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
xwrite(client, &info, sizeof(info));
|
xwrite(client, &flags, sizeof(flags));
|
||||||
|
|
||||||
if (!info.on_denylist) {
|
if ((flags & UNMOUNT_MASK) != UNMOUNT_MASK) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
get_exe(cred->pid, buf, sizeof(buf));
|
get_exe(cred->pid, buf, sizeof(buf));
|
||||||
vector<int> fds = get_module_fds(str_ends(buf, "64"));
|
vector<int> fds = get_module_fds(str_ends(buf, "64"));
|
||||||
|
@ -26,7 +26,7 @@ static bool unhook_functions();
|
|||||||
namespace {
|
namespace {
|
||||||
|
|
||||||
enum {
|
enum {
|
||||||
UNMOUNT_FLAG,
|
DO_UNMOUNT,
|
||||||
FORK_AND_SPECIALIZE,
|
FORK_AND_SPECIALIZE,
|
||||||
APP_SPECIALIZE,
|
APP_SPECIALIZE,
|
||||||
SERVER_SPECIALIZE,
|
SERVER_SPECIALIZE,
|
||||||
@ -46,12 +46,13 @@ struct HookContext {
|
|||||||
void *raw_args;
|
void *raw_args;
|
||||||
};
|
};
|
||||||
const char *process;
|
const char *process;
|
||||||
int pid;
|
|
||||||
bitset<FLAG_MAX> flags;
|
|
||||||
AppInfo info;
|
|
||||||
vector<ZygiskModule> modules;
|
vector<ZygiskModule> modules;
|
||||||
|
bitset<FLAG_MAX> state;
|
||||||
|
|
||||||
HookContext() : pid(-1), info{} {}
|
int pid;
|
||||||
|
uint32_t flags;
|
||||||
|
|
||||||
|
HookContext() : pid(-1), flags(0) {}
|
||||||
|
|
||||||
static void close_fds();
|
static void close_fds();
|
||||||
void unload_zygisk();
|
void unload_zygisk();
|
||||||
@ -154,7 +155,7 @@ DCL_HOOK_FUNC(int, fork) {
|
|||||||
DCL_HOOK_FUNC(int, unshare, int flags) {
|
DCL_HOOK_FUNC(int, unshare, int flags) {
|
||||||
int res = old_unshare(flags);
|
int res = old_unshare(flags);
|
||||||
if (g_ctx && (flags & CLONE_NEWNS) != 0 && res == 0) {
|
if (g_ctx && (flags & CLONE_NEWNS) != 0 && res == 0) {
|
||||||
if (g_ctx->flags[UNMOUNT_FLAG]) {
|
if (g_ctx->state[DO_UNMOUNT]) {
|
||||||
revert_unmount();
|
revert_unmount();
|
||||||
} else {
|
} else {
|
||||||
umount2("/system/bin/app_process64", MNT_DETACH);
|
umount2("/system/bin/app_process64", MNT_DETACH);
|
||||||
@ -174,7 +175,7 @@ DCL_HOOK_FUNC(void, android_log_close) {
|
|||||||
DCL_HOOK_FUNC(int, selinux_android_setcontext,
|
DCL_HOOK_FUNC(int, selinux_android_setcontext,
|
||||||
uid_t uid, int isSystemServer, const char *seinfo, const char *pkgname) {
|
uid_t uid, int isSystemServer, const char *seinfo, const char *pkgname) {
|
||||||
if (g_ctx) {
|
if (g_ctx) {
|
||||||
g_ctx->flags[CAN_DLCLOSE] = unhook_functions();
|
g_ctx->state[CAN_DLCLOSE] = unhook_functions();
|
||||||
}
|
}
|
||||||
return old_selinux_android_setcontext(uid, isSystemServer, seinfo, pkgname);
|
return old_selinux_android_setcontext(uid, isSystemServer, seinfo, pkgname);
|
||||||
}
|
}
|
||||||
@ -297,6 +298,7 @@ bool ZygiskModule::RegisterModule(ApiTable *table, long *module) {
|
|||||||
switch (ver) {
|
switch (ver) {
|
||||||
case 2:
|
case 2:
|
||||||
table->v2.getModuleDir = [](ZygiskModule *m) { return m->getModuleDir(); };
|
table->v2.getModuleDir = [](ZygiskModule *m) { return m->getModuleDir(); };
|
||||||
|
table->v2.getFlags = [](auto) { return ZygiskModule::getFlags(); };
|
||||||
[[fallthrough]];
|
[[fallthrough]];
|
||||||
case 1:
|
case 1:
|
||||||
table->v1.hookJniNativeMethods = &hookJniNativeMethods;
|
table->v1.hookJniNativeMethods = &hookJniNativeMethods;
|
||||||
@ -345,7 +347,7 @@ void ZygiskModule::setOption(zygisk::Option opt) {
|
|||||||
return;
|
return;
|
||||||
switch (opt) {
|
switch (opt) {
|
||||||
case zygisk::FORCE_DENYLIST_UNMOUNT:
|
case zygisk::FORCE_DENYLIST_UNMOUNT:
|
||||||
g_ctx->flags[UNMOUNT_FLAG] = true;
|
g_ctx->state[DO_UNMOUNT] = true;
|
||||||
break;
|
break;
|
||||||
case zygisk::DLCLOSE_MODULE_LIBRARY:
|
case zygisk::DLCLOSE_MODULE_LIBRARY:
|
||||||
unload = true;
|
unload = true;
|
||||||
@ -353,6 +355,10 @@ void ZygiskModule::setOption(zygisk::Option opt) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uint32_t ZygiskModule::getFlags() {
|
||||||
|
return g_ctx ? (g_ctx->flags & ~PRIVATE_MASK) : 0;
|
||||||
|
}
|
||||||
|
|
||||||
void HookContext::run_modules_pre(const vector<int> &fds) {
|
void HookContext::run_modules_pre(const vector<int> &fds) {
|
||||||
char buf[256];
|
char buf[256];
|
||||||
|
|
||||||
@ -384,9 +390,9 @@ void HookContext::run_modules_pre(const vector<int> &fds) {
|
|||||||
|
|
||||||
for (auto &m : modules) {
|
for (auto &m : modules) {
|
||||||
m.entry(&m.api, env);
|
m.entry(&m.api, env);
|
||||||
if (flags[APP_SPECIALIZE]) {
|
if (state[APP_SPECIALIZE]) {
|
||||||
m.preAppSpecialize(args);
|
m.preAppSpecialize(args);
|
||||||
} else if (flags[SERVER_SPECIALIZE]) {
|
} else if (state[SERVER_SPECIALIZE]) {
|
||||||
m.preServerSpecialize(server_args);
|
m.preServerSpecialize(server_args);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -403,9 +409,9 @@ void HookContext::run_modules_pre(const vector<int> &fds) {
|
|||||||
|
|
||||||
void HookContext::run_modules_post() {
|
void HookContext::run_modules_post() {
|
||||||
for (const auto &m : modules) {
|
for (const auto &m : modules) {
|
||||||
if (flags[APP_SPECIALIZE]) {
|
if (state[APP_SPECIALIZE]) {
|
||||||
m.postAppSpecialize(args);
|
m.postAppSpecialize(args);
|
||||||
} else if (flags[SERVER_SPECIALIZE]) {
|
} else if (state[SERVER_SPECIALIZE]) {
|
||||||
m.postServerSpecialize(server_args);
|
m.postServerSpecialize(server_args);
|
||||||
}
|
}
|
||||||
m.doUnload();
|
m.doUnload();
|
||||||
@ -417,7 +423,7 @@ void HookContext::close_fds() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HookContext::unload_zygisk() {
|
void HookContext::unload_zygisk() {
|
||||||
if (flags[CAN_DLCLOSE]) {
|
if (state[CAN_DLCLOSE]) {
|
||||||
// Do NOT call the destructor
|
// Do NOT call the destructor
|
||||||
operator delete(jni_method_map);
|
operator delete(jni_method_map);
|
||||||
// Directly unmap the whole memory block
|
// Directly unmap the whole memory block
|
||||||
@ -436,19 +442,19 @@ void HookContext::unload_zygisk() {
|
|||||||
|
|
||||||
void HookContext::nativeSpecializeAppProcess_pre() {
|
void HookContext::nativeSpecializeAppProcess_pre() {
|
||||||
g_ctx = this;
|
g_ctx = this;
|
||||||
flags[APP_SPECIALIZE] = true;
|
state[APP_SPECIALIZE] = true;
|
||||||
process = env->GetStringUTFChars(args->nice_name, nullptr);
|
process = env->GetStringUTFChars(args->nice_name, nullptr);
|
||||||
if (flags[FORK_AND_SPECIALIZE]) {
|
if (state[FORK_AND_SPECIALIZE]) {
|
||||||
ZLOGV("pre forkAndSpecialize [%s]\n", process);
|
ZLOGV("pre forkAndSpecialize [%s]\n", process);
|
||||||
} else {
|
} else {
|
||||||
ZLOGV("pre specialize [%s]\n", process);
|
ZLOGV("pre specialize [%s]\n", process);
|
||||||
}
|
}
|
||||||
|
|
||||||
auto module_fds = remote_get_info(args->uid, process, &info);
|
auto module_fds = remote_get_info(args->uid, process, &flags);
|
||||||
if (info.on_denylist) {
|
if ((flags & UNMOUNT_MASK) == UNMOUNT_MASK) {
|
||||||
// TODO: Handle MOUNT_EXTERNAL_NONE on older platforms
|
// TODO: Handle MOUNT_EXTERNAL_NONE on older platforms
|
||||||
ZLOGI("[%s] is on the denylist\n", process);
|
ZLOGI("[%s] is on the denylist\n", process);
|
||||||
flags[UNMOUNT_FLAG] = true;
|
state[DO_UNMOUNT] = true;
|
||||||
} else {
|
} else {
|
||||||
run_modules_pre(module_fds);
|
run_modules_pre(module_fds);
|
||||||
}
|
}
|
||||||
@ -458,7 +464,7 @@ void HookContext::nativeSpecializeAppProcess_pre() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
void HookContext::nativeSpecializeAppProcess_post() {
|
void HookContext::nativeSpecializeAppProcess_post() {
|
||||||
if (flags[FORK_AND_SPECIALIZE]) {
|
if (state[FORK_AND_SPECIALIZE]) {
|
||||||
ZLOGV("post forkAndSpecialize [%s]\n", process);
|
ZLOGV("post forkAndSpecialize [%s]\n", process);
|
||||||
} else {
|
} else {
|
||||||
ZLOGV("post specialize [%s]\n", process);
|
ZLOGV("post specialize [%s]\n", process);
|
||||||
@ -466,21 +472,21 @@ void HookContext::nativeSpecializeAppProcess_post() {
|
|||||||
|
|
||||||
env->ReleaseStringUTFChars(args->nice_name, process);
|
env->ReleaseStringUTFChars(args->nice_name, process);
|
||||||
run_modules_post();
|
run_modules_post();
|
||||||
if (info.is_magisk_app) {
|
if (flags & PROCESS_IS_MAGISK_APP) {
|
||||||
setenv("ZYGISK_ENABLED", "1", 1);
|
setenv("ZYGISK_ENABLED", "1", 1);
|
||||||
}
|
}
|
||||||
g_ctx = nullptr;
|
g_ctx = nullptr;
|
||||||
if (!flags[FORK_AND_SPECIALIZE]) {
|
if (!state[FORK_AND_SPECIALIZE]) {
|
||||||
unload_zygisk();
|
unload_zygisk();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void HookContext::nativeForkSystemServer_pre() {
|
void HookContext::nativeForkSystemServer_pre() {
|
||||||
fork_pre();
|
fork_pre();
|
||||||
flags[SERVER_SPECIALIZE] = true;
|
state[SERVER_SPECIALIZE] = true;
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
ZLOGV("pre forkSystemServer\n");
|
ZLOGV("pre forkSystemServer\n");
|
||||||
run_modules_pre(remote_get_info(1000, "system_server", &info));
|
run_modules_pre(remote_get_info(1000, "system_server", &flags));
|
||||||
close_fds();
|
close_fds();
|
||||||
android_logging();
|
android_logging();
|
||||||
}
|
}
|
||||||
@ -496,7 +502,7 @@ void HookContext::nativeForkSystemServer_post() {
|
|||||||
|
|
||||||
void HookContext::nativeForkAndSpecialize_pre() {
|
void HookContext::nativeForkAndSpecialize_pre() {
|
||||||
fork_pre();
|
fork_pre();
|
||||||
flags[FORK_AND_SPECIALIZE] = true;
|
state[FORK_AND_SPECIALIZE] = true;
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
nativeSpecializeAppProcess_pre();
|
nativeSpecializeAppProcess_pre();
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,17 @@ struct ServerSpecializeArgsImpl {
|
|||||||
effective_capabilities(effective_capabilities) {}
|
effective_capabilities(effective_capabilities) {}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum : uint32_t {
|
||||||
|
PROCESS_GRANTED_ROOT = zygisk::StateFlag::PROCESS_GRANTED_ROOT,
|
||||||
|
PROCESS_ON_DENYLIST = zygisk::StateFlag::PROCESS_ON_DENYLIST,
|
||||||
|
|
||||||
|
DENYLIST_ENFORCING = (1u << 30),
|
||||||
|
PROCESS_IS_MAGISK_APP = (1u << 31),
|
||||||
|
|
||||||
|
UNMOUNT_MASK = (PROCESS_ON_DENYLIST | DENYLIST_ENFORCING),
|
||||||
|
PRIVATE_MASK = (0x3u << 30)
|
||||||
|
};
|
||||||
|
|
||||||
template<typename T>
|
template<typename T>
|
||||||
struct force_cast_wrapper {
|
struct force_cast_wrapper {
|
||||||
template<typename U>
|
template<typename U>
|
||||||
@ -80,10 +91,11 @@ struct ApiTable {
|
|||||||
|
|
||||||
int (*connectCompanion)(ZygiskModule *);
|
int (*connectCompanion)(ZygiskModule *);
|
||||||
void (*setOption)(ZygiskModule *, zygisk::Option);
|
void (*setOption)(ZygiskModule *, zygisk::Option);
|
||||||
} v1;
|
} v1{};
|
||||||
struct {
|
struct {
|
||||||
int (*getModuleDir)(ZygiskModule *);
|
int (*getModuleDir)(ZygiskModule *);
|
||||||
} v2;
|
uint32_t (*getFlags)(ZygiskModule *);
|
||||||
|
} v2{};
|
||||||
|
|
||||||
ApiTable(ZygiskModule *m);
|
ApiTable(ZygiskModule *m);
|
||||||
};
|
};
|
||||||
@ -105,6 +117,7 @@ struct ZygiskModule {
|
|||||||
int connectCompanion() const;
|
int connectCompanion() const;
|
||||||
int getModuleDir() const;
|
int getModuleDir() const;
|
||||||
void setOption(zygisk::Option opt);
|
void setOption(zygisk::Option opt);
|
||||||
|
static uint32_t getFlags();
|
||||||
void doUnload() const { if (unload) dlclose(handle); }
|
void doUnload() const { if (unload) dlclose(handle); }
|
||||||
|
|
||||||
ZygiskModule(int id, void *handle, void *entry);
|
ZygiskModule(int id, void *handle, void *entry);
|
||||||
|
@ -37,14 +37,9 @@ uintptr_t get_function_off(int pid, uintptr_t addr, char *lib);
|
|||||||
// Get function address, given library name + offset
|
// Get function address, given library name + offset
|
||||||
uintptr_t get_function_addr(int pid, const char *lib, uintptr_t off);
|
uintptr_t get_function_addr(int pid, const char *lib, uintptr_t off);
|
||||||
|
|
||||||
struct AppInfo {
|
|
||||||
bool is_magisk_app;
|
|
||||||
bool on_denylist;
|
|
||||||
};
|
|
||||||
|
|
||||||
extern void *self_handle;
|
extern void *self_handle;
|
||||||
|
|
||||||
void unload_first_stage();
|
void unload_first_stage();
|
||||||
void hook_functions();
|
void hook_functions();
|
||||||
std::vector<int> remote_get_info(int uid, const char *process, AppInfo *info);
|
std::vector<int> remote_get_info(int uid, const char *process, uint32_t *flags);
|
||||||
int remote_request_unmount();
|
int remote_request_unmount();
|
||||||
|
Loading…
x
Reference in New Issue
Block a user