From 1f8c063dc64806c4f7320ed66c785ff7bc116383 Mon Sep 17 00:00:00 2001 From: Andrew Gunnerson Date: Sat, 25 Jun 2022 19:27:37 -0400 Subject: [PATCH] Fix booting into recovery with Android 13 GKI kernels With Android 13 GKI kernels, the boot partition has no ramdisk, so Magisk constructs one from scratch. In this scenario, there's no backup init binary at /.backup/init. For normal boot, magiskinit will symlink /init -> /system/bin/init if needed. This commit implements the same for booting into recovery. Before, magiskinit would just exec itself over and over again because it couldn't restore the backup init. Signed-off-by: Andrew Gunnerson --- native/jni/init/init.cpp | 16 +++++++++++++++- native/jni/init/init.hpp | 2 ++ native/jni/init/twostage.cpp | 12 +----------- 3 files changed, 18 insertions(+), 12 deletions(-) diff --git a/native/jni/init/init.cpp b/native/jni/init/init.cpp index c81d3dbd6..977e9c1da 100644 --- a/native/jni/init/init.cpp +++ b/native/jni/init/init.cpp @@ -59,6 +59,20 @@ static int dump_bin(const uint8_t *buf, size_t sz, const char *path, mode_t mode return 0; } +void restore_ramdisk_init() { + unlink("/init"); + + const char *orig_init = backup_init(); + if (access(orig_init, F_OK) == 0) { + xrename(orig_init, "/init"); + } else { + // If the backup init is missing, this means that the boot ramdisk + // was created from scratch, and the real init is in a separate CPIO, + // which is guaranteed to be placed at /system/bin/init. + xsymlink(INIT_PATH, "/init"); + } +} + int dump_manager(const char *path, mode_t mode) { return dump_bin(manager_xz, sizeof(manager_xz), path, mode); } @@ -72,7 +86,7 @@ public: using BaseInit::BaseInit; void start() override { LOGD("Ramdisk is recovery, abort\n"); - rename(backup_init(), "/init"); + restore_ramdisk_init(); rm_rf("/.backup"); exec_init(); } diff --git a/native/jni/init/init.hpp b/native/jni/init/init.hpp index 519ca4272..b6cbbd965 100644 --- a/native/jni/init/init.hpp +++ b/native/jni/init/init.hpp @@ -24,6 +24,7 @@ struct BootConfig { }; #define DEFAULT_DT_DIR "/proc/device-tree/firmware/android" +#define INIT_PATH "/system/bin/init" extern std::vector mount_list; @@ -33,6 +34,7 @@ void load_kernel_info(BootConfig *config); bool check_two_stage(); void setup_klog(); const char *backup_init(); +void restore_ramdisk_init(); int dump_manager(const char *path, mode_t mode); int dump_preload(const char *path, mode_t mode); diff --git a/native/jni/init/twostage.cpp b/native/jni/init/twostage.cpp index 5f7de268b..d9febb275 100644 --- a/native/jni/init/twostage.cpp +++ b/native/jni/init/twostage.cpp @@ -8,7 +8,6 @@ using namespace std; -#define INIT_PATH "/system/bin/init" #define REDIR_PATH "/data/magiskinit" void FirstStageInit::prepare() { @@ -16,16 +15,7 @@ void FirstStageInit::prepare() { xmount("tmpfs", "/data", "tmpfs", 0, "mode=755"); cp_afc("/init" /* magiskinit */, REDIR_PATH); - unlink("/init"); - const char *orig_init = backup_init(); - if (access(orig_init, F_OK) == 0) { - xrename(orig_init, "/init"); - } else { - // If the backup init is missing, this means that the boot ramdisk - // was created from scratch, and the real init is in a separate CPIO, - // which is guaranteed to be placed at /system/bin/init. - xsymlink(INIT_PATH, "/init"); - } + restore_ramdisk_init(); { auto init = mmap_data("/init", true);