From c8491d008f3e6a5799c0d757378f2ba6b4d951fc Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sat, 9 Feb 2019 01:51:46 -0500 Subject: [PATCH] Move sbin overlay creation to magiskinit --- native/jni/core/bootstages.cpp | 121 +++------------------- native/jni/core/init.cpp | 159 ++++++++++++++++++++++------- native/jni/core/magisk.cpp | 5 +- native/jni/include/magisk.h | 4 +- native/jni/include/magiskrc.h | 8 +- native/jni/magiskpolicy/rules.cpp | 4 + native/jni/utils/include/selinux.h | 1 + native/jni/utils/selinux.cpp | 75 +++++++++++--- 8 files changed, 214 insertions(+), 163 deletions(-) diff --git a/native/jni/core/bootstages.cpp b/native/jni/core/bootstages.cpp index 12e0fb37c..a5d0d8d7e 100644 --- a/native/jni/core/bootstages.cpp +++ b/native/jni/core/bootstages.cpp @@ -632,17 +632,24 @@ void unlock_blocks() { pthread_exit(nullptr); } -static const char wrapper[] = -"#!/system/bin/sh\n" -"unset LD_LIBRARY_PATH\n" -"unset LD_PRELOAD\n" -"exec /sbin/magisk.bin \"${0##*/}\" \"$@\"\n"; +[[noreturn]] static inline void core_only() { + auto_start_magiskhide(); + unblock_boot_process(); +} + +void post_fs_data(int client) { + // ack + write_int(client, 0); + close(client); -void startup() { - android_logging(); if (!check_data()) unblock_boot_process(); + LOGI("** post-fs-data mode running\n"); + + // Unlock all blocks for rw + unlock_blocks(); + if (access(SECURE_DIR, F_OK) != 0) { /* If the folder is not automatically created by the system, * do NOT proceed further. Manual creation of the folder @@ -673,106 +680,6 @@ void startup() { simple_mount("/vendor"); } - // Unlock all blocks for rw - unlock_blocks(); - - LOGI("* Creating /sbin overlay"); - DIR *dir; - struct dirent *entry; - int root, sbin, fd; - void *magisk, *init; - size_t magisk_size, init_size; - - xmount(nullptr, "/", nullptr, MS_REMOUNT, nullptr); - - // GSIs will have to override /sbin/adbd with /system/bin/adbd - if (access("/sbin/adbd", F_OK) == 0 && access("/system/bin/adbd", F_OK) == 0) { - umount2("/sbin/adbd", MNT_DETACH); - cp_afc("/system/bin/adbd", "/sbin/adbd"); - } - - // Create hardlink mirror of /sbin to /root - mkdir("/root", 0750); - clone_attr("/sbin", "/root"); - full_read("/sbin/magisk", &magisk, &magisk_size); - unlink("/sbin/magisk"); - full_read("/sbin/magiskinit", &init, &init_size); - unlink("/sbin/magiskinit"); - root = xopen("/root", O_RDONLY | O_CLOEXEC); - sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC); - link_dir(sbin, root); - close(sbin); - - // Mount the /sbin tmpfs overlay - xmount("tmpfs", "/sbin", "tmpfs", 0, nullptr); - chmod("/sbin", 0755); - setfilecon("/sbin", "u:object_r:rootfs:s0"); - sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC); - - // Remove some traces of Magisk - unlink(MAGISKRC); - mkdir(MAGISKTMP, 0755); - cp_afc("/.backup/.magisk", MAGISKTMP "/config"); - rm_rf("/.backup"); - - // Create applet symlinks - for (int i = 0; applet_names[i]; ++i) { - snprintf(buf, PATH_MAX, "/sbin/%s", applet_names[i]); - xsymlink("/sbin/magisk", buf); - } - - // Setup binary and wrapper - fd = creat("/sbin/magisk.bin", 0755); - xwrite(fd, magisk, magisk_size); - close(fd); - free(magisk); - unlink("/sbin/magisk"); - fd = creat("/sbin/magisk", 0755); - xwrite(fd, wrapper, sizeof(wrapper) - 1); - close(fd); - setfilecon("/sbin/magisk.bin", "u:object_r:" SEPOL_FILE_DOMAIN ":s0"); - setfilecon("/sbin/magisk", "u:object_r:" SEPOL_FILE_DOMAIN ":s0"); - - // Setup magiskinit symlinks - fd = creat("/sbin/magiskinit", 0755); - xwrite(fd, init, init_size); - close(fd); - free(init); - setfilecon("/sbin/magiskinit", "u:object_r:" SEPOL_FILE_DOMAIN ":s0"); - for (int i = 0; init_applet[i]; ++i) { - snprintf(buf, PATH_MAX, "/sbin/%s", init_applet[i]); - xsymlink("/sbin/magiskinit", buf); - } - - // Create symlinks pointing back to /root - dir = xfdopendir(root); - while((entry = xreaddir(dir))) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; - snprintf(buf, PATH_MAX, "/root/%s", entry->d_name); - xsymlinkat(buf, sbin, entry->d_name); - } - - close(sbin); - close(root); - - // Start post-fs-data mode - execl("/sbin/magisk.bin", "magisk", "--post-fs-data", nullptr); -} - -[[noreturn]] static inline void core_only() { - auto_start_magiskhide(); - unblock_boot_process(); -} - -void post_fs_data(int client) { - // ack - write_int(client, 0); - close(client); - - xmount(nullptr, "/", nullptr, MS_REMOUNT | MS_RDONLY, nullptr); - - LOGI("** post-fs-data mode running\n"); - if (!magisk_env()) { LOGE("* Magisk environment setup incomplete, abort\n"); unblock_boot_process(); diff --git a/native/jni/core/init.cpp b/native/jni/core/init.cpp index 5004b219f..bde715111 100644 --- a/native/jni/core/init.cpp +++ b/native/jni/core/init.cpp @@ -42,6 +42,7 @@ #include "magiskrc.h" #include "magisk.h" #include "magiskpolicy.h" +#include "selinux.h" #include "utils.h" #include "flags.h" @@ -49,10 +50,12 @@ int (*init_applet_main[]) (int, char *[]) = { magiskpolicy_main, magiskpolicy_main, nullptr }; -static int root = -1; static bool mnt_system = false; static bool mnt_vendor = false; +static void *self, *config; +static size_t self_sz, config_sz; + struct cmdline { bool early_boot; char slot[3]; @@ -344,9 +347,104 @@ static void patch_socket_name(const char *path) { munmap(buf, size); } +static void setup_rc() { + // Patch init.rc to load magisk scripts + bool injected = false; + char line[4096]; + FILE *fp = xfopen("/init.rc", "r"); + int fd = open("/init.rc.new", O_WRONLY | O_CREAT | O_CLOEXEC, 0750); + while(fgets(line, sizeof(line), fp)) { + if (!injected && strncmp(line, "import", 6) == 0) { + if (strstr(line, "init.magisk.rc")) { + injected = true; + } else { + xwrite(fd, "import /init.magisk.rc\n", 23); + injected = true; + } + } else if (strstr(line, "selinux.reload_policy")) { + // Do not allow sepolicy patch + continue; + } + xwrite(fd, line, strlen(line)); + } + fclose(fp); + close(fd); + rename("/init.rc.new", "/init.rc"); + dump_magiskrc(MAGISKRC, 0750); +} + +static const char wrapper[] = +"#!/system/bin/sh\n" +"unset LD_LIBRARY_PATH\n" +"unset LD_PRELOAD\n" +"exec /sbin/magisk.bin \"${0##*/}\" \"$@\"\n"; + +static void setup_overlay() { + char buf[128]; + int fd; + + while (access(EARLYINIT, F_OK) != 0) + usleep(10); + selinux_builtin_impl(); + setcon("u:r:" SEPOL_PROC_DOMAIN ":s0"); + unlink(EARLYINIT); + + fd = open("/dev/null", O_RDWR); + xdup2(fd, STDIN_FILENO); + xdup2(fd, STDOUT_FILENO); + xdup2(fd, STDERR_FILENO); + + // Mount the /sbin tmpfs overlay + xmount("tmpfs", "/sbin", "tmpfs", 0, nullptr); + chmod("/sbin", 0755); + setfilecon("/sbin", "u:object_r:rootfs:s0"); + + // Dump binaries + mkdir(MAGISKTMP, 0755); + fd = open(MAGISKTMP "/config", O_WRONLY | O_CREAT, 0000); + write(fd, config, config_sz); + close(fd); + fd = open("/sbin/magiskinit", O_WRONLY | O_CREAT, 0755); + write(fd, self, self_sz); + close(fd); + fd = open("/sbin/magisk", O_WRONLY | O_CREAT, 0755); + write(fd, wrapper, sizeof(wrapper)); + close(fd); + dump_magisk("/sbin/magisk.bin", 0755); + patch_socket_name("/sbin/magisk.bin"); + setfilecon("/sbin/magisk", "u:object_r:" SEPOL_FILE_DOMAIN ":s0"); + setfilecon("/sbin/magisk.bin", "u:object_r:" SEPOL_FILE_DOMAIN ":s0"); + setfilecon("/sbin/magiskinit", "u:object_r:" SEPOL_FILE_DOMAIN ":s0"); + + // Create applet symlinks + for (int i = 0; applet_names[i]; ++i) { + sprintf(buf, "/sbin/%s", applet_names[i]); + xsymlink("/sbin/magisk", buf); + } + for (int i = 0; init_applet[i]; ++i) { + sprintf(buf, "/sbin/%s", init_applet[i]); + xsymlink("/sbin/magiskinit", buf); + } + + // Create symlinks pointing back to /root + DIR *dir; + struct dirent *entry; + dir = xopendir("/root"); + fd = xopen("/sbin", O_RDONLY); + while((entry = xreaddir(dir))) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + snprintf(buf, PATH_MAX, "/root/%s", entry->d_name); + xsymlinkat(buf, fd, entry->d_name); + } + closedir(dir); + close(fd); + + close(xopen(EARLYINITDONE, O_RDONLY | O_CREAT, 0)); + exit(0); +} + static void exec_init(char *argv[]) { // Clean up - close(root); umount("/proc"); umount("/sys"); if (mnt_system) @@ -384,8 +482,9 @@ int main(int argc, char *argv[]) { if (null > STDERR_FILENO) close(null); - // Backup self - rename("/init", "/init.bak"); + // Backup stuffs + full_read("/init", &self, &self_sz); + full_read("/.backup/.magisk", &config, &config_sz); // Communicate with kernel using procfs and sysfs mkdir("/proc", 0755); @@ -400,25 +499,24 @@ int main(int argc, char *argv[]) { * Initialize * ***********/ + int root, sbin; root = open("/", O_RDONLY | O_CLOEXEC); if (cmd.early_boot) { // Clear rootfs - const char *excl[] = { "overlay", ".backup", "proc", "sys", "init.bak", nullptr }; + const char *excl[] = { "overlay", "proc", "sys", nullptr }; excl_list = excl; frm_rf(root); excl_list = nullptr; } else { // Revert original init binary link("/.backup/init", "/init"); + rm_rf("/.backup"); } // Do not go further if system_root device is booting as recovery - if (!cmd.early_boot && access("/sbin/recovery", F_OK) == 0) { - // Remove Magisk traces - rm_rf("/.backup"); + if (!cmd.early_boot && access("/sbin/recovery", F_OK) == 0) exec_init(argv); - } /* ************ * Early Mount @@ -467,38 +565,25 @@ int main(int argc, char *argv[]) { close(fd); rmdir("/overlay"); } + close(root); - // Patch init.rc to load magisk scripts - bool injected = false; - char line[4096]; - FILE *fp = xfopen("/init.rc", "r"); - fd = creat("/init.rc.new", 0750); - while(fgets(line, sizeof(line), fp)) { - if (!injected && strncmp(line, "import", 6) == 0) { - if (strstr(line, "init.magisk.rc")) { - injected = true; - } else { - xwrite(fd, "import /init.magisk.rc\n", 23); - injected = true; - } - } else if (strstr(line, "selinux.reload_policy")) { - // Do not allow sepolicy patch - continue; - } - xwrite(fd, line, strlen(line)); - } - fclose(fp); - close(fd); - rename("/init.rc.new", "/init.rc"); + // Create hardlink mirror of /sbin to /root + mkdir("/root", 0750); + clone_attr("/sbin", "/root"); + root = xopen("/root", O_RDONLY | O_CLOEXEC); + sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC); + link_dir(sbin, root); - // Patch sepolicy + setup_rc(); patch_sepolicy(); - // Dump binaries - dump_magiskrc(MAGISKRC, 0750); - dump_magisk("/sbin/magisk", 0755); - patch_socket_name("/sbin/magisk"); - rename("/init.bak", "/sbin/magiskinit"); + // Close all file descriptors + for (int i = 0; i < 30; ++i) + close(i); + + // Launch daemon to setup overlay + if (fork_dont_care() == 0) + setup_overlay(); exec_init(argv); } diff --git a/native/jni/core/magisk.cpp b/native/jni/core/magisk.cpp index 55ae0f1d1..1fa3b4d1d 100644 --- a/native/jni/core/magisk.cpp +++ b/native/jni/core/magisk.cpp @@ -31,7 +31,7 @@ " --sqlite SQL exec SQL to Magisk database\n" "\n" "Supported init triggers:\n" - " startup, post-fs-data, service, boot-complete\n" + " post-fs-data, service, boot-complete\n" "\n" "Supported applets:\n"); @@ -77,9 +77,6 @@ int magisk_main(int argc, char *argv[]) { int fd = connect_daemon(); write_int(fd, DO_NOTHING); return 0; - } else if (strcmp(argv[1], "--startup") == 0) { - startup(); - return 0; } else if (strcmp(argv[1], "--post-fs-data") == 0) { int fd = connect_daemon(); write_int(fd, POST_FS_DATA); diff --git a/native/jni/include/magisk.h b/native/jni/include/magisk.h index 78f489acd..503d9e0b9 100644 --- a/native/jni/include/magisk.h +++ b/native/jni/include/magisk.h @@ -10,7 +10,9 @@ #define LOG_SOCKET "5864cd77f2f8c59b3882e2d35dbf51e4" #define JAVA_PACKAGE_NAME "com.topjohnwu.magisk" #define LOGFILE "/cache/magisk.log" -#define UNBLOCKFILE "/dev/.magisk.unblock" +#define UNBLOCKFILE "/dev/.magisk_unblock" +#define EARLYINIT "/dev/.magisk_early_init" +#define EARLYINITDONE "/dev/.magisk_early_init_done" #define DISABLEFILE "/cache/.disable_magisk" #define MAGISKTMP "/sbin/.magisk" #define BLOCKDIR MAGISKTMP "/block" diff --git a/native/jni/include/magiskrc.h b/native/jni/include/magiskrc.h index 43d2dd3ad..a1234f1cf 100644 --- a/native/jni/include/magiskrc.h +++ b/native/jni/include/magiskrc.h @@ -3,6 +3,12 @@ static const char magiskrc[] = +"on early-init\n" +" write " EARLYINIT " 1\n" +" wait " EARLYINITDONE "\n" +" rm " EARLYINITDONE "\n" +"\n" + "on post-fs-data\n" " start logd\n" " load_persist_props\n" @@ -12,7 +18,7 @@ static const char magiskrc[] = " rm " UNBLOCKFILE "\n" "\n" -"service %s /sbin/magisk --startup\n" +"service %s /sbin/magisk --post-fs-data\n" " user root\n" " seclabel u:r:" SEPOL_PROC_DOMAIN ":s0\n" " oneshot\n" diff --git a/native/jni/magiskpolicy/rules.cpp b/native/jni/magiskpolicy/rules.cpp index 22cdede09..0677e6e5f 100644 --- a/native/jni/magiskpolicy/rules.cpp +++ b/native/jni/magiskpolicy/rules.cpp @@ -46,6 +46,10 @@ void sepol_magisk_rules() { sepol_attradd(SEPOL_PROC_DOMAIN, "bluetoothdomain"); sepol_attradd(SEPOL_FILE_DOMAIN, "mlstrustedobject"); + // Let init daemon transit context + sepol_allow("kernel", "kernel", "process", "setcurrent"); + sepol_allow("kernel", SEPOL_PROC_DOMAIN, "process", "dyntransition"); + // Let init run stuffs sepol_allow("kernel", SEPOL_PROC_DOMAIN, "fd", "use"); sepol_allow("init", SEPOL_PROC_DOMAIN, "process", ALL); diff --git a/native/jni/utils/include/selinux.h b/native/jni/utils/include/selinux.h index 41ad7aa80..11f4bef89 100644 --- a/native/jni/utils/include/selinux.h +++ b/native/jni/utils/include/selinux.h @@ -11,6 +11,7 @@ extern int (*lgetfilecon)(const char *path, char ** con); extern int (*setfilecon)(const char *path, const char * con); extern int (*lsetfilecon)(const char *path, const char * con); +void selinux_builtin_impl(); void dload_selinux(); void restorecon(); diff --git a/native/jni/utils/selinux.cpp b/native/jni/utils/selinux.cpp index 5e184e2d8..fb32404f9 100644 --- a/native/jni/utils/selinux.cpp +++ b/native/jni/utils/selinux.cpp @@ -1,6 +1,9 @@ #include #include +#include #include +#include +#include #include "magisk.h" #include "utils.h" @@ -11,27 +14,73 @@ #define ADB_CON "u:object_r:adb_data_file:s0" #define MAGISK_CON "u:object_r:" SEPOL_FILE_DOMAIN ":s0" -// Stub implementations +// Stub implementation -static void v_s(char *s) { delete[] s; } +static int stub(const char *) { return 0; } -static int i_s(const char *) { return 0; } +static int stub(const char *, const char *) { return 0; } -static int i_ss(const char *, const char *) { return 0; } - -static int i_ssp(const char *, char ** sp) { - *sp = new char[1](); +static int stub(const char *, char **ctx) { + *ctx = strdup(""); return 0; } +// Builtin implementation + +static void __freecon(char *s) { + free(s); +} + +static int __setcon(const char *ctx) { + int fd = open("/proc/self/attr/current", O_WRONLY | O_CLOEXEC); + if (fd < 0) + return fd; + size_t len = strlen(ctx) + 1; + int rc = write(fd, ctx, len); + close(fd); + return rc != len; +} + +static int __getfilecon(const char *path, char **ctx) { + char buf[1024]; + int rc = syscall(__NR_getxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1); + if (rc > 0) + *ctx = strdup(buf); + return rc; +} + +static int __lgetfilecon(const char *path, char **ctx) { + char buf[1024]; + int rc = syscall(__NR_lgetxattr, path, XATTR_NAME_SELINUX, buf, sizeof(buf) - 1); + if (rc > 0) + *ctx = strdup(buf); + return rc; +} + +static int __setfilecon(const char *path, const char *ctx) { + return syscall(__NR_setxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0); +} + +static int __lsetfilecon(const char *path, const char *ctx) { + return syscall(__NR_lsetxattr, path, XATTR_NAME_SELINUX, ctx, strlen(ctx) + 1, 0); +} + // Function pointers -void (*freecon)(char *) = v_s; -int (*setcon)(const char *) = i_s; -int (*getfilecon)(const char *, char **) = i_ssp; -int (*lgetfilecon)(const char *, char **) = i_ssp; -int (*setfilecon)(const char *, const char *) = i_ss; -int (*lsetfilecon)(const char *, const char *) = i_ss; +void (*freecon)(char *) = __freecon; +int (*setcon)(const char *) = stub; +int (*getfilecon)(const char *, char **) = stub; +int (*lgetfilecon)(const char *, char **) = stub; +int (*setfilecon)(const char *, const char *) = stub; +int (*lsetfilecon)(const char *, const char *) = stub; + +void selinux_builtin_impl() { + setcon = __setcon; + getfilecon = __getfilecon; + lgetfilecon = __lgetfilecon; + setfilecon = __setfilecon; + setfilecon = __lsetfilecon; +} void dload_selinux() { void *handle = dlopen("libselinux.so", RTLD_LAZY);