diff --git a/native/jni/init/early_mount.cpp b/native/jni/init/early_mount.cpp index c9b47e44e..05b913e64 100644 --- a/native/jni/init/early_mount.cpp +++ b/native/jni/init/early_mount.cpp @@ -53,7 +53,7 @@ static void collect_devices() { closedir(dir); } -static void setup_block(const char *partname, char *block_dev = nullptr) { +static dev_t setup_block(const char *partname, char *block_dev = nullptr) { if (dev_list.empty()) collect_devices(); for (;;) { @@ -65,9 +65,9 @@ static void setup_block(const char *partname, char *block_dev = nullptr) { xmkdir("/dev/block", 0755); } LOGD("Found %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor); - mknod(block_dev ? block_dev : "/dev/root", S_IFBLK | 0600, - makedev(dev.major, dev.minor)); - return; + dev_t rdev = makedev(dev.major, dev.minor); + mknod(block_dev ? block_dev : "/dev/root", S_IFBLK | 0600, rdev); + return rdev; } } // Wait 10ms and try again @@ -174,7 +174,7 @@ void SARInit::early_mount() { LOGD("Early mount system_root\n"); sprintf(partname, "system%s", cmd->slot); - setup_block(partname); + system_dev = setup_block(partname); xmkdir("/system_root", 0755); if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr)) xmount("/dev/root", "/system_root", "erofs", MS_RDONLY, nullptr); diff --git a/native/jni/init/init.cpp b/native/jni/init/init.cpp index 06c84fe71..13f6a3f87 100644 --- a/native/jni/init/init.cpp +++ b/native/jni/init/init.cpp @@ -134,6 +134,7 @@ void LegacyInit::preset() { void SARInit::preset() { full_read("/init", &self.buf, &self.sz); + full_read("/.backup/.magisk", &config.buf, &config.sz); LOGD("Cleaning rootfs\n"); root = open("/", O_RDONLY | O_CLOEXEC); @@ -145,7 +146,7 @@ void SARCompatInit::preset() { LOGD("Cleaning rootfs\n"); root = open("/", O_RDONLY | O_CLOEXEC); - frm_rf(root, { "overlay", "proc", "sys" }); + frm_rf(root, { ".backup", "overlay", "proc", "sys" }); } void RootFSInit::start() { @@ -158,6 +159,7 @@ void RootFSInit::start() { void SARInit::start() { preset(); early_mount(); + patch_rootdir(); re_exec_init(); } diff --git a/native/jni/init/init.h b/native/jni/init/init.h index 8041f8b39..b7a2d3d94 100644 --- a/native/jni/init/init.h +++ b/native/jni/init/init.h @@ -44,8 +44,12 @@ public: class SARInit : public MagiskInit { protected: + raw_data config{}; + dev_t system_dev; + void preset() override; void early_mount() override; + void patch_rootdir(); public: SARInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {}; void start() override; diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index 70a670075..52d00203c 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -175,6 +175,84 @@ bool MagiskInit::patch_sepolicy() { return patch_init; } +static void sbin_overlay(const raw_data &self, const raw_data &config) { + LOGD("Mount /sbin tmpfs overlay\n"); + xmount("tmpfs", "/sbin", "tmpfs", 0, "mode=755"); + + // Dump binaries + xmkdir(MAGISKTMP, 0755); + int fd = xopen(MAGISKTMP "/config", O_WRONLY | O_CREAT, 0000); + xwrite(fd, config.buf, config.sz); + close(fd); + fd = xopen("/sbin/magiskinit", O_WRONLY | O_CREAT, 0755); + xwrite(fd, self.buf, self.sz); + close(fd); + if (access("/system/apex", F_OK) == 0) { + LOGD("APEX detected, use wrapper\n"); + dump_magisk("/sbin/magisk.bin", 0755); + patch_socket_name("/sbin/magisk.bin"); + fd = xopen("/sbin/magisk", O_WRONLY | O_CREAT, 0755); + xwrite(fd, wrapper, sizeof(wrapper) - 1); + close(fd); + } else { + dump_magisk("/sbin/magisk", 0755); + patch_socket_name("/sbin/magisk"); + } + + // Create applet symlinks + char path[64]; + for (int i = 0; applet_names[i]; ++i) { + sprintf(path, "/sbin/%s", applet_names[i]); + xsymlink("/sbin/magisk", path); + } + xsymlink("/sbin/magiskinit", "/sbin/magiskpolicy"); + xsymlink("/sbin/magiskinit", "/sbin/supolicy"); +} + +#define ROOTMIR MIRRDIR "/system_root" +#define ROOTBLK BLOCKDIR "/system_root" + +void SARInit::patch_rootdir() { + sbin_overlay(self, config); + + // Mount system_root mirror + xmkdir(MIRRDIR, 0777); + xmkdir(ROOTMIR, 0777); + xmkdir(BLOCKDIR, 0777); + mknod(ROOTBLK, S_IFBLK | 0600, system_dev); + if (xmount(ROOTBLK, ROOTMIR, "ext4", MS_RDONLY, nullptr)) + xmount(ROOTBLK, ROOTMIR, "erofs", MS_RDONLY, nullptr); + + // Recreate original sbin structure + int src = xopen(ROOTMIR, O_RDONLY | O_CLOEXEC); + int dest = xopen(ROOTMIR, O_RDONLY | O_CLOEXEC); + DIR *fp = fdopendir(src); + struct dirent *entry; + struct stat st; + char buf[256]; + while ((entry = xreaddir(fp))) { + if (entry->d_name == "."sv || entry->d_name == ".."sv) + continue; + fstatat(src, entry->d_name, &st, AT_SYMLINK_NOFOLLOW); + if (S_ISLNK(st.st_mode)) { + xreadlinkat(src, entry->d_name, buf, sizeof(buf)); + xsymlinkat(buf, dest, entry->d_name); + } else { + char tpath[256]; + sprintf(buf, "/sbin/%s", entry->d_name); + sprintf(tpath, ROOTMIR "/sbin/%s", entry->d_name); + // Create dummy + if (S_ISDIR(st.st_mode)) + xmkdir(tpath, st.st_mode & 0777); + else + close(xopen(tpath, O_CREAT | O_WRONLY | O_CLOEXEC, st.st_mode & 0777)); + xmount(tpath, buf, nullptr, MS_BIND, nullptr); + } + } + close(src); + close(dest); +} + #ifdef MAGISK_DEBUG static FILE *kmsg; static int vprintk(const char *fmt, va_list ap) { @@ -206,14 +284,12 @@ int magisk_proxy_main(int argc, char *argv[]) { unlink("/sbin/magisk"); rm_rf("/.backup"); - LOGD("Mount /sbin tmpfs overlay\n"); - xmount("tmpfs", "/sbin", "tmpfs", 0, "mode=755"); - int sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC); - - char path[64]; + sbin_overlay(self, config); // Create symlinks pointing back to /root { + char path[256]; + int sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC); unique_ptr dir(xopendir("/root"), &closedir); struct dirent *entry; while((entry = xreaddir(dir.get()))) { @@ -222,36 +298,9 @@ int magisk_proxy_main(int argc, char *argv[]) { sprintf(path, "/root/%s", entry->d_name); xsymlinkat(path, sbin, entry->d_name); } + close(sbin); } - // Dump binaries - mkdir(MAGISKTMP, 0755); - int fd = xopen(MAGISKTMP "/config", O_WRONLY | O_CREAT, 0000); - write(fd, config.buf, config.sz); - close(fd); - fd = xopen("/sbin/magiskinit", O_WRONLY | O_CREAT, 0755); - write(fd, self.buf, self.sz); - close(fd); - if (access("/system/apex", F_OK) == 0) { - LOGD("APEX detected, use wrapper\n"); - dump_magisk("/sbin/magisk.bin", 0755); - patch_socket_name("/sbin/magisk.bin"); - fd = xopen("/sbin/magisk", O_WRONLY | O_CREAT, 0755); - write(fd, wrapper, sizeof(wrapper) - 1); - close(fd); - } else { - dump_magisk("/sbin/magisk", 0755); - patch_socket_name("/sbin/magisk"); - } - - // Create applet symlinks - for (int i = 0; applet_names[i]; ++i) { - sprintf(path, "/sbin/%s", applet_names[i]); - xsymlink("/sbin/magisk", path); - } - xsymlink("/sbin/magiskinit", "/sbin/magiskpolicy"); - xsymlink("/sbin/magiskinit", "/sbin/supolicy"); - setenv("REMOUNT_ROOT", "1", 1); execv("/sbin/magisk", argv); diff --git a/native/jni/utils/include/missing.h b/native/jni/utils/include/missing.h index 54fe4af9c..d437f784a 100644 --- a/native/jni/utils/include/missing.h +++ b/native/jni/utils/include/missing.h @@ -9,6 +9,7 @@ #define setns __setns #define unshare __unshare #define accept4 __accept4 +#define dup3 __dup3 #define readlinkat __readlinkat #define symlinkat __symlinkat #define linkat __linkat @@ -39,6 +40,10 @@ static inline int __accept4(int sockfd, struct sockaddr *addr, socklen_t *addrle return syscall(__NR_accept4, sockfd, addr, addrlen, flags); } +static inline int __dup3(int oldfd, int newfd, int flags) { + return syscall(__NR_dup3, oldfd, newfd, flags); +} + static inline ssize_t __readlinkat(int dirfd, const char *pathname, char *buf, size_t bufsiz) { return syscall(__NR_readlinkat, dirfd, pathname, buf, bufsiz); } diff --git a/native/jni/utils/xwrap.cpp b/native/jni/utils/xwrap.cpp index e55fd69b8..6f609c656 100644 --- a/native/jni/utils/xwrap.cpp +++ b/native/jni/utils/xwrap.cpp @@ -278,7 +278,7 @@ int xdup2(int oldfd, int newfd) { } int xdup3(int oldfd, int newfd, int flags) { - int ret = (int) syscall(__NR_dup3, oldfd, newfd, flags); + int ret = dup3(oldfd, newfd, flags); if (ret == -1) { PLOGE("dup3"); }