Hijack another binary for 2nd stage

Instead of using ptrace hacks, use another hack instead :D
This commit is contained in:
topjohnwu 2020-04-19 22:15:12 -07:00
parent 765d5d9729
commit e219867cdf
4 changed files with 52 additions and 52 deletions

View File

@ -101,7 +101,7 @@ public:
class SARFirstStageInit : public SARBase {
private:
void traced_exec_init();
void prepare();
protected:
void early_mount() override;
public:
@ -110,7 +110,8 @@ public:
};
void start() override {
early_mount();
traced_exec_init();
prepare();
exec_init();
}
};

View File

@ -195,7 +195,8 @@ void SARBase::backup_files() {
backup_folder("/overlay.d", overlays);
full_read("/proc/self/exe", self.buf, self.sz);
full_read("/.backup/.magisk", config.buf, config.sz);
if (access("/.backup/.magisk", R_OK) == 0)
full_read("/.backup/.magisk", config.buf, config.sz);
}
void SARBase::mount_system_root() {
@ -242,11 +243,9 @@ void SARFirstStageInit::early_mount() {
void SecondStageInit::early_mount() {
backup_files();
rm_rf("/system");
rm_rf("/.backup");
rm_rf("/overlay.d");
umount2("/system/bin/init", MNT_DETACH);
umount2("/init", MNT_DETACH);
umount2("/proc/self/exe", MNT_DETACH);
if (access("/system_root", F_OK) == 0)
switch_root("/system_root");

View File

@ -131,9 +131,11 @@ bool MagiskInit::patch_sepolicy(const char *file) {
return false;
}
// Mount selinuxfs to communicate with kernel
xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr);
mount_list.emplace_back(SELINUX_MNT);
if (access(SELINUX_VERSION, F_OK) != 0) {
// Mount selinuxfs to communicate with kernel
xmount("selinuxfs", SELINUX_MNT, "selinuxfs", 0, nullptr);
mount_list.emplace_back(SELINUX_MNT);
}
if (patch_init)
load_split_cil();
@ -307,10 +309,10 @@ void SARBase::patch_rootdir() {
struct sockaddr_un sun;
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
if (connect(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET)) == 0) {
LOGD("ACK init tracer to write backup files\n");
// Let tracer know where tmp_dir is
LOGD("ACK init daemon to write backup files\n");
// Let daemon know where tmp_dir is
write_string(sockfd, tmp_dir);
// Wait for tracer to finish copying files
// Wait for daemon to finish restoring files
int ack;
read(sockfd, &ack, sizeof(ack));
} else {

View File

@ -1,6 +1,3 @@
#include <sys/ptrace.h>
#include <sys/wait.h>
#include <magisk.hpp>
#include <utils.hpp>
#include <logging.hpp>
@ -76,20 +73,41 @@ void FirstStageInit::prepare() {
chdir("/");
}
static inline long xptrace(int request, pid_t pid, void *addr, void *data) {
long ret = ptrace(request, pid, addr, data);
if (ret < 0)
PLOGE("ptrace %d", pid);
return ret;
}
#define INIT_PATH "/system/bin/init"
#define REDIR_PATH "/system/bin/adbd"
static inline long xptrace(int request, pid_t pid, void *addr = nullptr, intptr_t data = 0) {
return xptrace(request, pid, addr, reinterpret_cast<void *>(data));
}
void SARFirstStageInit::traced_exec_init() {
void SARFirstStageInit::prepare() {
int pid = getpid();
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
// Patch init binary
raw_data init;
int src = xopen("/init", O_RDONLY);
fd_full_read(src, init.buf, init.sz);
for (uint8_t *p = init.buf, *eof = init.buf + init.sz; p < eof; ++p) {
if (memcmp(p, INIT_PATH, sizeof(INIT_PATH)) == 0) {
LOGD("Patch init [" INIT_PATH "] -> [" REDIR_PATH "]\n");
memcpy(p, REDIR_PATH, sizeof(REDIR_PATH));
break;
}
}
int dest = xopen("/dev/init", O_CREAT | O_WRONLY, 0);
write(dest, init.buf, init.sz);
fclone_attr(src, dest);
close(dest);
// Replace redirect init with magiskinit
dest = xopen("/dev/magiskinit", O_CREAT | O_WRONLY, 0);
write(dest, self.buf, self.sz);
fclone_attr(src, dest);
close(src);
close(dest);
xmount("/dev/init", "/init", nullptr, MS_BIND, nullptr);
xmount("/dev/magiskinit", REDIR_PATH, nullptr, MS_BIND, nullptr);
xumount2("/dev", MNT_DETACH);
// Block SIGUSR1
sigset_t block, old;
sigemptyset(&block);
@ -97,42 +115,22 @@ void SARFirstStageInit::traced_exec_init() {
sigprocmask(SIG_BLOCK, &block, &old);
if (int child = xfork(); child) {
LOGD("init tracer [%d]\n", child);
// Wait for children to attach
LOGD("init daemon [%d]\n", child);
// Wait for children signal
int sig;
sigwait(&block, &sig);
// Restore sigmask
sigprocmask(SIG_BLOCK, &old, nullptr);
// Re-exec init
exec_init();
sigprocmask(SIG_SETMASK, &old, nullptr);
} else {
// Attach to parent to trace exec
xptrace(PTRACE_ATTACH, pid);
waitpid(pid, nullptr, __WALL | __WNOTHREAD);
xptrace(PTRACE_SETOPTIONS, pid, nullptr, PTRACE_O_TRACEEXEC);
xptrace(PTRACE_CONT, pid, 0, SIGUSR1);
// Wait for execve
waitpid(pid, nullptr, __WALL | __WNOTHREAD);
// Swap out init with bind mount
xmount("tmpfs", "/dev", "tmpfs", 0, "mode=755");
int init = xopen("/dev/magiskinit", O_CREAT | O_WRONLY, 0750);
write(init, self.buf, self.sz);
close(init);
xmount("/dev/magiskinit", "/init", nullptr, MS_BIND, nullptr);
xumount2("/dev", MNT_DETACH);
// Establish socket for 2nd stage ack
struct sockaddr_un sun;
int sockfd = xsocket(AF_LOCAL, SOCK_STREAM | SOCK_CLOEXEC, 0);
xbind(sockfd, (struct sockaddr*) &sun, setup_sockaddr(&sun, INIT_SOCKET));
xlisten(sockfd, 1);
// Resume init
xptrace(PTRACE_DETACH, pid);
// Resume parent
kill(pid, SIGUSR1);
// Wait for second stage ack
int client = xaccept4(sockfd, nullptr, nullptr, SOCK_CLOEXEC);