From a8c2ae223aa6b08efa7b6e4f0da847b5db13e969 Mon Sep 17 00:00:00 2001 From: LoveSy Date: Sat, 30 Dec 2023 12:56:46 +0800 Subject: [PATCH] Avoid hexpatch /init for 2SI when possible Previous we hexpatch /init from /system/bin/init to /data/magiskinit to redirect the second stage init. However, some devices like sony has /init that does not directly invoke /system/bin/init, and thus the hexpatch fails. In this patch, we further make use of AOSP `SwitchRoot` to help us bind mount /data/magisk to /system/bin/init after `SwitchRoot`. Two important assumption about 2SI are i) that the second stage init is always /system/bin/init and ii) that the /sdcard (path after `SwitchRoot`) is always a symlink to `/storage/self/primary`. When these assumptions hold, during first stage init (before `SwitchRoot`) we can bind mount magiskinit to /sdcard, and create a symlink /storage/self/primary to /system/system/bin/init. By these steps, during `SwitchRoot`, AOSP init will try to mount move /sdcard to /system/sdcard. And /system/sdcard is symlink to /storage/self/primary, it will try to mount move /sdcard to /storage/self/primary. And /storage/self/primary in ramfs is now a symlink that points to /system/system/bin/init, thus AOSP will try to mount move /sdcard (which is a bind mount to magiskinit) to /system/system/bin/init. After chroot done by AOSP init, we then have a magiskinit bind mount on /system/bin/init, which is the second stage init. An edge case is that some devices (like meizu) use 2SI but does not switch root. In this case, they must already have a /sdcard in the ramfs, thus we can check if /sdcard exists and fallback to hexpatch. --- native/src/init/twostage.cpp | 37 +++++++++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 5 deletions(-) diff --git a/native/src/init/twostage.cpp b/native/src/init/twostage.cpp index 50fc348ac..41ebbef3f 100644 --- a/native/src/init/twostage.cpp +++ b/native/src/init/twostage.cpp @@ -10,11 +10,37 @@ using namespace std; void FirstStageInit::prepare() { prepare_data(); - restore_ramdisk_init(); - auto init = mmap_data("/init", true); - // Redirect original init to magiskinit - for (size_t off : init.patch(INIT_PATH, REDIR_PATH)) { - LOGD("Patch @ %08zX [" INIT_PATH "] -> [" REDIR_PATH "]\n", off); + + if (struct stat st{}; fstatat(-1, "/sdcard", &st, AT_SYMLINK_NOFOLLOW) != 0 && + fstatat(-1, "/first_stage_ramdisk/sdcard", &st, AT_SYMLINK_NOFOLLOW) != 0) { + if (config->force_normal_boot) { + xmkdirs("/first_stage_ramdisk/storage/self", 0755); + xsymlink("/system/system/bin/init", "/first_stage_ramdisk/storage/self/primary"); + LOGD("Symlink /first_stage_ramdisk/storage/self/primary -> /system/system/bin/init\n"); + close(xopen("/first_stage_ramdisk/sdcard", O_RDONLY | O_CREAT | O_CLOEXEC, 0)); + } else { + xmkdirs("/storage/self", 0755); + xsymlink("/system/system/bin/init", "/storage/self/primary"); + LOGD("Symlink /storage/self/primary -> /system/system/bin/init\n"); + } + xrename("/init", "/sdcard"); + // Try to keep magiskinit in rootfs for samsung RKP + if (mount("/sdcard", "/sdcard", nullptr, MS_BIND, nullptr) == 0) { + LOGD("Bind mount /sdcard -> /sdcard\n"); + } else { + // rootfs before 3.12 + xmount("/data/magiskinit", "/sdcard", nullptr, MS_BIND, nullptr); + LOGD("Bind mount /sdcard -> /data/magiskinit\n"); + } + restore_ramdisk_init(); + } else { + restore_ramdisk_init(); + // fallback to hexpatch if /sdcard exists + auto init = mmap_data("/init", true); + // Redirect original init to magiskinit + for (size_t off : init.patch(INIT_PATH, REDIR_PATH)) { + LOGD("Patch @ %08zX [" INIT_PATH "] -> [" REDIR_PATH "]\n", off); + } } } @@ -37,6 +63,7 @@ void LegacySARInit::first_stage_prep() { bool SecondStageInit::prepare() { umount2("/init", MNT_DETACH); + umount2(INIT_PATH, MNT_DETACH); // just in case unlink("/data/init"); // Make sure init dmesg logs won't get messed up