diff --git a/native/jni/init/init.hpp b/native/jni/init/init.hpp index 409351521..0f4f67a25 100644 --- a/native/jni/init/init.hpp +++ b/native/jni/init/init.hpp @@ -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(); } }; diff --git a/native/jni/init/mount.cpp b/native/jni/init/mount.cpp index 138f7430e..8e65d6b80 100644 --- a/native/jni/init/mount.cpp +++ b/native/jni/init/mount.cpp @@ -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"); diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index 69927116c..71ea627c5 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -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 { diff --git a/native/jni/init/twostage.cpp b/native/jni/init/twostage.cpp index d3707a609..cccf74f87 100644 --- a/native/jni/init/twostage.cpp +++ b/native/jni/init/twostage.cpp @@ -1,6 +1,3 @@ -#include -#include - #include #include #include @@ -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(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);