mirror of
https://github.com/topjohnwu/Magisk.git
synced 2024-11-27 20:15:29 +00:00
parent
4c747c4148
commit
ea75a09f95
@ -29,10 +29,10 @@ LOCAL_SRC_FILES := \
|
|||||||
su/pts.cpp \
|
su/pts.cpp \
|
||||||
su/su_daemon.cpp \
|
su/su_daemon.cpp \
|
||||||
zygisk/entry.cpp \
|
zygisk/entry.cpp \
|
||||||
|
zygisk/main.cpp \
|
||||||
zygisk/utils.cpp \
|
zygisk/utils.cpp \
|
||||||
zygisk/hook.cpp \
|
zygisk/hook.cpp \
|
||||||
zygisk/memory.cpp \
|
zygisk/memory.cpp \
|
||||||
zygisk/companion.cpp \
|
|
||||||
zygisk/deny/cli.cpp \
|
zygisk/deny/cli.cpp \
|
||||||
zygisk/deny/utils.cpp \
|
zygisk/deny/utils.cpp \
|
||||||
zygisk/deny/revert.cpp
|
zygisk/deny/revert.cpp
|
||||||
|
@ -10,14 +10,15 @@ using namespace std;
|
|||||||
|
|
||||||
using main_fun = int (*)(int, char *[]);
|
using main_fun = int (*)(int, char *[]);
|
||||||
|
|
||||||
static main_fun applet_main[] = { su_client_main, resetprop_main, nullptr };
|
constexpr const char *applets[] = { "su", "resetprop", "zygisk", nullptr };
|
||||||
|
static main_fun applet_mains[] = { su_client_main, resetprop_main, zygisk_main, nullptr };
|
||||||
|
|
||||||
static int call_applet(int argc, char *argv[]) {
|
static int call_applet(int argc, char *argv[]) {
|
||||||
// Applets
|
// Applets
|
||||||
string_view base = basename(argv[0]);
|
string_view base = basename(argv[0]);
|
||||||
for (int i = 0; applet_names[i]; ++i) {
|
for (int i = 0; applets[i]; ++i) {
|
||||||
if (base == applet_names[i]) {
|
if (base == applets[i]) {
|
||||||
return (*applet_main[i])(argc, argv);
|
return (*applet_mains[i])(argc, argv);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (str_starts(base, "app_process")) {
|
if (str_starts(base, "app_process")) {
|
||||||
|
@ -34,6 +34,3 @@ void exec_common_scripts(const char *stage);
|
|||||||
void exec_module_scripts(const char *stage, const std::vector<std::string_view> &modules);
|
void exec_module_scripts(const char *stage, const std::vector<std::string_view> &modules);
|
||||||
void install_apk(const char *apk);
|
void install_apk(const char *apk);
|
||||||
[[noreturn]] void install_module(const char *file);
|
[[noreturn]] void install_module(const char *file);
|
||||||
|
|
||||||
// Zygisk companion entrypoint
|
|
||||||
[[noreturn]] void zygiskd(int socket);
|
|
||||||
|
@ -157,6 +157,7 @@ static void handle_request_async(int client, int code, const sock_cred &cred) {
|
|||||||
reboot();
|
reboot();
|
||||||
break;
|
break;
|
||||||
case ZYGISK_REQUEST:
|
case ZYGISK_REQUEST:
|
||||||
|
case ZYGISK_PASSTHROUGH:
|
||||||
zygisk_handler(client, &cred);
|
zygisk_handler(client, &cred);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
|
@ -39,7 +39,6 @@ Advanced Options (Internal APIs):
|
|||||||
--sqlite SQL exec SQL commands to Magisk database
|
--sqlite SQL exec SQL commands to Magisk database
|
||||||
--path print Magisk tmpfs mount path
|
--path print Magisk tmpfs mount path
|
||||||
--denylist ARGS denylist config CLI
|
--denylist ARGS denylist config CLI
|
||||||
--companion FD start zygisk root companion
|
|
||||||
|
|
||||||
Available applets:
|
Available applets:
|
||||||
)EOF");
|
)EOF");
|
||||||
@ -128,8 +127,6 @@ int magisk_main(int argc, char *argv[]) {
|
|||||||
return 0;
|
return 0;
|
||||||
} else if (argc >= 3 && argv[1] == "--install-module"sv) {
|
} else if (argc >= 3 && argv[1] == "--install-module"sv) {
|
||||||
install_module(argv[2]);
|
install_module(argv[2]);
|
||||||
} else if (argc >= 3 && argv[1] == "--companion"sv) {
|
|
||||||
zygiskd(parse_int(argv[2]));
|
|
||||||
}
|
}
|
||||||
#if 0
|
#if 0
|
||||||
/* Entry point for testing stuffs */
|
/* Entry point for testing stuffs */
|
||||||
|
@ -550,18 +550,21 @@ struct module_info {
|
|||||||
};
|
};
|
||||||
|
|
||||||
static vector<module_info> *modules;
|
static vector<module_info> *modules;
|
||||||
|
int app_process_32 = -1;
|
||||||
|
int app_process_64 = -1;
|
||||||
|
|
||||||
#define mount_zygisk(bit) \
|
#define mount_zygisk(bit) \
|
||||||
if (access("/system/bin/app_process" #bit, F_OK) == 0) { \
|
if (access("/system/bin/app_process" #bit, F_OK) == 0) { \
|
||||||
string zbin = zygisk_bin + "/app_process" #bit; \
|
app_process_##bit = xopen("/system/bin/app_process" #bit, O_RDONLY | O_CLOEXEC); \
|
||||||
string mbin = MAGISKTMP + "/magisk" #bit; \
|
string zbin = zygisk_bin + "/app_process" #bit; \
|
||||||
int src = xopen(mbin.data(), O_RDONLY | O_CLOEXEC); \
|
string mbin = MAGISKTMP + "/magisk" #bit; \
|
||||||
int out = xopen(zbin.data(), O_CREAT | O_WRONLY | O_CLOEXEC, 0); \
|
int src = xopen(mbin.data(), O_RDONLY | O_CLOEXEC); \
|
||||||
xsendfile(out, src, nullptr, INT_MAX); \
|
int out = xopen(zbin.data(), O_CREAT | O_WRONLY | O_CLOEXEC, 0); \
|
||||||
close(src); \
|
xsendfile(out, src, nullptr, INT_MAX); \
|
||||||
close(out); \
|
close(src); \
|
||||||
clone_attr("/system/bin/app_process" #bit, zbin.data()); \
|
close(out); \
|
||||||
bind_mount(zbin.data(), "/system/bin/app_process" #bit); \
|
clone_attr("/system/bin/app_process" #bit, zbin.data()); \
|
||||||
|
bind_mount(zbin.data(), "/system/bin/app_process" #bit); \
|
||||||
}
|
}
|
||||||
|
|
||||||
void magic_mount() {
|
void magic_mount() {
|
||||||
|
@ -30,6 +30,7 @@ enum : int {
|
|||||||
SQLITE_CMD,
|
SQLITE_CMD,
|
||||||
REMOVE_MODULES,
|
REMOVE_MODULES,
|
||||||
ZYGISK_REQUEST,
|
ZYGISK_REQUEST,
|
||||||
|
ZYGISK_PASSTHROUGH,
|
||||||
DAEMON_CODE_END,
|
DAEMON_CODE_END,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -42,6 +43,8 @@ enum : int {
|
|||||||
};
|
};
|
||||||
|
|
||||||
extern bool zygisk_enabled;
|
extern bool zygisk_enabled;
|
||||||
|
extern int app_process_32;
|
||||||
|
extern int app_process_64;
|
||||||
|
|
||||||
int connect_daemon(bool create = false);
|
int connect_daemon(bool create = false);
|
||||||
|
|
||||||
|
@ -43,3 +43,4 @@ int magiskpolicy_main(int argc, char *argv[]);
|
|||||||
int su_client_main(int argc, char *argv[]);
|
int su_client_main(int argc, char *argv[]);
|
||||||
int resetprop_main(int argc, char *argv[]);
|
int resetprop_main(int argc, char *argv[]);
|
||||||
int app_process_main(int argc, char *argv[]);
|
int app_process_main(int argc, char *argv[]);
|
||||||
|
int zygisk_main(int argc, char *argv[]);
|
||||||
|
@ -5,6 +5,7 @@
|
|||||||
#include <selinux.hpp>
|
#include <selinux.hpp>
|
||||||
|
|
||||||
#include "su.hpp"
|
#include "su.hpp"
|
||||||
|
#include "daemon.hpp"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
|
|
||||||
@ -15,11 +16,11 @@ enum {
|
|||||||
};
|
};
|
||||||
|
|
||||||
#define CALL_PROVIDER \
|
#define CALL_PROVIDER \
|
||||||
"/system/bin/app_process", "/system/bin", "com.android.commands.content.Content", \
|
exe, "/system/bin", "com.android.commands.content.Content", \
|
||||||
"call", "--uri", target, "--user", user, "--method", action
|
"call", "--uri", target, "--user", user, "--method", action
|
||||||
|
|
||||||
#define START_ACTIVITY \
|
#define START_ACTIVITY \
|
||||||
"/system/bin/app_process", "/system/bin", "com.android.commands.am.Am", \
|
exe, "/system/bin", "com.android.commands.am.Am", \
|
||||||
"start", "-p", target, "--user", user, "-a", "android.intent.action.VIEW", \
|
"start", "-p", target, "--user", user, "-a", "android.intent.action.VIEW", \
|
||||||
"-f", "0x18000020", "--es", "action", action
|
"-f", "0x18000020", "--es", "action", action
|
||||||
|
|
||||||
@ -100,9 +101,20 @@ static bool check_no_error(int fd) {
|
|||||||
|
|
||||||
static void exec_cmd(const char *action, vector<Extra> &data,
|
static void exec_cmd(const char *action, vector<Extra> &data,
|
||||||
const shared_ptr<su_info> &info, int mode = CONTENT_PROVIDER) {
|
const shared_ptr<su_info> &info, int mode = CONTENT_PROVIDER) {
|
||||||
|
char exe[128];
|
||||||
char target[128];
|
char target[128];
|
||||||
char user[4];
|
char user[4];
|
||||||
sprintf(user, "%d", get_user(info));
|
snprintf(user, sizeof(user), "%d", get_user(info));
|
||||||
|
|
||||||
|
if (zygisk_enabled) {
|
||||||
|
#if defined(__LP64__)
|
||||||
|
snprintf(exe, sizeof(exe), "/proc/self/fd/%d", app_process_64);
|
||||||
|
#else
|
||||||
|
snprintf(exe, sizeof(exe), "/proc/self/fd/%d", app_process_32);
|
||||||
|
#endif
|
||||||
|
} else {
|
||||||
|
strlcpy(exe, "/system/bin/app_process", sizeof(exe));
|
||||||
|
}
|
||||||
|
|
||||||
// First try content provider call method
|
// First try content provider call method
|
||||||
if (mode >= CONTENT_PROVIDER) {
|
if (mode >= CONTENT_PROVIDER) {
|
||||||
|
@ -1,114 +0,0 @@
|
|||||||
#include <dlfcn.h>
|
|
||||||
#include <fcntl.h>
|
|
||||||
|
|
||||||
#include <utils.hpp>
|
|
||||||
#include <socket.hpp>
|
|
||||||
#include <daemon.hpp>
|
|
||||||
#include <magisk.hpp>
|
|
||||||
|
|
||||||
#include "zygisk.hpp"
|
|
||||||
|
|
||||||
using namespace std;
|
|
||||||
|
|
||||||
void zygiskd(int socket) {
|
|
||||||
if (getuid() != 0 || fcntl(socket, F_GETFD) < 0)
|
|
||||||
exit(-1);
|
|
||||||
android_logging();
|
|
||||||
|
|
||||||
#if defined(__LP64__)
|
|
||||||
set_nice_name("zygiskd64");
|
|
||||||
LOGI("* Launching zygiskd64\n");
|
|
||||||
#else
|
|
||||||
set_nice_name("zygiskd32");
|
|
||||||
LOGI("* Launching zygiskd32\n");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Load modules
|
|
||||||
using comp_entry = void(*)(int);
|
|
||||||
vector<comp_entry> modules;
|
|
||||||
{
|
|
||||||
vector<int> module_fds = recv_fds(socket);
|
|
||||||
char buf[256];
|
|
||||||
for (int fd : module_fds) {
|
|
||||||
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
|
||||||
comp_entry entry = nullptr;
|
|
||||||
if (void *h = dlopen(buf, RTLD_LAZY)) {
|
|
||||||
*(void **) &entry = dlsym(h, "zygisk_companion_entry");
|
|
||||||
}
|
|
||||||
modules.push_back(entry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ack
|
|
||||||
write_int(socket, 0);
|
|
||||||
|
|
||||||
// Start accepting requests
|
|
||||||
pollfd pfd = { socket, POLLIN, 0 };
|
|
||||||
for (;;) {
|
|
||||||
poll(&pfd, 1, -1);
|
|
||||||
if (!(pfd.revents & POLLIN)) {
|
|
||||||
// Something bad happened in magiskd, terminate zygiskd
|
|
||||||
exit(0);
|
|
||||||
}
|
|
||||||
int client = recv_fd(socket);
|
|
||||||
int module_id = read_int(client);
|
|
||||||
if (module_id < modules.size() && modules[module_id]) {
|
|
||||||
exec_task([=, entry = modules[module_id]] {
|
|
||||||
int dup = fcntl(client, F_DUPFD_CLOEXEC);
|
|
||||||
entry(client);
|
|
||||||
// Only close client if it is the same as dup so we don't
|
|
||||||
// accidentally close a re-used file descriptor.
|
|
||||||
// This check is required because the module companion
|
|
||||||
// handler could've closed the file descriptor already.
|
|
||||||
if (struct stat s1; fstat(client, &s1) == 0) {
|
|
||||||
struct stat s2{};
|
|
||||||
fstat(dup, &s2);
|
|
||||||
if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
|
|
||||||
close(client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
close(dup);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
close(client);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static int zygiskd_sockets[] = { -1, -1 };
|
|
||||||
#define zygiskd_socket zygiskd_sockets[is_64_bit]
|
|
||||||
|
|
||||||
void connect_companion(int client, bool is_64_bit) {
|
|
||||||
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]);
|
|
||||||
execlp(exe.data(), "magisk", "--companion", buf, (char *) nullptr);
|
|
||||||
exit(-1);
|
|
||||||
}
|
|
||||||
close(fds[1]);
|
|
||||||
vector<int> module_fds = zygisk_module_fds(is_64_bit);
|
|
||||||
send_fds(zygiskd_socket, module_fds.data(), module_fds.size());
|
|
||||||
// Wait for ack
|
|
||||||
if (read_int(zygiskd_socket) != 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
send_fd(zygiskd_socket, client);
|
|
||||||
}
|
|
@ -1,7 +1,5 @@
|
|||||||
#include <libgen.h>
|
#include <libgen.h>
|
||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
#include <sys/mount.h>
|
|
||||||
#include <sys/sendfile.h>
|
|
||||||
#include <sys/prctl.h>
|
#include <sys/prctl.h>
|
||||||
#include <android/log.h>
|
#include <android/log.h>
|
||||||
|
|
||||||
@ -145,37 +143,7 @@ static void zygisk_init() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Start code for magiskd IPC
|
// The following code runs in zygote/app process
|
||||||
|
|
||||||
int app_process_main(int argc, char *argv[]) {
|
|
||||||
android_logging();
|
|
||||||
|
|
||||||
if (int fd = connect_daemon(); fd >= 0) {
|
|
||||||
write_int(fd, ZYGISK_REQUEST);
|
|
||||||
write_int(fd, ZYGISK_SETUP);
|
|
||||||
|
|
||||||
if (read_int(fd) == 0) {
|
|
||||||
string path = read_string(fd);
|
|
||||||
string lib = path + ".1.so";
|
|
||||||
if (char *ld = getenv("LD_PRELOAD")) {
|
|
||||||
char env[256];
|
|
||||||
sprintf(env, "%s:%s", ld, lib.data());
|
|
||||||
setenv("LD_PRELOAD", env, 1);
|
|
||||||
} else {
|
|
||||||
setenv("LD_PRELOAD", lib.data(), 1);
|
|
||||||
}
|
|
||||||
setenv(INJECT_ENV_1, "1", 1);
|
|
||||||
}
|
|
||||||
close(fd);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Execute real app_process
|
|
||||||
char buf[256];
|
|
||||||
xreadlink("/proc/self/exe", buf, sizeof(buf));
|
|
||||||
xumount2("/proc/self/exe", MNT_DETACH);
|
|
||||||
execve(buf, argv, environ);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
static int zygisk_log(int prio, const char *fmt, va_list ap) {
|
static int zygisk_log(int prio, const char *fmt, va_list ap) {
|
||||||
// If we don't have log pipe set, ask magiskd for it
|
// If we don't have log pipe set, ask magiskd for it
|
||||||
@ -248,6 +216,50 @@ static bool get_exe(int pid, char *buf, size_t sz) {
|
|||||||
return xreadlink(buf, buf, sz) > 0;
|
return xreadlink(buf, buf, sz) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int zygiskd_sockets[] = { -1, -1 };
|
||||||
|
#define zygiskd_socket zygiskd_sockets[is_64_bit]
|
||||||
|
|
||||||
|
static void connect_companion(int client, bool is_64_bit) {
|
||||||
|
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]);
|
||||||
|
vector<int> module_fds = zygisk_module_fds(is_64_bit);
|
||||||
|
send_fds(zygiskd_socket, module_fds.data(), module_fds.size());
|
||||||
|
// Wait for ack
|
||||||
|
if (read_int(zygiskd_socket) != 0) {
|
||||||
|
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; }
|
||||||
|
|
||||||
static void setup_files(int client, const sock_cred *cred) {
|
static void setup_files(int client, const sock_cred *cred) {
|
||||||
LOGD("zygisk: setup files for pid=[%d]\n", cred->pid);
|
LOGD("zygisk: setup files for pid=[%d]\n", cred->pid);
|
||||||
|
|
||||||
@ -257,15 +269,54 @@ static void setup_files(int client, const sock_cred *cred) {
|
|||||||
return;
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
write_int(client, 0);
|
write_int(client, 0);
|
||||||
|
send_fd(client, is_64_bit ? app_process_64 : app_process_32);
|
||||||
|
|
||||||
string path = MAGISKTMP + "/" ZYGISKBIN "/zygisk." + basename(buf);
|
string path = MAGISKTMP + "/" ZYGISKBIN "/zygisk." + basename(buf);
|
||||||
cp_afc(buf, (path + ".1.so").data());
|
cp_afc(buf, (path + ".1.so").data());
|
||||||
cp_afc(buf, (path + ".2.so").data());
|
cp_afc(buf, (path + ".2.so").data());
|
||||||
|
|
||||||
write_string(client, path);
|
write_string(client, path);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
|
||||||
int cached_manager_app_id = -1;
|
int cached_manager_app_id = -1;
|
||||||
static time_t last_modified = 0;
|
static time_t last_modified = 0;
|
||||||
|
|
||||||
@ -344,6 +395,9 @@ void zygisk_handler(int client, const sock_cred *cred) {
|
|||||||
case ZYGISK_SETUP:
|
case ZYGISK_SETUP:
|
||||||
setup_files(client, cred);
|
setup_files(client, cred);
|
||||||
break;
|
break;
|
||||||
|
case ZYGISK_PASSTHROUGH:
|
||||||
|
magiskd_passthrough(client);
|
||||||
|
break;
|
||||||
case ZYGISK_GET_INFO:
|
case ZYGISK_GET_INFO:
|
||||||
get_process_info(client, cred);
|
get_process_info(client, cred);
|
||||||
break;
|
break;
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
#include <dlfcn.h>
|
#include <dlfcn.h>
|
||||||
|
#include <sys/mount.h>
|
||||||
#include <xhook.h>
|
#include <xhook.h>
|
||||||
#include <bitset>
|
#include <bitset>
|
||||||
|
|
||||||
@ -143,6 +144,16 @@ DCL_HOOK_FUNC(int, fork) {
|
|||||||
return (g_ctx && g_ctx->pid >= 0) ? g_ctx->pid : old_fork();
|
return (g_ctx && g_ctx->pid >= 0) ? g_ctx->pid : old_fork();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Unmount app_process overlays in the process's private mount namespace
|
||||||
|
DCL_HOOK_FUNC(int, unshare, int flags) {
|
||||||
|
int res = old_unshare(flags);
|
||||||
|
if (g_ctx && res == 0) {
|
||||||
|
umount2("/system/bin/app_process64", MNT_DETACH);
|
||||||
|
umount2("/system/bin/app_process32", MNT_DETACH);
|
||||||
|
}
|
||||||
|
return res;
|
||||||
|
}
|
||||||
|
|
||||||
// This is the latest point where we can still connect to the magiskd main socket
|
// This is the latest point where we can still connect to the magiskd main socket
|
||||||
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) {
|
||||||
@ -501,6 +512,7 @@ void hook_functions() {
|
|||||||
default_new(jni_method_map);
|
default_new(jni_method_map);
|
||||||
|
|
||||||
XHOOK_REGISTER(ANDROID_RUNTIME, fork);
|
XHOOK_REGISTER(ANDROID_RUNTIME, fork);
|
||||||
|
XHOOK_REGISTER(ANDROID_RUNTIME, unshare);
|
||||||
XHOOK_REGISTER(ANDROID_RUNTIME, selinux_android_setcontext);
|
XHOOK_REGISTER(ANDROID_RUNTIME, selinux_android_setcontext);
|
||||||
XHOOK_REGISTER(ANDROID_RUNTIME, jniRegisterNativeMethods);
|
XHOOK_REGISTER(ANDROID_RUNTIME, jniRegisterNativeMethods);
|
||||||
XHOOK_REGISTER_SYM(ANDROID_RUNTIME, "__android_log_close", android_log_close);
|
XHOOK_REGISTER_SYM(ANDROID_RUNTIME, "__android_log_close", android_log_close);
|
||||||
|
199
native/jni/zygisk/main.cpp
Normal file
199
native/jni/zygisk/main.cpp
Normal file
@ -0,0 +1,199 @@
|
|||||||
|
#include <sys/mount.h>
|
||||||
|
#include <dlfcn.h>
|
||||||
|
|
||||||
|
#include <magisk.hpp>
|
||||||
|
#include <utils.hpp>
|
||||||
|
#include <socket.hpp>
|
||||||
|
#include <daemon.hpp>
|
||||||
|
|
||||||
|
#include "zygisk.hpp"
|
||||||
|
|
||||||
|
using namespace std;
|
||||||
|
|
||||||
|
// Entrypoint for app_process overlay
|
||||||
|
int app_process_main(int argc, char *argv[]) {
|
||||||
|
android_logging();
|
||||||
|
char buf[256];
|
||||||
|
|
||||||
|
bool zygote = false;
|
||||||
|
if (auto fp = open_file("/proc/self/attr/current", "r")) {
|
||||||
|
fscanf(fp.get(), "%s", buf);
|
||||||
|
zygote = (buf == "u:r:zygote:s0"sv);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!zygote) {
|
||||||
|
// For the non zygote case, we need to get real app_process via passthrough
|
||||||
|
// We have to connect magiskd via exec-ing magisk due to SELinux restrictions
|
||||||
|
|
||||||
|
// This is actually only relevant for calling app_process via ADB shell
|
||||||
|
// because zygisk shall already have the app_process overlays unmounted
|
||||||
|
// during app process specialization within its private mount namespace.
|
||||||
|
|
||||||
|
int fds[2];
|
||||||
|
socketpair(AF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0, fds);
|
||||||
|
if (fork_dont_care() == 0) {
|
||||||
|
// This fd has to survive exec
|
||||||
|
fcntl(fds[1], F_SETFD, 0);
|
||||||
|
snprintf(buf, sizeof(buf), "%d", fds[1]);
|
||||||
|
#if defined(__LP64__)
|
||||||
|
execlp("magisk", "zygisk", "passthrough", buf, "1", (char *) nullptr);
|
||||||
|
#else
|
||||||
|
execlp("magisk", "zygisk", "passthrough", buf, "0", (char *) nullptr);
|
||||||
|
#endif
|
||||||
|
exit(-1);
|
||||||
|
}
|
||||||
|
|
||||||
|
close(fds[1]);
|
||||||
|
if (read_int(fds[0]) != 0)
|
||||||
|
return 1;
|
||||||
|
int app_proc_fd = recv_fd(fds[0]);
|
||||||
|
if (app_proc_fd < 0)
|
||||||
|
return 1;
|
||||||
|
close(fds[0]);
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", app_proc_fd);
|
||||||
|
fcntl(app_proc_fd, F_SETFD, FD_CLOEXEC);
|
||||||
|
execve(buf, argv, environ);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (int socket = connect_daemon(); socket >= 0) {
|
||||||
|
do {
|
||||||
|
write_int(socket, ZYGISK_REQUEST);
|
||||||
|
write_int(socket, ZYGISK_SETUP);
|
||||||
|
|
||||||
|
if (read_int(socket) != 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
int app_proc_fd = recv_fd(socket);
|
||||||
|
if (app_proc_fd < 0)
|
||||||
|
break;
|
||||||
|
|
||||||
|
string path = read_string(socket);
|
||||||
|
string lib = path + ".1.so";
|
||||||
|
if (char *ld = getenv("LD_PRELOAD")) {
|
||||||
|
char env[256];
|
||||||
|
sprintf(env, "%s:%s", ld, lib.data());
|
||||||
|
setenv("LD_PRELOAD", env, 1);
|
||||||
|
} else {
|
||||||
|
setenv("LD_PRELOAD", lib.data(), 1);
|
||||||
|
}
|
||||||
|
setenv(INJECT_ENV_1, "1", 1);
|
||||||
|
|
||||||
|
close(socket);
|
||||||
|
|
||||||
|
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", app_proc_fd);
|
||||||
|
fcntl(app_proc_fd, F_SETFD, FD_CLOEXEC);
|
||||||
|
execve(buf, argv, environ);
|
||||||
|
} while (false);
|
||||||
|
|
||||||
|
close(socket);
|
||||||
|
}
|
||||||
|
|
||||||
|
// If encountering any errors, unmount and execute the original app_process
|
||||||
|
xreadlink("/proc/self/exe", buf, sizeof(buf));
|
||||||
|
xumount2("/proc/self/exe", MNT_DETACH);
|
||||||
|
execve(buf, argv, environ);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void zygiskd(int socket) {
|
||||||
|
if (getuid() != 0 || fcntl(socket, F_GETFD) < 0)
|
||||||
|
exit(-1);
|
||||||
|
|
||||||
|
#if defined(__LP64__)
|
||||||
|
set_nice_name("zygiskd64");
|
||||||
|
LOGI("* Launching zygiskd64\n");
|
||||||
|
#else
|
||||||
|
set_nice_name("zygiskd32");
|
||||||
|
LOGI("* Launching zygiskd32\n");
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Load modules
|
||||||
|
using comp_entry = void(*)(int);
|
||||||
|
vector<comp_entry> modules;
|
||||||
|
{
|
||||||
|
vector<int> module_fds = recv_fds(socket);
|
||||||
|
char buf[256];
|
||||||
|
for (int fd : module_fds) {
|
||||||
|
snprintf(buf, sizeof(buf), "/proc/self/fd/%d", fd);
|
||||||
|
comp_entry entry = nullptr;
|
||||||
|
if (void *h = dlopen(buf, RTLD_LAZY)) {
|
||||||
|
*(void **) &entry = dlsym(h, "zygisk_companion_entry");
|
||||||
|
}
|
||||||
|
modules.push_back(entry);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ack
|
||||||
|
write_int(socket, 0);
|
||||||
|
|
||||||
|
// Start accepting requests
|
||||||
|
pollfd pfd = { socket, POLLIN, 0 };
|
||||||
|
for (;;) {
|
||||||
|
poll(&pfd, 1, -1);
|
||||||
|
if (pfd.revents && !(pfd.revents & POLLIN)) {
|
||||||
|
// Something bad happened in magiskd, terminate zygiskd
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
int client = recv_fd(socket);
|
||||||
|
if (client < 0) {
|
||||||
|
// Something bad happened in magiskd, terminate zygiskd
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
int module_id = read_int(client);
|
||||||
|
if (module_id >= 0 && module_id < modules.size() && modules[module_id]) {
|
||||||
|
exec_task([=, entry = modules[module_id]] {
|
||||||
|
int dup = fcntl(client, F_DUPFD_CLOEXEC);
|
||||||
|
entry(client);
|
||||||
|
// Only close client if it is the same as dup so we don't
|
||||||
|
// accidentally close a re-used file descriptor.
|
||||||
|
// This check is required because the module companion
|
||||||
|
// handler could've closed the file descriptor already.
|
||||||
|
if (struct stat s1; fstat(client, &s1) == 0) {
|
||||||
|
struct stat s2{};
|
||||||
|
fstat(dup, &s2);
|
||||||
|
if (s1.st_dev == s2.st_dev && s1.st_ino == s2.st_ino) {
|
||||||
|
close(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
close(dup);
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
close(client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Entrypoint where we need to re-exec ourselves
|
||||||
|
// This should only ever be called internally
|
||||||
|
int zygisk_main(int argc, char *argv[]) {
|
||||||
|
android_logging();
|
||||||
|
|
||||||
|
if (argc == 3 && argv[1] == "companion"sv) {
|
||||||
|
zygiskd(parse_int(argv[2]));
|
||||||
|
} else if (argc == 4 && argv[1] == "passthrough"sv) {
|
||||||
|
int client = parse_int(argv[2]);
|
||||||
|
int is_64_bit = parse_int(argv[3]);
|
||||||
|
if (fcntl(client, F_GETFD) < 0)
|
||||||
|
return 1;
|
||||||
|
if (int magiskd = connect_daemon(); magiskd >= 0) {
|
||||||
|
write_int(magiskd, ZYGISK_PASSTHROUGH);
|
||||||
|
write_int(magiskd, ZYGISK_PASSTHROUGH);
|
||||||
|
write_int(magiskd, is_64_bit);
|
||||||
|
|
||||||
|
if (read_int(magiskd) != 0) {
|
||||||
|
write_int(client, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
write_int(client, 0);
|
||||||
|
int real_app_fd = recv_fd(magiskd);
|
||||||
|
send_fd(client, real_app_fd);
|
||||||
|
} else {
|
||||||
|
write_int(client, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
@ -47,4 +47,3 @@ void hook_functions();
|
|||||||
bool unhook_functions();
|
bool unhook_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, AppInfo *info);
|
||||||
int remote_request_unmount();
|
int remote_request_unmount();
|
||||||
void connect_companion(int client, bool is_64_bit);
|
|
||||||
|
Loading…
Reference in New Issue
Block a user