diff --git a/app/src/main/res/raw/utils.sh b/app/src/main/res/raw/utils.sh index 5dda5e38b..66d2cafe1 100644 --- a/app/src/main/res/raw/utils.sh +++ b/app/src/main/res/raw/utils.sh @@ -77,6 +77,7 @@ post_ota() { cat << EOF > post-fs-data.d/post_ota.sh ${1}/bootctl mark-boot-successful rm -f ${1}/bootctl +rm -f ${1}/post-fs-data.d/post_ota.sh EOF chmod 755 post-fs-data.d/post_ota.sh cd / diff --git a/native/jni/core/daemon.cpp b/native/jni/core/daemon.cpp index f284ccb56..719bec4a9 100644 --- a/native/jni/core/daemon.cpp +++ b/native/jni/core/daemon.cpp @@ -101,6 +101,8 @@ static void main_daemon() { android_logging(); setsid(); setcon("u:r:" SEPOL_PROC_DOMAIN ":s0"); + restore_rootcon(); + int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC); xdup2(fd, STDOUT_FILENO); xdup2(fd, STDERR_FILENO); diff --git a/native/jni/core/init.cpp b/native/jni/core/init.cpp index 43da07002..7814ec1d3 100644 --- a/native/jni/core/init.cpp +++ b/native/jni/core/init.cpp @@ -46,7 +46,8 @@ static int vprintk(const char *fmt, va_list ap) { static void setup_klog() { mknod("/kmsg", S_IFCHR | 0666, makedev(1, 11)); - kmsg = xfopen("/kmsg", "ae"); + int fd = xopen("/kmsg", O_WRONLY | O_CLOEXEC); + kmsg = fdopen(fd, "w"); setbuf(kmsg, nullptr); unlink("/kmsg"); log_cb.d = log_cb.i = log_cb.w = log_cb.e = vprintk; @@ -156,11 +157,10 @@ private: bool read_dt_fstab(const char *name, char *partname, char *partfs); bool patch_sepolicy(); void cleanup(); + void re_exec_init(); public: explicit MagiskInit(char *argv[]) : argv(argv) {} - void setup_overlay(); - void re_exec_init(); void start(); void test(); }; @@ -460,6 +460,27 @@ void MagiskInit::early_mount() { mount_root(odm); } +static void patch_socket_name(const char *path) { + uint8_t *buf; + char name[sizeof(MAIN_SOCKET)]; + size_t size; + mmap_rw(path, buf, size); + for (int i = 0; i < size; ++i) { + if (memcmp(buf + i, MAIN_SOCKET, sizeof(MAIN_SOCKET)) == 0) { + gen_rand_str(name, sizeof(name)); + memcpy(buf + i, name, sizeof(name)); + i += sizeof(name); + } + } + munmap(buf, size); +} + +constexpr const char wrapper[] = +"#!/system/bin/sh\n" +"export LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH:/apex/com.android.runtime/" LIBNAME "\"\n" +"exec /sbin/magisk.bin \"$0\" \"$@\"\n" +; + void MagiskInit::setup_rootfs() { bool patch_init = patch_sepolicy(); @@ -531,6 +552,7 @@ void MagiskInit::setup_rootfs() { gen_rand_str(pfd_svc + 1, sizeof(pfd_svc) - 1); gen_rand_str(ls_svc + 1, sizeof(ls_svc) - 1); gen_rand_str(bc_svc + 1, sizeof(bc_svc) - 1); + LOGD("Inject magisk services: [%s] [%s] [%s]\n", pfd_svc, ls_svc, bc_svc); fprintf(rc, magiskrc, pfd_svc, pfd_svc, ls_svc, bc_svc, bc_svc); fclose(rc); clone_attr("/init.rc", "/init.p.rc"); @@ -545,6 +567,56 @@ void MagiskInit::setup_rootfs() { int rootdir = xopen("/root", O_RDONLY | O_CLOEXEC); int sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC); link_dir(sbin, rootdir); + close(sbin); + + LOGD("Mount /sbin tmpfs overlay\n"); + xmount("tmpfs", "/sbin", "tmpfs", 0, "mode=755"); + sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC); + + char path[64]; + + // Create symlinks pointing back to /root + DIR *dir = xfdopendir(rootdir); + struct dirent *entry; + while((entry = xreaddir(dir))) { + if (entry->d_name == "."sv || entry->d_name == ".."sv) + continue; + sprintf(path, "/root/%s", entry->d_name); + xsymlinkat(path, sbin, entry->d_name); + } + + // Dump binaries + mkdir(MAGISKTMP, 0755); + 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); + } + for (int i = 0; init_applet[i]; ++i) { + sprintf(path, "/sbin/%s", init_applet[i]); + xsymlink("/sbin/magiskinit", path); + } + + close(rootdir); + close(sbin); } bool MagiskInit::patch_sepolicy() { @@ -603,99 +675,8 @@ void MagiskInit::cleanup() { umount_root(odm); } -static inline void patch_socket_name(const char *path) { - uint8_t *buf; - char name[sizeof(MAIN_SOCKET)]; - size_t size; - mmap_rw(path, buf, size); - for (int i = 0; i < size; ++i) { - if (memcmp(buf + i, MAIN_SOCKET, sizeof(MAIN_SOCKET)) == 0) { - gen_rand_str(name, sizeof(name)); - memcpy(buf + i, name, sizeof(name)); - i += sizeof(name); - } - } - munmap(buf, size); -} - -static const char wrapper[] = -"#!/system/bin/sh\n" -"export LD_LIBRARY_PATH=\"$LD_LIBRARY_PATH:/apex/com.android.runtime/" LIBNAME "\"\n" -"exec /sbin/magisk.bin \"$0\" \"$@\"\n"; - -void MagiskInit::setup_overlay() { - char path[128]; - int fd; - - // Wait for early-init start - while (access(EARLYINIT, F_OK) != 0) - usleep(10); - setcon("u:r:" SEPOL_PROC_DOMAIN ":s0"); - unlink(EARLYINIT); - -#ifdef MAGISK_DEBUG - kmsg = xfopen("/dev/kmsg", "ae"); - setbuf(kmsg, nullptr); -#endif - - LOGD("Setting up overlay\n"); - - // 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 = 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"); - setfilecon("/sbin/magisk.bin", "u:object_r:" SEPOL_FILE_DOMAIN ":s0"); - 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"); - } - setfilecon("/sbin/magisk", "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(path, "/sbin/%s", applet_names[i]); - xsymlink("/sbin/magisk", path); - } - for (int i = 0; init_applet[i]; ++i) { - sprintf(path, "/sbin/%s", init_applet[i]); - xsymlink("/sbin/magiskinit", path); - } - - // Create symlinks pointing back to /root - DIR *dir = xopendir("/root"); - struct dirent *entry; - fd = xopen("/sbin", O_RDONLY); - while((entry = xreaddir(dir))) { - if (entry->d_name == "."sv || entry->d_name == ".."sv) - continue; - sprintf(path, "/root/%s", entry->d_name); - xsymlinkat(path, fd, entry->d_name); - } - closedir(dir); - close(fd); - - close(xopen(EARLYINITDONE, O_RDONLY | O_CREAT, 0)); - exit(0); -} - void MagiskInit::re_exec_init() { + LOGD("Re-exec /init\n"); cleanup(); execv("/init", argv); exit(1); @@ -722,6 +703,7 @@ void MagiskInit::start() { preset(); early_mount(); setup_rootfs(); + re_exec_init(); } void MagiskInit::test() { @@ -767,14 +749,4 @@ int main(int argc, char *argv[]) { // Run the main routine init.start(); - - // Close all file descriptors - for (int i = 0; i < 30; ++i) - close(i); - - // Launch daemon to setup overlay - if (fork_dont_care() == 0) - init.setup_overlay(); - - init.re_exec_init(); } diff --git a/native/jni/core/magisk.cpp b/native/jni/core/magisk.cpp index b2543f6f3..3468728cd 100644 --- a/native/jni/core/magisk.cpp +++ b/native/jni/core/magisk.cpp @@ -71,6 +71,7 @@ int magisk_main(int argc, char *argv[]) { unlock_blocks(); return 0; } else if (strcmp(argv[1], "--restorecon") == 0) { + restore_rootcon(); restorecon(); return 0; } else if (strcmp(argv[1], "--clone-attr") == 0) { diff --git a/native/jni/core/magiskrc.h b/native/jni/core/magiskrc.h index 40c0028c2..f0d7a7554 100644 --- a/native/jni/core/magiskrc.h +++ b/native/jni/core/magiskrc.h @@ -1,15 +1,9 @@ #include #include -static const char magiskrc[] = +constexpr const char magiskrc[] = "\n\n" -"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" diff --git a/native/jni/include/magisk.h b/native/jni/include/magisk.h index fc9bca31b..4ea5557ce 100644 --- a/native/jni/include/magisk.h +++ b/native/jni/include/magisk.h @@ -6,8 +6,6 @@ #define JAVA_PACKAGE_NAME "com.topjohnwu.magisk" #define LOGFILE "/cache/magisk.log" #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 MIRRDIR MAGISKTMP "/mirror" diff --git a/native/jni/magiskhide/hide_utils.cpp b/native/jni/magiskhide/hide_utils.cpp index 4166847c8..b95c40953 100644 --- a/native/jni/magiskhide/hide_utils.cpp +++ b/native/jni/magiskhide/hide_utils.cpp @@ -71,7 +71,7 @@ void crawl_procfs(DIR *dir, const function &fn) { } } -bool proc_name_match(int pid, const char *name) { +static bool proc_name_match(int pid, const char *name) { char buf[4019]; FILE *f; #if 0 diff --git a/native/jni/magiskhide/magiskhide.h b/native/jni/magiskhide/magiskhide.h index 7e0a81e0e..e60ba8a51 100644 --- a/native/jni/magiskhide/magiskhide.h +++ b/native/jni/magiskhide/magiskhide.h @@ -19,8 +19,6 @@ #define SAFETYNET_PKG "com.google.android.gms" #define MICROG_SAFETYNET "org.microg.gms.droidguard" -#define WEVENT(s) (((s) & 0xffff0000) >> 16) - // CLI entries void launch_magiskhide(int client); int stop_magiskhide(); @@ -29,15 +27,14 @@ int rm_list(int client); void ls_list(int client); // Process monitoring -void *update_uid_map(void * p = nullptr); void proc_monitor(); +void update_uid_map(); // Utility functions void manage_selinux(); void clean_magisk_props(); void crawl_procfs(const std::function &fn); void crawl_procfs(DIR *dir, const std::function &fn); -bool proc_name_match(int pid, const char *name); extern bool hide_enabled; extern pthread_mutex_t monitor_lock; diff --git a/native/jni/magiskhide/proc_monitor.cpp b/native/jni/magiskhide/proc_monitor.cpp index be6b47a63..0881112c8 100644 --- a/native/jni/magiskhide/proc_monitor.cpp +++ b/native/jni/magiskhide/proc_monitor.cpp @@ -134,18 +134,21 @@ static bool parse_packages_xml(string_view s) { return true; } +void update_uid_map() { + MutexGuard lock(monitor_lock); + uid_proc_map.clear(); + file_readline("/data/system/packages.xml", parse_packages_xml, true); +} + static void check_zygote() { int min_zyg = 1; if (access("/system/bin/app_process64", R_OK) == 0) min_zyg = 2; - for (bool first = true; zygote_map.size() < min_zyg; first = false) { - if (!first) - usleep(10000); + for (;;) { crawl_procfs([](int pid) -> bool { char buf[512]; snprintf(buf, sizeof(buf), "/proc/%d/cmdline", pid); - FILE *f = fopen(buf, "re"); - if (f) { + if (FILE *f = fopen(buf, "re"); f) { fgets(buf, sizeof(buf), f); if (strncmp(buf, "zygote", 6) == 0 && parse_ppid(pid) == 1) new_zygote(pid); @@ -153,14 +156,41 @@ static void check_zygote() { } return true; }); + if (zygote_map.size() >= min_zyg) + break; + usleep(10000); } } -void *update_uid_map(void*) { - MutexGuard lock(monitor_lock); - uid_proc_map.clear(); - file_readline("/data/system/packages.xml", parse_packages_xml, true); - return nullptr; +#define APP_PROC "/system/bin/app_process" + +static void setup_inotify() { + inotify_fd = xinotify_init1(IN_CLOEXEC); + if (inotify_fd < 0) + term_thread(); + + // Setup inotify asynchronous I/O + fcntl(inotify_fd, F_SETFL, O_ASYNC); + struct f_owner_ex ex = { + .type = F_OWNER_TID, + .pid = gettid() + }; + fcntl(inotify_fd, F_SETOWN_EX, &ex); + + // Monitor packages.xml + inotify_add_watch(inotify_fd, "/data/system", IN_CLOSE_WRITE); + + // Monitor app_process + if (access(APP_PROC "32", F_OK) == 0) { + inotify_add_watch(inotify_fd, APP_PROC "32", IN_ACCESS); + if (access(APP_PROC "64", F_OK) == 0) + inotify_add_watch(inotify_fd, APP_PROC "64", IN_ACCESS); + } else { + inotify_add_watch(inotify_fd, APP_PROC, IN_ACCESS); + } + + // First find existing zygotes + check_zygote(); } /************************* @@ -233,7 +263,10 @@ static void inotify_event(int) { read(inotify_fd, buf, sizeof(buf)); if ((event->mask & IN_CLOSE_WRITE) && strcmp(event->name, "packages.xml") == 0) { LOGD("proc_monitor: /data/system/packages.xml updated\n"); - new_daemon_thread(update_uid_map); + uid_proc_map.clear(); + file_readline("/data/system/packages.xml", parse_packages_xml, true); + } else if (event->mask & IN_ACCESS) { + check_zygote(); } } @@ -362,12 +395,10 @@ static void new_zygote(int pid) { xptrace(PTRACE_CONT, pid); } +#define WEVENT(s) (((s) & 0xffff0000) >> 16) #define DETACH_AND_CONT { detach = true; continue; } -void proc_monitor() { - inotify_fd = xinotify_init1(IN_CLOEXEC); - if (inotify_fd < 0) - term_thread(); +void proc_monitor() { // Unblock some signals sigset_t block_set; sigemptyset(&block_set); @@ -381,19 +412,7 @@ void proc_monitor() { act.sa_handler = inotify_event; sigaction(SIGIO, &act, nullptr); - // Setup inotify asynchronous I/O - fcntl(inotify_fd, F_SETFL, O_ASYNC); - struct f_owner_ex ex = { - .type = F_OWNER_TID, - .pid = gettid() - }; - fcntl(inotify_fd, F_SETOWN_EX, &ex); - - // Start monitoring packages.xml - inotify_add_watch(inotify_fd, "/data/system", IN_CLOSE_WRITE); - - // First find existing zygotes - check_zygote(); + setup_inotify(); int status; diff --git a/native/jni/magiskpolicy/rules.cpp b/native/jni/magiskpolicy/rules.cpp index e9907a104..ee9d96a46 100644 --- a/native/jni/magiskpolicy/rules.cpp +++ b/native/jni/magiskpolicy/rules.cpp @@ -54,6 +54,8 @@ void sepol_magisk_rules() { // Let init run stuffs sepol_allow("kernel", SEPOL_PROC_DOMAIN, "fd", "use"); sepol_allow("init", SEPOL_PROC_DOMAIN, "process", ALL); + sepol_allow("init", "tmpfs", "file", "getattr"); + sepol_allow("init", "tmpfs", "file", "execute"); // Shell, properties, logs if (sepol_exists("default_prop")) diff --git a/native/jni/utils/include/selinux.h b/native/jni/utils/include/selinux.h index 11801d813..21b0a4096 100644 --- a/native/jni/utils/include/selinux.h +++ b/native/jni/utils/include/selinux.h @@ -36,6 +36,7 @@ void setfilecon_at(int dirfd, const char *name, const char *con); void selinux_builtin_impl(); void dload_selinux(); void restorecon(); +void restore_rootcon(); #ifdef __cplusplus } diff --git a/native/jni/utils/selinux.cpp b/native/jni/utils/selinux.cpp index 3ac5484cc..f19600e62 100644 --- a/native/jni/utils/selinux.cpp +++ b/native/jni/utils/selinux.cpp @@ -1,17 +1,21 @@ +#include #include #include #include #include #include -#include +#include #include #include #include +using namespace std::literals; + #define UNLABEL_CON "u:object_r:unlabeled:s0" #define SYSTEM_CON "u:object_r:system_file:s0" #define ADB_CON "u:object_r:adb_data_file:s0" +#define ROOT_CON "u:object_r:rootfs:s0" #define MAGISK_CON "u:object_r:" SEPOL_FILE_DOMAIN ":s0" // Stub implementation @@ -164,7 +168,7 @@ static void restore_syscon(int dirfd) { dir = xfdopendir(dirfd); while ((entry = xreaddir(dir))) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + if (entry->d_name == "."sv || entry->d_name == ".."sv) continue; int fd = openat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); if (entry->d_type == DT_DIR) { @@ -193,7 +197,7 @@ static void restore_magiskcon(int dirfd) { dir = xfdopendir(dirfd); while ((entry = xreaddir(dir))) { - if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + if (entry->d_name == "."sv || entry->d_name == ".."sv) continue; int fd = xopenat(dirfd, entry->d_name, O_RDONLY | O_CLOEXEC); if (entry->d_type == DT_DIR) { @@ -220,3 +224,22 @@ void restorecon() { restore_magiskcon(fd); close(fd); } + +void restore_rootcon() { + setfilecon("/sbin", ROOT_CON); + struct dirent *entry; + DIR *dir = xopendir("/sbin"); + int dfd = dirfd(dir); + + while ((entry = xreaddir(dir))) { + if (entry->d_name == "."sv || entry->d_name == ".."sv) + continue; + setfilecon_at(dfd, entry->d_name, ROOT_CON); + } + + setfilecon("/sbin/magisk.bin", MAGISK_CON); + setfilecon("/sbin/magisk", MAGISK_CON); + setfilecon("/sbin/magiskinit", MAGISK_CON); + + closedir(dir); +}