From 03c8d716cc471d9c65a4332dcd16f1c83b7415e0 Mon Sep 17 00:00:00 2001 From: topjohnwu Date: Sun, 8 Oct 2017 22:00:22 +0800 Subject: [PATCH] Introduce Invincible Mode: Self recover service --- jni/daemon/bootstages.c | 48 ++++++++++++++++++++++++++++---- jni/daemon/daemon.c | 52 ++++++++++++++--------------------- jni/daemon/magisk.c | 9 ++++-- jni/include/daemon.h | 2 +- jni/magiskhide/hide_utils.c | 36 ------------------------ jni/magiskhide/magiskhide.h | 1 - jni/magiskhide/proc_monitor.c | 1 - jni/utils/img.c | 11 ++------ jni/utils/misc.c | 21 +++++--------- scripts/init.magisk.rc | 14 ++++++---- 10 files changed, 88 insertions(+), 107 deletions(-) diff --git a/jni/daemon/bootstages.c b/jni/daemon/bootstages.c index 7bfc40496..03f57026a 100644 --- a/jni/daemon/bootstages.c +++ b/jni/daemon/bootstages.c @@ -399,7 +399,45 @@ static void simple_mount(const char *path) { * Miscellaneous * *****************/ -static void mount_mirrors() { +// A one time setup +void daemon_init() { + LOGI("* Creating /sbin overlay"); + DIR *dir; + struct dirent *entry; + int root, sbin; + char target[PATH_MAX], linkpath[PATH_MAX]; + // Setup links under /sbin + xmount(NULL, "/", NULL, MS_REMOUNT, NULL); + xmkdir("/root", 0755); + xchmod("/root", 0755); + root = xopen("/root", O_RDONLY | O_CLOEXEC); + sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC); + dir = fdopendir(sbin); + while((entry = readdir(dir))) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + linkat(sbin, entry->d_name, root, entry->d_name, 0); + if (strcmp(entry->d_name, "magisk") == 0) + unlinkat(sbin, entry->d_name, 0); + } + close(sbin); + mount("tmpfs", "/sbin", "tmpfs", 0, NULL); + sbin = xopen("/sbin", O_RDONLY | O_CLOEXEC); + fchmod(sbin, 0755); + fsetfilecon(sbin, "u:object_r:rootfs:s0"); + dir = fdopendir(root); + while((entry = readdir(dir))) { + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) continue; + snprintf(target, sizeof(target), "/root/%s", entry->d_name); + snprintf(linkpath, sizeof(linkpath), "/sbin/%s", entry->d_name); + symlink(target, linkpath); + } + for (int i = 0; applet[i]; ++i) { + snprintf(linkpath, sizeof(linkpath), "/sbin/%s", applet[i]); + symlink("/root/magisk", linkpath); + } + xmkdir("/magisk", 0755); + xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL); + LOGI("* Mounting mirrors"); struct vector mounts; vec_init(&mounts); @@ -451,9 +489,8 @@ static void mount_mirrors() { } mkdir_p(MIRRDIR "/bin", 0755); bind_mount(DATABIN, MIRRDIR "/bin"); -} -static void link_busybox() { + LOGI("* Setting up internal busybox"); mkdir_p(BBPATH, 0755); exec_command_sync(MIRRDIR "/bin/busybox", "--install", "-s", BBPATH, NULL); symlink(MIRRDIR "/bin/busybox", BBPATH "/busybox"); @@ -595,9 +632,8 @@ void post_fs_data(int client) { exec_command_sync("sh", "-c", "mv /data/magisk/stock_boot* /data", NULL); } - // Link busybox - mount_mirrors(); - link_busybox(); + // Initialize + daemon_init(); // Merge images if (merge_img("/data/magisk_merge.img", MAINIMG)) { diff --git a/jni/daemon/daemon.c b/jni/daemon/daemon.c index c08a8bd2b..7b10e580b 100644 --- a/jni/daemon/daemon.c +++ b/jni/daemon/daemon.c @@ -114,25 +114,7 @@ static void *large_sepol_patch(void *args) { return NULL; } -void start_daemon(int client) { - // Launch the daemon, create new session, set proper context - if (getuid() != UID_ROOT || getgid() != UID_ROOT) { - fprintf(stderr, "Starting daemon requires root: %s\n", strerror(errno)); - PLOGE("start daemon"); - } - - switch (fork()) { - case -1: - PLOGE("fork"); - case 0: - break; - default: - return; - } - - // First close the client, it's useless for us - close(client); - xsetsid(); +void start_daemon() { setcon("u:r:su:s0"); umask(0); int fd = xopen("/dev/null", O_RDWR | O_CLOEXEC); @@ -166,13 +148,6 @@ void start_daemon(int client) { // Unlock all blocks for rw unlock_blocks(); - // Setup links under /sbin - xmount(NULL, "/", NULL, MS_REMOUNT, NULL); - create_links(NULL, "/sbin"); - xchmod("/sbin", 0755); - xmkdir("/magisk", 0755); - xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL); - // Loop forever to listen for requests while(1) { int *client = xmalloc(sizeof(int)); @@ -189,11 +164,26 @@ int connect_daemon() { struct sockaddr_un sun; int fd = setup_socket(&sun); if (connect(fd, (struct sockaddr*) &sun, sizeof(sun))) { - /* If we cannot access the daemon, we start the daemon - * since there is no clear entry point when the daemon should be started - */ - LOGD("client: connect fail, try launching new daemon process\n"); - start_daemon(fd); + // If we cannot access the daemon, we start a daemon in the child process if possible + + if (getuid() != UID_ROOT || getgid() != UID_ROOT) { + fprintf(stderr, "Starting daemon requires root: %s\n", strerror(errno)); + PLOGE("start daemon"); + } + + switch (fork()) { + case -1: + PLOGE("fork"); + case 0: + LOGD("client: connect fail, try launching new daemon process\n"); + close(fd); + xsetsid(); + start_daemon(); + break; + default: + break; + } + do { // Wait for 10ms usleep(10); diff --git a/jni/daemon/magisk.c b/jni/daemon/magisk.c index 298c196a2..3e27c1de4 100644 --- a/jni/daemon/magisk.c +++ b/jni/daemon/magisk.c @@ -54,11 +54,11 @@ static void usage() { " --resizeimg IMG SIZE resize ext4 image. SIZE is interpreted in MB\n" " --mountimg IMG PATH mount IMG to PATH and prints the loop device\n" " --umountimg PATH LOOP unmount PATH and delete LOOP device\n" - " --[boot stage] start boot stage service\n" + " --[init service] start init service\n" " --unlock-blocks set BLKROSET flag to OFF for all block devices\n" "\n" - "Supported boot stages:\n" - " post-fs, post-fs-data, service\n" + "Supported init services:\n" + " daemon post-fs, post-fs-data, service\n" "\n" "Supported applets:\n" , argv0, argv0); @@ -146,6 +146,9 @@ int main(int argc, char *argv[]) { } else if (strcmp(argv[1], "--unlock-blocks") == 0) { unlock_blocks(); return 0; + } else if (strcmp(argv[1], "--daemon") == 0) { + // Start daemon, this process won't return + start_daemon(); } else if (strcmp(argv[1], "--post-fs") == 0) { int fd = connect_daemon(); write_int(fd, POST_FS); diff --git a/jni/include/daemon.h b/jni/include/daemon.h index 0a72b1c29..b3275d02f 100644 --- a/jni/include/daemon.h +++ b/jni/include/daemon.h @@ -38,7 +38,7 @@ typedef enum { // daemon.c -void start_daemon(int client); +void start_daemon(); int connect_daemon(); // socket_trans.c diff --git a/jni/magiskhide/hide_utils.c b/jni/magiskhide/hide_utils.c index e01896aad..175aa2540 100644 --- a/jni/magiskhide/hide_utils.c +++ b/jni/magiskhide/hide_utils.c @@ -69,42 +69,6 @@ void clean_magisk_props() { getprop_all(rm_magisk_prop); } -void relink_sbin() { - struct stat st; - if (stat("/sbin_orig", &st) == -1 && errno == ENOENT) { - // Re-link all binaries and bind mount - DIR *dir; - struct dirent *entry; - char from[PATH_MAX], to[PATH_MAX]; - - LOGI("hide_utils: Re-linking /sbin\n"); - - xmount(NULL, "/", NULL, MS_REMOUNT, NULL); - xrename("/sbin", "/sbin_orig"); - xmkdir("/sbin", 0755); - xchmod("/sbin", 0755); - xmount(NULL, "/", NULL, MS_REMOUNT | MS_RDONLY, NULL); - xmkdir("/dev/sbin_bind", 0755); - xchmod("/dev/sbin_bind", 0755); - dir = xopendir("/sbin_orig"); - - while ((entry = xreaddir(dir))) { - if (strcmp(entry->d_name, "..") == 0) - continue; - snprintf(from, sizeof(from), "/sbin_orig/%s", entry->d_name); - if (entry->d_type == DT_LNK) - xreadlink(from, from, sizeof(from)); - snprintf(to, sizeof(to), "/dev/sbin_bind/%s", entry->d_name); - symlink(from, to); - lsetfilecon(to, "u:object_r:rootfs:s0"); - } - - closedir(dir); - - xmount("/dev/sbin_bind", "/sbin", NULL, MS_BIND, NULL); - } -} - int add_list(char *proc) { if (!hideEnabled) { free(proc); diff --git a/jni/magiskhide/magiskhide.h b/jni/magiskhide/magiskhide.h index 78858dc80..a5353a37f 100644 --- a/jni/magiskhide/magiskhide.h +++ b/jni/magiskhide/magiskhide.h @@ -12,7 +12,6 @@ void proc_monitor(); // Utility functions void manage_selinux(); void hide_sensitive_props(); -void relink_sbin(); void clean_magisk_props(); // List managements diff --git a/jni/magiskhide/proc_monitor.c b/jni/magiskhide/proc_monitor.c index d41d4bf69..ca3f9833e 100644 --- a/jni/magiskhide/proc_monitor.c +++ b/jni/magiskhide/proc_monitor.c @@ -90,7 +90,6 @@ static void hide_daemon(int pid) { struct vector mount_list; manage_selinux(); - relink_sbin(); clean_magisk_props(); if (switch_mnt_ns(pid)) diff --git a/jni/utils/img.c b/jni/utils/img.c index b38f1187f..5a80781ef 100644 --- a/jni/utils/img.c +++ b/jni/utils/img.c @@ -51,20 +51,13 @@ static char *loopsetup(const char *img) { int create_img(const char *img, int size) { unlink(img); LOGI("Create %s with size %dM\n", img, size); - // Create a temp file with the file contexts - char file_contexts[] = "/magisk(/.*)? u:object_r:system_file:s0\n"; - // If not root, attempt to create in current diretory - char *filename = getuid() == UID_ROOT ? "/dev/file_contexts_image" : "file_contexts_image"; - int ret, fd = xopen(filename, O_WRONLY | O_CREAT | O_TRUNC, 0644); - xwrite(fd, file_contexts, sizeof(file_contexts)); - close(fd); + int ret; char buffer[16]; snprintf(buffer, sizeof(buffer), "%dM", size); - ret = exec_command_sync("make_ext4fs", "-l", buffer, "-a", "/magisk", "-S", filename, img, NULL); + ret = exec_command_sync("make_ext4fs", "-l", buffer, img, NULL); if (ret < 0) return 1; - unlink(filename); return ret; } diff --git a/jni/utils/misc.c b/jni/utils/misc.c index d9a7ecb5f..afe250b2a 100644 --- a/jni/utils/misc.c +++ b/jni/utils/misc.c @@ -167,32 +167,25 @@ void ps_filter_proc_name(const char *pattern, void (*func)(int)) { ps(proc_name_filter); } -#define DEV_BLOCK "/dev/block" - void unlock_blocks() { - char path[PATH_MAX]; DIR *dir; struct dirent *entry; - int fd, OFF = 0; + int fd, dev, OFF = 0; - if (!(dir = xopendir(DEV_BLOCK))) + if ((dev = xopen("/dev/block", O_RDONLY | O_CLOEXEC)) < 0) return; + dir = fdopendir(dev); while((entry = readdir(dir))) { - if (entry->d_type == DT_BLK && - strstr(entry->d_name, "ram") == NULL && - strstr(entry->d_name, "loop") == NULL) { - snprintf(path, sizeof(path), "%s/%s", DEV_BLOCK, entry->d_name); - if ((fd = xopen(path, O_RDONLY)) < 0) + if (entry->d_type == DT_BLK) { + if ((fd = openat(dev, entry->d_name, O_RDONLY)) < 0) continue; - if (ioctl(fd, BLKROSET, &OFF) == -1) - PLOGE("unlock %s", path); + PLOGE("unlock %s", entry->d_name); close(fd); } } - - closedir(dir); + close(dev); } void setup_sighandlers(void (*handler)(int)) { diff --git a/scripts/init.magisk.rc b/scripts/init.magisk.rc index 75cd4b6b2..8252b2e42 100644 --- a/scripts/init.magisk.rc +++ b/scripts/init.magisk.rc @@ -2,20 +2,24 @@ on post-fs start logd + start magisk_daemon + wait /dev/.magisk.unblock 1 start magisk_pfs - wait /dev/.magisk.unblock 20 + wait /dev/.magisk.unblock 5 on post-fs-data rm /dev/.magisk.unblock load_persist_props start magisk_pfsd - wait /dev/.magisk.unblock 60 - -on property:magisk.restart_pfsd=1 - trigger post-fs-data + wait /dev/.magisk.unblock 10 # Services +# Self recoverable service +service magisk_daemon /sbin/magisk --daemon + user root + seclabel u:r:su:s0 + # launch post-fs script service magisk_pfs /sbin/magisk --post-fs user root