Use magiskd to setup files

This commit is contained in:
topjohnwu 2021-08-18 03:44:32 -07:00
parent 003fea52b1
commit 9b3efffba9
6 changed files with 118 additions and 62 deletions

View File

@ -68,6 +68,9 @@ static void handle_request_async(int client, int code, ucred cred) {
close(client);
reboot();
break;
case ZYGISK_REQUEST:
zygisk_handler(client, &cred);
break;
default:
close(client);
break;
@ -116,6 +119,7 @@ static void handle_request(int client) {
case BOOT_COMPLETE:
case SQLITE_CMD:
case GET_PATH:
case MAGISKHIDE:
if (!is_root) {
write_int(client, ROOT_REQUIRED);
goto done;
@ -127,9 +131,9 @@ static void handle_request(int client) {
goto done;
}
break;
case MAGISKHIDE: // accept hide request from zygote
if (!is_root && !is_zygote) {
write_int(client, ROOT_REQUIRED);
case ZYGISK_REQUEST:
if (!is_zygote) {
write_int(client, DAEMON_ERROR);
goto done;
}
break;
@ -260,7 +264,7 @@ int connect_daemon(bool create) {
if (connect(fd, (sockaddr*) &sun, len)) {
if (!create || getuid() != UID_ROOT) {
LOGE("No daemon is currently running!\n");
exit(1);
return 1;
}
if (fork_dont_care() == 0) {

View File

@ -158,6 +158,16 @@ void magisk_logging() {
log_cb.ex = nop_ex;
}
#define alog(prio) [](auto fmt, auto ap){ \
return __android_log_vprint(ANDROID_LOG_##prio, "Magisk", fmt, ap); }
void android_logging() {
log_cb.d = alog(DEBUG);
log_cb.i = alog(INFO);
log_cb.w = alog(WARN);
log_cb.e = alog(ERROR);
log_cb.ex = nop_ex;
}
void start_log_daemon() {
int fds[2];
if (pipe2(fds, O_CLOEXEC) == 0) {

View File

@ -25,6 +25,7 @@ enum : int {
MAGISKHIDE,
SQLITE_CMD,
REMOVE_MODULES,
ZYGISK_REQUEST,
DAEMON_CODE_END,
};
@ -47,12 +48,15 @@ enum : int {
int connect_daemon(bool create = false);
void android_logging();
// Daemon handlers
void post_fs_data(int client);
void late_start(int client);
void boot_complete(int client);
void magiskhide_handler(int client, ucred *cred);
void su_daemon_handler(int client, ucred *credential);
void zygisk_handler(int client, ucred *cred);
// MagiskHide
void check_enable_hide();

View File

@ -3,9 +3,10 @@
#include <sys/mount.h>
#include <sys/sendfile.h>
#include <sys/prctl.h>
#include <android/log.h>
#include <utils.hpp>
#include <daemon.hpp>
#include <magisk.hpp>
#include "inject.hpp"
@ -14,16 +15,6 @@ using namespace std;
static void *self_handle = nullptr;
static atomic<int> active_threads = -1;
#define alog(prio) [](auto fmt, auto ap){ \
return __android_log_vprint(ANDROID_LOG_##prio, "Magisk", fmt, ap); }
static void inject_logging() {
log_cb.d = alog(DEBUG);
log_cb.i = alog(INFO);
log_cb.w = alog(WARN);
log_cb.e = alog(ERROR);
log_cb.ex = nop_ex;
}
void self_unload() {
LOGD("hook: Request to self unload\n");
// If unhook failed, do not unload or else it will cause SIGSEGV
@ -33,7 +24,7 @@ void self_unload() {
active_threads--;
}
static void *unload_first_stage(void *) {
static void *unload_first_stage(void *v) {
// Setup 1ms
timespec ts = { .tv_sec = 0, .tv_nsec = 1000000L };
@ -43,7 +34,8 @@ static void *unload_first_stage(void *) {
// Wait another 1ms to make sure all threads left our code
nanosleep(&ts, nullptr);
unmap_all(INJECT_LIB_1);
char *path = static_cast<char *>(v);
unmap_all(path);
active_threads--;
return nullptr;
}
@ -87,66 +79,108 @@ static void inject_cleanup_wait() {
__attribute__((constructor))
static void inject_init() {
if (getenv(INJECT_ENV_2)) {
inject_logging();
if (char *env = getenv(INJECT_ENV_2)) {
android_logging();
LOGD("zygote: inject 2nd stage\n");
active_threads = 1;
unsetenv(INJECT_ENV_2);
// Get our own handle
self_handle = dlopen(INJECT_LIB_2, RTLD_LAZY);
self_handle = dlopen(env, RTLD_LAZY);
dlclose(self_handle);
unlink(INJECT_LIB_2);
hook_functions();
// Update path to 1st stage lib
*(strrchr(env, '.') - 1) = '1';
// Some cleanup
sanitize_environ();
active_threads++;
new_daemon_thread(&unload_first_stage);
} else if (char *env = getenv(INJECT_ENV_1)) {
inject_logging();
new_daemon_thread(&unload_first_stage, env);
} else if (getenv(INJECT_ENV_1)) {
android_logging();
LOGD("zygote: inject 1st stage\n");
if (env[0] == '1')
char *ld = getenv("LD_PRELOAD");
char *path;
if (char *c = strrchr(ld, ':')) {
*c = '\0';
setenv("LD_PRELOAD", ld, 1); // Restore original LD_PRELOAD
path = c + 1;
} else {
unsetenv("LD_PRELOAD");
else
setenv("LD_PRELOAD", env, 1); // Restore original LD_PRELOAD
path = ld;
}
// Update path to 2nd stage lib
*(strrchr(path, '.') - 1) = '2';
// Setup second stage
setenv(INJECT_ENV_2, "1", 1);
cp_afc(INJECT_LIB_1, INJECT_LIB_2);
dlopen(INJECT_LIB_2, RTLD_LAZY);
setenv(INJECT_ENV_2, path, 1);
dlopen(path, RTLD_LAZY);
unlink(INJECT_LIB_1);
unsetenv(INJECT_ENV_1);
}
}
int app_process_main(int argc, char *argv[]) {
inject_logging();
char buf[4096];
if (realpath("/proc/self/exe", buf) == nullptr)
return 1;
android_logging();
int in = xopen(buf, O_RDONLY);
int out = xopen(INJECT_LIB_1, O_WRONLY | O_CREAT, 0644);
sendfile(out, in, nullptr, INT_MAX);
close(in);
close(out);
if (int fd = connect_daemon(); fd >= 0) {
write_int(fd, ZYGISK_REQUEST);
write_int(fd, ZYGISK_SETUP);
if (char *ld = getenv("LD_PRELOAD")) {
char env[128];
sprintf(env, "%s:" INJECT_LIB_1, ld);
setenv("LD_PRELOAD", env, 1);
setenv(INJECT_ENV_1, ld, 1); // Backup original LD_PRELOAD
} else {
setenv("LD_PRELOAD", INJECT_LIB_1, 1);
setenv(INJECT_ENV_1, "1", 1);
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
xumount2(buf, MNT_DETACH);
char buf[256];
xreadlink("/proc/self/exe", buf, sizeof(buf));
xumount2("/proc/self/exe", MNT_DETACH);
execve(buf, argv, environ);
return 1;
}
// The following code runs in magiskd
static void setup_files(int client, ucred *cred) {
LOGD("zygisk: setup files\n");
char buf[PATH_MAX];
sprintf(buf, "/proc/%d/exe", cred->pid);
if (realpath(buf, buf) == nullptr) {
write_int(client, 1);
return;
}
write_int(client, 0);
string path = MAGISKTMP + "/zygisk." + basename(buf);
cp_afc(buf, (path + ".1.so").data());
cp_afc(buf, (path + ".2.so").data());
write_string(client, path);
}
void zygisk_handler(int client, ucred *cred) {
int code = read_int(client);
switch (code) {
case ZYGISK_SETUP:
setup_files(client, cred);
break;
}
close(client);
}

View File

@ -3,11 +3,13 @@
#include <stdint.h>
#include <jni.h>
#define INJECT_LIB_1 "/dev/tmp/magisk.1.so"
#define INJECT_LIB_2 "/dev/tmp/magisk.2.so"
#define INJECT_ENV_1 "MAGISK_INJ_1"
#define INJECT_ENV_2 "MAGISK_INJ_2"
enum : int {
ZYGISK_SETUP,
};
// Unmap all pages matching the name
void unmap_all(const char *name);

View File

@ -23,7 +23,7 @@ abort() {
mount_sbin() {
mount -t tmpfs -o 'mode=0755' tmpfs /sbin
$SELINUX && chcon u:object_r:rootfs:s0 /sbin
chcon u:object_r:rootfs:s0 /sbin
}
if [ ! -f /system/build.prop ]; then
@ -56,14 +56,14 @@ fi
pgrep magiskd >/dev/null && pkill -9 magiskd
[ -f /sbin/magisk ] && umount -l /sbin
[ -f /system/bin/magisk ] && umount -l /system/bin
if [ -d /dev/magisk ]; then
umount -l /dev/magisk 2>/dev/null
rm -rf /dev/magisk
fi
# SELinux stuffs
SELINUX=false
[ -e /sys/fs/selinux ] && SELINUX=true
if $SELINUX; then
ln -sf ./magiskinit magiskpolicy
./magiskpolicy --live --magisk
fi
ln -sf ./magiskinit magiskpolicy
./magiskpolicy --live --magisk
BINDIR=/sbin
@ -99,12 +99,14 @@ elif [ -e /sbin ]; then
done
else
# Android Q+ without sbin, use overlayfs
BINDIR=/system/bin
rm -rf /dev/magisk
mkdir -p /dev/magisk/upper
BINDIR=/dev/magisk/upper
mkdir /dev/magisk
mount -t tmpfs -o 'mode=0755' tmpfs /dev/magisk
chcon u:object_r:system_file:s0 /dev/magisk
mkdir /dev/magisk/upper
mkdir /dev/magisk/work
./magisk --clone-attr /system/bin /dev/magisk/upper
mount -t overlay overlay -olowerdir=/system/bin,upperdir=/dev/magisk/upper,workdir=/dev/magisk/work /system/bin
mount -t overlay overlay -o lowerdir=/system/bin,upperdir=/dev/magisk/upper,workdir=/dev/magisk/work /system/bin
fi
# Magisk stuffs