diff --git a/native/jni/init/early_mount.cpp b/native/jni/init/early_mount.cpp index 020ef7a24..691111c19 100644 --- a/native/jni/init/early_mount.cpp +++ b/native/jni/init/early_mount.cpp @@ -159,8 +159,15 @@ static void switch_root(const string &path) { LOGD("Switch root to %s\n", path.data()); vector mounts; parse_mnt("/proc/mounts", [&](mntent *me) { - if (me->mnt_dir != "/"sv && me->mnt_dir != path) - mounts.emplace_back(me->mnt_dir); + // Skip root and self + if (me->mnt_dir == "/"sv || me->mnt_dir == path) + return true; + // Do not include subtrees + for (const auto &m : mounts) { + if (strncmp(me->mnt_dir, m.data(), m.length()) == 0) + return true; + } + mounts.emplace_back(me->mnt_dir); return true; }); for (auto &dir : mounts) { @@ -202,6 +209,28 @@ void SARInit::early_mount() { mount_root(odm); } +void SecondStageInit::early_mount() { + // Early mounts should already be done by first stage init + + full_read("/system/bin/init", &self.buf, &self.sz); + full_read("/.backup/.magisk", &config.buf, &config.sz); + rm_rf("/system"); + rm_rf("/.backup"); + + // Find system_dev + parse_mnt("/proc/mounts", [&](mntent *me) -> bool { + if (me->mnt_dir == "/system_root"sv) { + struct stat st; + stat(me->mnt_fsname, &st); + system_dev = st.st_rdev; + return false; + } + return true; + }); + + switch_root("/system_root"); +} + #define umount_root(name) \ if (mnt_##name) \ umount("/" #name); diff --git a/native/jni/init/getinfo.cpp b/native/jni/init/getinfo.cpp index 3f9bf2e95..9791e37b4 100644 --- a/native/jni/init/getinfo.cpp +++ b/native/jni/init/getinfo.cpp @@ -112,6 +112,8 @@ void load_kernel_info(cmdline *cmd) { strcpy(cmd->slot + 1, value); } else if (key == "skip_initramfs") { cmd->system_as_root = true; + } else if (key == "androidboot.force_normal_boot") { + cmd->force_normal_boot = value[0] == '1'; } else if (key == "androidboot.android_dt_dir") { strcpy(cmd->dt_dir, value); } else if (key == "enter_recovery") { @@ -147,6 +149,7 @@ void load_kernel_info(cmdline *cmd) { strcpy(cmd->dt_dir, DEFAULT_DT_DIR); LOGD("system_as_root=[%d]\n", cmd->system_as_root); + LOGD("force_normal_boot=[%d]\n", cmd->force_normal_boot); LOGD("slot=[%s]\n", cmd->slot); LOGD("dt_dir=[%s]\n", cmd->dt_dir); } diff --git a/native/jni/init/init.cpp b/native/jni/init/init.cpp index 292c9cd73..629391a64 100644 --- a/native/jni/init/init.cpp +++ b/native/jni/init/init.cpp @@ -141,12 +141,19 @@ void RootFSInit::start() { re_exec_init(); } -void SARInit::start() { +void SARCommon::start() { early_mount(); patch_rootdir(); re_exec_init(); } +void FirstStageInit::start() { + patch_fstab(); + cleanup(); + execv("/system/bin/init", argv); + exit(1); +} + class RecoveryInit : public BaseInit { public: RecoveryInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}; @@ -208,6 +215,11 @@ int main(int argc, char *argv[]) { return dump_manager(argv[3], 0644); } + if (argc > 1 && argv[1] == "selinux_setup"sv) { + auto init = make_unique(argv); + init->start(); + } + #ifdef MAGISK_DEBUG bool run_test = getenv("INIT_TEST") != nullptr; #else @@ -228,6 +240,8 @@ int main(int argc, char *argv[]) { unique_ptr init; if (run_test) { init = make_unique(argv, &cmd); + } else if (cmd.force_normal_boot) { + init = make_unique(argv, &cmd); } else if (cmd.system_as_root) { if (access("/overlay", F_OK) == 0) /* Compatible mode */ init = make_unique(argv, &cmd); @@ -243,4 +257,5 @@ int main(int argc, char *argv[]) { // Run the main routine init->start(); + exit(1); } diff --git a/native/jni/init/init.h b/native/jni/init/init.h index da372d0a0..ea99c5a77 100644 --- a/native/jni/init/init.h +++ b/native/jni/init/init.h @@ -2,6 +2,7 @@ struct cmdline { bool system_as_root; + bool force_normal_boot; char slot[3]; char dt_dir[128]; }; @@ -11,10 +12,15 @@ struct raw_data { size_t sz; }; +/* ************* + * Base classes + * *************/ + class BaseInit { protected: cmdline *cmd; char **argv; + void re_exec_init(); virtual void cleanup(); public: @@ -39,18 +45,6 @@ public: MagiskInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}; }; -class SARInit : public MagiskInit { -protected: - raw_data config{}; - dev_t system_dev; - - void early_mount() override; - void patch_rootdir(); -public: - SARInit(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {}; - void start() override; -}; - class RootFSInit : public MagiskInit { protected: int root = -1; @@ -61,6 +55,52 @@ public: void start() override; }; +class SARCommon : public MagiskInit { +protected: + raw_data config{}; + dev_t system_dev; + + void patch_rootdir(); +public: + SARCommon(char *argv[], cmdline *cmd) : MagiskInit(argv, cmd) {}; + void start() override; +}; + +/* ******************* + * Logical Partitions + * *******************/ + +class FirstStageInit : public BaseInit { +protected: + void patch_fstab(); +public: + FirstStageInit(char *argv[], cmdline *cmd) : BaseInit(argv, cmd) {}; + void start() override; +}; + +class SecondStageInit : public SARCommon { +protected: + void early_mount() override; + void cleanup() override { /* Do not do any cleanup */ } +public: + SecondStageInit(char *argv[]) : SARCommon(argv, nullptr) {}; +}; + +/* *********** + * Normal SAR + * ***********/ + +class SARInit : public SARCommon { +protected: + void early_mount() override; +public: + SARInit(char *argv[], cmdline *cmd) : SARCommon(argv, cmd) {}; +}; + +/* ********** + * Initramfs + * **********/ + class LegacyInit : public RootFSInit { protected: void early_mount() override; @@ -68,6 +108,10 @@ public: LegacyInit(char *argv[], cmdline *cmd) : RootFSInit(argv, cmd) {}; }; +/* **************** + * Compat-mode SAR + * ****************/ + class SARCompatInit : public RootFSInit { protected: void early_mount() override; diff --git a/native/jni/init/rootdir.cpp b/native/jni/init/rootdir.cpp index 074907540..bab70a887 100644 --- a/native/jni/init/rootdir.cpp +++ b/native/jni/init/rootdir.cpp @@ -34,7 +34,7 @@ static void patch_socket_name(const char *path) { } static void patch_init_rc(FILE *rc) { - file_readline("/init.rc", [&](string_view line) -> bool { + file_readline("/init.rc", [=](string_view line) -> bool { // Do not start vaultkeeper if (str_contains(line, "start vaultkeeper")) { LOGD("Remove vaultkeeper\n"); @@ -197,7 +197,7 @@ static void sbin_overlay(const raw_data &self, const raw_data &config) { #define PATCHPOLICY "/sbin/.se" #define LIBSELINUX "/system/" LIBNAME "/libselinux.so" -void SARInit::patch_rootdir() { +void SARCommon::patch_rootdir() { sbin_overlay(self, config); // Mount system_root mirror @@ -300,6 +300,68 @@ void SARInit::patch_rootdir() { xmount(ROOTOVERLAY "/init.rc", "/init.rc", nullptr, MS_BIND, nullptr); } +#define FSR "/first_stage_ramdisk" + +void FirstStageInit::patch_fstab() { + // Find fstab + DIR *dir = xopendir(FSR); + if (!dir) + return; + dirent *de; + string fstab(FSR "/"); + while ((de = readdir(dir))) { + if (strstr(de->d_name, "fstab")) { + fstab += de->d_name; + break; + } + } + closedir(dir); + if (fstab.length() == sizeof(FSR)) + return; + + // Patch fstab + string patched = fstab + ".p"; + FILE *fp = xfopen(patched.data(), "we"); + file_readline(fstab.data(), [=](string_view l) -> bool { + if (l[0] == '#' || l.length() == 1) + return true; + char *line = (char *) l.data(); + int src0, src1, mnt0, mnt1, type0, type1, opt0, opt1, flag0, flag1; + sscanf(line, "%n%*s%n %n%*s%n %n%*s%n %n%*s%n %n%*s%n", + &src0, &src1, &mnt0, &mnt1, &type0, &type1, &opt0, &opt1, &flag0, &flag1); + const char *src, *mnt, *type, *opt, *flag; + src = &line[src0]; + line[src1] = '\0'; + mnt = &line[mnt0]; + line[mnt1] = '\0'; + type = &line[type0]; + line[type1] = '\0'; + opt = &line[opt0]; + line[opt1] = '\0'; + flag = &line[flag0]; + line[flag1] = '\0'; + + // Redirect system to system_root + if (mnt == "/system"sv) + mnt = "/system_root"; + + fprintf(fp, "%s %s %s %s %s\n", src, mnt, type, opt, flag); + return true; + }); + fclose(fp); + + // Replace old fstab + clone_attr(fstab.data(), patched.data()); + rename(patched.data(), fstab.data()); + + // Move stuffs for next stage + xmkdir(FSR "/system", 0755); + xmkdir(FSR "/system/bin", 0755); + rename("/init", FSR "/system/bin/init"); + xmkdir(FSR "/.backup", 0); + rename("/.backup/.magisk", FSR "/.backup/.magisk"); +} + #ifdef MAGISK_DEBUG static FILE *kmsg; static int vprintk(const char *fmt, va_list ap) { diff --git a/scripts/util_functions.sh b/scripts/util_functions.sh index c764dec6e..36523e9c0 100644 --- a/scripts/util_functions.sh +++ b/scripts/util_functions.sh @@ -198,7 +198,8 @@ mount_partitions() { mount --move /system /system_root mount -o bind /system_root/system /system else - grep -qE '/dev/root|/system_root' /proc/mounts && SYSTEM_ROOT=true || SYSTEM_ROOT=false + grep ' / ' /proc/mounts | grep -qv 'rootfs' || grep -q ' /system_root ' /proc/mounts \ + && SYSTEM_ROOT=true || SYSTEM_ROOT=false fi [ -L /system/vendor ] && mount_part vendor $SYSTEM_ROOT && ui_print "- Device is system-as-root"