Magisk/native/src/zygisk/entry.cpp

418 lines
12 KiB
C++
Raw Normal View History

#include <libgen.h>
#include <dlfcn.h>
2021-01-07 07:41:37 +00:00
#include <sys/prctl.h>
2022-06-01 08:50:42 +00:00
#include <sys/mount.h>
2021-08-21 10:52:59 +00:00
#include <android/log.h>
#include <android/dlext.h>
2022-05-12 09:03:42 +00:00
#include <base.hpp>
2021-08-18 10:44:32 +00:00
#include <daemon.hpp>
#include <magisk.hpp>
2021-10-05 10:53:11 +00:00
#include "zygisk.hpp"
2022-01-18 03:54:33 +00:00
#include "module.hpp"
2021-09-18 21:50:11 +00:00
#include "deny/deny.hpp"
using namespace std;
2021-11-07 21:05:44 +00:00
void *self_handle = nullptr;
2021-09-18 12:11:10 +00:00
// Make sure /proc/self/environ is sanitized
// Filter env and reset MM_ENV_END
2021-01-07 07:41:37 +00:00
static void sanitize_environ() {
2021-09-18 12:11:10 +00:00
char *cur = environ[0];
2021-01-07 07:41:37 +00:00
for (int i = 0; environ[i]; ++i) {
2021-09-22 07:14:22 +00:00
// Copy all env onto the original stack
size_t len = strlen(environ[i]);
2021-09-18 12:11:10 +00:00
memmove(cur, environ[i], len + 1);
environ[i] = cur;
cur += len + 1;
2021-01-07 07:41:37 +00:00
}
2021-09-18 12:11:10 +00:00
prctl(PR_SET_MM, PR_SET_MM_ENV_END, cur, 0, 0);
2021-01-07 07:41:37 +00:00
}
[[gnu::destructor]] [[maybe_unused]]
2021-09-22 07:14:22 +00:00
static void zygisk_cleanup_wait() {
2021-09-22 09:52:33 +00:00
if (self_handle) {
// Wait 10us to make sure none of our code is executing
timespec ts = { .tv_sec = 0, .tv_nsec = 10000L };
nanosleep(&ts, nullptr);
}
}
2022-06-01 08:50:42 +00:00
static void *unload_first_stage(void *) {
// Wait 10us to make sure 1st stage is done
timespec ts = { .tv_sec = 0, .tv_nsec = 10000L };
nanosleep(&ts, nullptr);
unmap_all(HIJACK_BIN);
xumount2(HIJACK_BIN, MNT_DETACH);
return nullptr;
}
#if defined(__LP64__)
// Use symlink to workaround linker bug on old broken Android
// https://issuetracker.google.com/issues/36914295
#define SECOND_STAGE_PATH "/system/bin/app_process"
#else
#define SECOND_STAGE_PATH "/system/bin/app_process32"
#endif
static void second_stage_entry() {
2021-09-22 07:14:22 +00:00
zygisk_logging();
2021-10-14 09:13:23 +00:00
ZLOGD("inject 2nd stage\n");
MAGISKTMP = getenv(MAGISKTMP_ENV);
self_handle = dlopen(SECOND_STAGE_PATH, RTLD_NOLOAD);
dlclose(self_handle);
2022-06-01 08:50:42 +00:00
unsetenv(MAGISKTMP_ENV);
sanitize_environ();
hook_functions();
2022-06-01 08:50:42 +00:00
new_daemon_thread(&unload_first_stage, nullptr);
2021-09-22 07:14:22 +00:00
}
static void first_stage_entry() {
2021-10-14 09:13:23 +00:00
ZLOGD("inject 1st stage\n");
2021-09-22 07:14:22 +00:00
char *ld = getenv("LD_PRELOAD");
if (char *c = strrchr(ld, ':')) {
*c = '\0';
setenv("LD_PRELOAD", ld, 1); // Restore original LD_PRELOAD
} else {
unsetenv("LD_PRELOAD");
}
2022-06-01 08:50:42 +00:00
// Load second stage
android_dlextinfo info {
.flags = ANDROID_DLEXT_FORCE_LOAD
};
2021-09-22 07:14:22 +00:00
setenv(INJECT_ENV_2, "1", 1);
if (android_dlopen_ext(SECOND_STAGE_PATH, RTLD_LAZY, &info) == nullptr) {
// Android 5.x doesn't support ANDROID_DLEXT_FORCE_LOAD
ZLOGI("ANDROID_DLEXT_FORCE_LOAD is not supported, fallback to dlopen\n");
if (dlopen(SECOND_STAGE_PATH, RTLD_LAZY) == nullptr) {
ZLOGE("Cannot load the second stage\n");
unsetenv(INJECT_ENV_2);
}
}
2021-09-22 07:14:22 +00:00
}
[[gnu::constructor]] [[maybe_unused]]
2021-09-22 07:14:22 +00:00
static void zygisk_init() {
2022-06-01 08:50:42 +00:00
android_logging();
if (getenv(INJECT_ENV_1)) {
unsetenv(INJECT_ENV_1);
2021-09-22 07:14:22 +00:00
first_stage_entry();
} else if (getenv(INJECT_ENV_2)) {
unsetenv(INJECT_ENV_2);
second_stage_entry();
}
}
// The following code runs in zygote/app process
2021-08-18 10:44:32 +00:00
2022-07-06 04:13:09 +00:00
extern "C" void zygisk_log_write(int prio, const char *msg, int len) {
2021-08-21 10:52:59 +00:00
// If we don't have log pipe set, ask magiskd for it
// This could happen multiple times in zygote because it was closed to prevent crashing
if (logd_fd < 0) {
// Change logging temporarily to prevent infinite recursion and stack overflow
android_logging();
2022-02-12 15:43:36 +00:00
if (int fd = zygisk_request(ZygiskRequest::GET_LOG_PIPE); fd >= 0) {
2021-08-21 10:52:59 +00:00
if (read_int(fd) == 0) {
logd_fd = recv_fd(fd);
}
close(fd);
}
zygisk_logging();
}
sigset_t mask;
sigset_t orig_mask;
bool sig = false;
// Make sure SIGPIPE won't crash zygote
if (logd_fd >= 0) {
sig = true;
sigemptyset(&mask);
sigaddset(&mask, SIGPIPE);
pthread_sigmask(SIG_BLOCK, &mask, &orig_mask);
}
2022-07-06 04:13:09 +00:00
magisk_log_write(prio, msg, len);
2021-08-21 10:52:59 +00:00
if (sig) {
timespec ts{};
sigtimedwait(&mask, nullptr, &ts);
pthread_sigmask(SIG_SETMASK, &orig_mask, nullptr);
}
}
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 12:43:27 +00:00
int remote_get_info(int uid, const char *process, uint32_t *flags, vector<int> &fds) {
2022-02-12 15:43:36 +00:00
if (int fd = zygisk_request(ZygiskRequest::GET_INFO); fd >= 0) {
2021-09-18 09:38:53 +00:00
write_int(fd, uid);
write_string(fd, process);
2022-01-18 03:54:33 +00:00
xxread(fd, flags, sizeof(*flags));
if (should_load_modules(*flags)) {
2021-10-13 11:52:02 +00:00
fds = recv_fds(fd);
}
2022-01-21 12:43:27 +00:00
return fd;
2021-08-19 11:55:17 +00:00
}
2022-01-21 12:43:27 +00:00
return -1;
2021-08-19 11:55:17 +00:00
}
2021-08-18 10:44:32 +00:00
// The following code runs in magiskd
2022-01-14 11:10:02 +00: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 21:38:30 +00:00
static bool get_exe(int pid, char *buf, size_t sz) {
snprintf(buf, sz, "/proc/%d/exe", pid);
return xreadlink(buf, buf, sz) > 0;
}
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) {
string exe = MAGISKTMP + "/magisk" + (is_64_bit ? "64" : "32");
// This fd has to survive exec
fcntl(fds[1], F_SETFD, 0);
char buf[16];
snprintf(buf, sizeof(buf), "%d", fds[1]);
execl(exe.data(), "zygisk", "companion", buf, (char *) nullptr);
exit(-1);
}
close(fds[1]);
2022-01-14 11:10:02 +00: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);
}
static timespec last_zygote_start;
static int zygote_start_counts[] = { 0, 0 };
#define zygote_start_count zygote_start_counts[is_64_bit]
#define zygote_started (zygote_start_counts[0] + zygote_start_counts[1])
#define zygote_start_reset(val) { zygote_start_counts[0] = val; zygote_start_counts[1] = val; }
2021-10-20 06:46:38 +00:00
static void setup_files(int client, const sock_cred *cred) {
2021-08-22 09:11:48 +00:00
LOGD("zygisk: setup files for pid=[%d]\n", cred->pid);
2021-08-18 10:44:32 +00:00
2021-08-22 09:11:48 +00:00
char buf[256];
2021-10-23 21:38:30 +00:00
if (!get_exe(cred->pid, buf, sizeof(buf))) {
2021-08-18 10:44:32 +00:00
write_int(client, 1);
return;
}
bool is_64_bit = str_ends(buf, "64");
if (!zygote_started) {
// First zygote launch, record time
clock_gettime(CLOCK_MONOTONIC, &last_zygote_start);
}
if (zygote_start_count) {
// This zygote ABI had started before, kill existing zygiskd
close(zygiskd_sockets[0]);
close(zygiskd_sockets[1]);
zygiskd_sockets[0] = -1;
zygiskd_sockets[1] = -1;
}
++zygote_start_count;
if (zygote_start_count >= 5) {
// Bootloop prevention
timespec ts;
clock_gettime(CLOCK_MONOTONIC, &ts);
if (ts.tv_sec - last_zygote_start.tv_sec > 60) {
// This is very likely manual soft reboot
memcpy(&last_zygote_start, &ts, sizeof(ts));
zygote_start_reset(1);
} else {
// If any zygote relaunched more than 5 times within a minute,
// don't do any setups further to prevent bootloop.
zygote_start_reset(999);
write_int(client, 1);
return;
}
}
2022-06-01 08:50:42 +00:00
// Hijack some binary in /system/bin to host 1st stage
const char *hbin;
string mbin;
int app_fd;
if (is_64_bit) {
hbin = HIJACK_BIN64;
mbin = MAGISKTMP + "/" ZYGISKBIN "/magisk64";
app_fd = app_process_64;
} else {
hbin = HIJACK_BIN32;
mbin = MAGISKTMP + "/" ZYGISKBIN "/magisk32";
app_fd = app_process_32;
}
xmount(mbin.data(), hbin, nullptr, MS_BIND, nullptr);
2021-08-18 10:44:32 +00:00
write_int(client, 0);
2022-06-01 08:50:42 +00:00
send_fd(client, app_fd);
2021-10-27 10:25:54 +00:00
write_string(client, MAGISKTMP);
2021-08-18 10:44:32 +00:00
}
static void magiskd_passthrough(int client) {
bool is_64_bit = read_int(client);
write_int(client, 0);
send_fd(client, is_64_bit ? app_process_64 : app_process_32);
}
2022-01-18 03:54:33 +00:00
extern bool uid_granted_root(int uid);
2021-10-20 06:46:38 +00:00
static void get_process_info(int client, const sock_cred *cred) {
2021-08-19 11:55:17 +00:00
int uid = read_int(client);
string process = read_string(client);
2021-09-20 12:47:15 +00:00
2022-01-18 03:54:33 +00:00
uint32_t flags = 0;
2022-05-30 06:31:57 +00:00
check_pkg_refresh();
if (is_deny_target(uid, process)) {
flags |= PROCESS_ON_DENYLIST;
}
2022-05-18 08:55:58 +00:00
int manager_app_id = get_manager();
if (to_app_id(uid) == manager_app_id) {
flags |= PROCESS_IS_MAGISK_APP;
}
if (denylist_enforced) {
flags |= DENYLIST_ENFORCING;
}
if (uid_granted_root(uid)) {
flags |= PROCESS_GRANTED_ROOT;
2021-09-18 09:38:53 +00:00
}
2021-10-13 11:52:02 +00:00
2022-01-18 03:54:33 +00:00
xwrite(client, &flags, sizeof(flags));
2021-10-13 11:52:02 +00:00
if (should_load_modules(flags)) {
2021-10-13 11:52:02 +00: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 11:10:02 +00:00
vector<int> fds = get_module_fds(str_ends(buf, "64"));
2021-10-13 11:52:02 +00:00
send_fds(client, fds.data(), fds.size());
}
2022-01-21 12:43:27 +00:00
if (uid != 1000 || process != "system_server")
return;
// Collect module status from system_server
2022-01-21 12:43:27 +00:00
int slots = read_int(client);
2022-02-11 09:00:58 +00:00
dynamic_bitset bits;
2022-01-21 12:43:27 +00:00
for (int i = 0; i < slots; ++i) {
2022-01-23 12:39:00 +00:00
dynamic_bitset::slot_type l = 0;
2022-01-21 12:43:27 +00:00
xxread(client, &l, sizeof(l));
2022-02-11 09:00:58 +00: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];
snprintf(buf, sizeof(buf), MODULEROOT "/%s/zygisk",
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 12:43:27 +00:00
}
}
}
2021-08-19 11:55:17 +00:00
}
2021-08-21 10:52:59 +00:00
static void send_log_pipe(int fd) {
// There is race condition here, but we can't really do much about it...
2021-08-22 09:11:48 +00:00
if (logd_fd >= 0) {
2021-08-21 10:52:59 +00:00
write_int(fd, 0);
send_fd(fd, logd_fd);
} else {
write_int(fd, 1);
}
}
2022-01-14 11:10:02 +00:00
static void get_moddir(int client) {
int id = read_int(client);
char buf[4096];
snprintf(buf, sizeof(buf), MODULEROOT "/%s", module_list->operator[](id).name.data());
int dfd = xopen(buf, O_RDONLY | O_CLOEXEC);
send_fd(client, dfd);
close(dfd);
}
2021-10-20 06:46:38 +00:00
void zygisk_handler(int client, const sock_cred *cred) {
2021-08-18 10:44:32 +00:00
int code = read_int(client);
2021-10-23 21:38:30 +00:00
char buf[256];
2022-03-01 10:13:18 +00:00
switch (code) {
2022-02-12 15:43:36 +00:00
case ZygiskRequest::SETUP:
2021-08-18 10:44:32 +00:00
setup_files(client, cred);
break;
2022-02-12 15:43:36 +00:00
case ZygiskRequest::PASSTHROUGH:
magiskd_passthrough(client);
break;
2022-02-12 15:43:36 +00:00
case ZygiskRequest::GET_INFO:
2021-10-13 11:52:02 +00:00
get_process_info(client, cred);
2021-08-19 11:55:17 +00:00
break;
2022-02-12 15:43:36 +00:00
case ZygiskRequest::GET_LOG_PIPE:
2021-08-21 10:52:59 +00:00
send_log_pipe(client);
break;
2022-02-12 15:43:36 +00: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 11:36:18 +00:00
break;
2022-02-12 15:43:36 +00:00
case ZygiskRequest::GET_MODDIR:
2022-01-14 11:10:02 +00:00
get_moddir(client);
break;
2022-03-01 10:13:18 +00:00
default:
// Unknown code
break;
2021-08-18 10:44:32 +00:00
}
close(client);
}