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.
This commit is contained in:
LoveSy 2023-12-30 12:56:46 +08:00 committed by John Wu
parent 953d44302c
commit a8c2ae223a

View File

@ -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