239 lines
7.1 KiB
C++
Raw Normal View History

#include <libgen.h>
#include <dlfcn.h>
2021-01-06 23:41:37 -08:00
#include <sys/prctl.h>
2022-06-01 01:50:42 -07:00
#include <sys/mount.h>
2021-08-21 03:52:59 -07:00
#include <android/log.h>
#include <android/dlext.h>
2022-05-12 02:03:42 -07:00
#include <base.hpp>
2023-11-08 01:46:02 -08:00
#include <consts.hpp>
2021-10-05 03:53:11 -07:00
#include "zygisk.hpp"
2022-01-17 19:54:33 -08:00
#include "module.hpp"
using namespace std;
string native_bridge = "0";
2023-11-08 17:46:39 -08:00
static bool is_compatible_with(uint32_t) {
2024-01-25 00:17:47 -08:00
zygisk_logging();
2024-01-07 22:13:43 +08:00
hook_functions();
ZLOGD("load success\n");
2023-11-08 17:46:39 -08:00
return false;
}
2024-03-03 15:15:42 +08:00
extern "C" [[maybe_unused]] NativeBridgeCallbacks NativeBridgeItf {
2023-11-08 17:46:39 -08:00
.version = 2,
.padding = {},
.isCompatibleWith = &is_compatible_with,
};
// The following code runs in zygote/app process
2021-08-18 03:44:32 -07:00
static inline bool should_load_modules(uint32_t flags) {
return (flags & UNMOUNT_MASK) != UNMOUNT_MASK &&
(flags & PROCESS_IS_MAGISK_APP) != PROCESS_IS_MAGISK_APP;
}
2022-01-21 04:43:27 -08:00
int remote_get_info(int uid, const char *process, uint32_t *flags, vector<int> &fds) {
2022-02-12 23:43:36 +08:00
if (int fd = zygisk_request(ZygiskRequest::GET_INFO); fd >= 0) {
2021-09-18 02:38:53 -07:00
write_int(fd, uid);
write_string(fd, process);
2022-01-17 19:54:33 -08:00
xxread(fd, flags, sizeof(*flags));
if (should_load_modules(*flags)) {
2021-10-13 04:52:02 -07:00
fds = recv_fds(fd);
}
2022-01-21 04:43:27 -08:00
return fd;
2021-08-19 04:55:17 -07:00
}
2022-01-21 04:43:27 -08:00
return -1;
2021-08-19 04:55:17 -07:00
}
2021-08-18 03:44:32 -07:00
// The following code runs in magiskd
2022-01-14 03:10:02 -08:00
static vector<int> get_module_fds(bool is_64_bit) {
vector<int> fds;
// All fds passed to send_fds have to be valid file descriptors.
// To workaround this issue, send over STDOUT_FILENO as an indicator of an
// invalid fd as it will always be /dev/null in magiskd
if (is_64_bit) {
#if defined(__LP64__)
std::transform(module_list->begin(), module_list->end(), std::back_inserter(fds),
[](const module_info &info) { return info.z64 < 0 ? STDOUT_FILENO : info.z64; });
#endif
} else {
std::transform(module_list->begin(), module_list->end(), std::back_inserter(fds),
[](const module_info &info) { return info.z32 < 0 ? STDOUT_FILENO : info.z32; });
}
return fds;
}
2021-10-23 14:38:30 -07:00
static bool get_exe(int pid, char *buf, size_t sz) {
char exe[128];
if (ssprintf(exe, sizeof(exe), "/proc/%d/exe", pid) < 0)
return false;
return xreadlink(exe, buf, sz) > 0;
2021-10-23 14:38:30 -07:00
}
static pthread_mutex_t zygiskd_lock = PTHREAD_MUTEX_INITIALIZER;
static int zygiskd_sockets[] = { -1, -1 };
#define zygiskd_socket zygiskd_sockets[is_64_bit]
static void connect_companion(int client, bool is_64_bit) {
mutex_guard g(zygiskd_lock);
if (zygiskd_socket >= 0) {
// Make sure the socket is still valid
pollfd pfd = { zygiskd_socket, 0, 0 };
poll(&pfd, 1, 0);
if (pfd.revents) {
// Any revent means error
close(zygiskd_socket);
zygiskd_socket = -1;
}
}
if (zygiskd_socket < 0) {
int fds[2];
socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds);
zygiskd_socket = fds[0];
if (fork_dont_care() == 0) {
2023-11-02 15:50:36 -07:00
char exe[64];
2024-03-31 22:01:22 -07:00
#if defined(__LP64__)
ssprintf(exe, sizeof(exe), "%s/magisk%s", get_magisk_tmp(), (is_64_bit ? "" : "32"));
#else
ssprintf(exe, sizeof(exe), "%s/magisk", get_magisk_tmp());
#endif
// This fd has to survive exec
fcntl(fds[1], F_SETFD, 0);
char buf[16];
ssprintf(buf, sizeof(buf), "%d", fds[1]);
2023-11-02 15:50:36 -07:00
execl(exe, "", "zygisk", "companion", buf, (char *) nullptr);
exit(-1);
}
close(fds[1]);
2022-01-14 03:10:02 -08:00
vector<int> module_fds = get_module_fds(is_64_bit);
send_fds(zygiskd_socket, module_fds.data(), module_fds.size());
// Wait for ack
if (read_int(zygiskd_socket) != 0) {
LOGE("zygiskd startup error\n");
return;
}
}
send_fd(zygiskd_socket, client);
}
2022-01-17 19:54:33 -08:00
extern bool uid_granted_root(int uid);
2021-10-19 23:46:38 -07:00
static void get_process_info(int client, const sock_cred *cred) {
2021-08-19 04:55:17 -07:00
int uid = read_int(client);
string process = read_string(client);
2021-09-20 05:47:15 -07:00
2022-01-17 19:54:33 -08:00
uint32_t flags = 0;
if (is_deny_target(uid, process)) {
flags |= PROCESS_ON_DENYLIST;
}
2024-02-01 04:33:35 +08:00
if (get_manager(to_user_id(uid)) == uid) {
flags |= PROCESS_IS_MAGISK_APP;
}
if (denylist_enforced) {
flags |= DENYLIST_ENFORCING;
}
if (uid_granted_root(uid)) {
flags |= PROCESS_GRANTED_ROOT;
2021-09-18 02:38:53 -07:00
}
2021-10-13 04:52:02 -07:00
2022-01-17 19:54:33 -08:00
xwrite(client, &flags, sizeof(flags));
2021-10-13 04:52:02 -07:00
if (should_load_modules(flags)) {
2021-10-13 04:52:02 -07:00
char buf[256];
if (!get_exe(cred->pid, buf, sizeof(buf))) {
LOGW("zygisk: remote process %d probably died, abort\n", cred->pid);
send_fd(client, -1);
return;
}
2022-01-14 03:10:02 -08:00
vector<int> fds = get_module_fds(str_ends(buf, "64"));
2021-10-13 04:52:02 -07:00
send_fds(client, fds.data(), fds.size());
}
2022-01-21 04:43:27 -08:00
if (uid != 1000 || process != "system_server")
return;
// Collect module status from system_server
2022-01-21 04:43:27 -08:00
int slots = read_int(client);
2022-02-11 01:00:58 -08:00
dynamic_bitset bits;
2022-01-21 04:43:27 -08:00
for (int i = 0; i < slots; ++i) {
2022-01-23 04:39:00 -08:00
dynamic_bitset::slot_type l = 0;
2022-01-21 04:43:27 -08:00
xxread(client, &l, sizeof(l));
2022-02-11 01:00:58 -08:00
bits.emplace_back(l);
}
for (int id = 0; id < module_list->size(); ++id) {
if (!as_const(bits)[id]) {
// Either not a zygisk module, or incompatible
char buf[4096];
ssprintf(buf, sizeof(buf), MODULEROOT "/%s/zygisk",
2022-02-11 01:00:58 -08:00
module_list->operator[](id).name.data());
if (int dirfd = open(buf, O_RDONLY | O_CLOEXEC); dirfd >= 0) {
close(xopenat(dirfd, "unloaded", O_CREAT | O_RDONLY, 0644));
close(dirfd);
2022-01-21 04:43:27 -08:00
}
}
}
2021-08-19 04:55:17 -07:00
}
2022-01-14 03:10:02 -08:00
static void get_moddir(int client) {
int id = read_int(client);
char buf[4096];
ssprintf(buf, sizeof(buf), MODULEROOT "/%s", module_list->operator[](id).name.data());
2022-01-14 03:10:02 -08:00
int dfd = xopen(buf, O_RDONLY | O_CLOEXEC);
send_fd(client, dfd);
close(dfd);
}
2021-10-19 23:46:38 -07:00
void zygisk_handler(int client, const sock_cred *cred) {
2021-08-18 03:44:32 -07:00
int code = read_int(client);
2021-10-23 14:38:30 -07:00
char buf[256];
2022-03-01 02:13:18 -08:00
switch (code) {
2022-02-12 23:43:36 +08:00
case ZygiskRequest::GET_INFO:
2021-10-13 04:52:02 -07:00
get_process_info(client, cred);
2021-08-19 04:55:17 -07:00
break;
2022-02-12 23:43:36 +08:00
case ZygiskRequest::CONNECT_COMPANION:
if (get_exe(cred->pid, buf, sizeof(buf))) {
connect_companion(client, str_ends(buf, "64"));
} else {
LOGW("zygisk: remote process %d probably died, abort\n", cred->pid);
}
2021-10-17 04:36:18 -07:00
break;
2022-02-12 23:43:36 +08:00
case ZygiskRequest::GET_MODDIR:
2022-01-14 03:10:02 -08:00
get_moddir(client);
break;
2022-03-01 02:13:18 -08:00
default:
// Unknown code
break;
2021-08-18 03:44:32 -07:00
}
close(client);
}
void reset_zygisk(bool restore) {
if (!zygisk_enabled) return;
static atomic_uint zygote_start_count{1};
if (!restore) {
close(zygiskd_sockets[0]);
close(zygiskd_sockets[1]);
zygiskd_sockets[0] = zygiskd_sockets[1] = -1;
}
if (restore) {
zygote_start_count = 1;
} else if (zygote_start_count.fetch_add(1) > 3) {
LOGW("zygote crashes too many times, rolling-back\n");
restore = true;
}
if (restore) {
string native_bridge_orig = "0";
if (native_bridge.length() > strlen(ZYGISKLDR)) {
native_bridge_orig = native_bridge.substr(strlen(ZYGISKLDR));
}
set_prop(NBPROP, native_bridge_orig.data());
} else {
set_prop(NBPROP, native_bridge.data());
}
}