diff --git a/native/src/init/getinfo.cpp b/native/src/init/getinfo.cpp index 8ba5e330a..28cd20bae 100644 --- a/native/src/init/getinfo.cpp +++ b/native/src/init/getinfo.cpp @@ -11,8 +11,6 @@ using namespace std; -vector mount_list; - template using chars = integer_sequence; // If quoted, parsing ends when we find char in [breaks] @@ -180,22 +178,7 @@ if (access(file_name, R_OK) == 0) { \ } \ } -BootConfig::BootConfig() { - // Get kernel data using procfs and sysfs - if (access("/proc/cmdline", F_OK) != 0) { - xmkdir("/proc", 0755); - xmount("proc", "/proc", "proc", 0, nullptr); - mount_list.emplace_back("/proc"); - } - if (access("/sys/block", F_OK) != 0) { - xmkdir("/sys", 0755); - xmount("sysfs", "/sys", "sysfs", 0, nullptr); - mount_list.emplace_back("/sys"); - } - - // Log to kernel - rust::setup_klog(); - +void BootConfig::init() { set(parse_cmdline(full_read("/proc/cmdline"))); set(parse_bootconfig(full_read("/proc/bootconfig"))); @@ -234,7 +217,7 @@ bool check_two_stage() { return init.contains("selinux_setup"); } -void unxz_init(const char *init_xz, const char *init) { +static void unxz_init(const char *init_xz, const char *init) { LOGD("unxz %s -> %s\n", init_xz, init); int fd = xopen(init, O_WRONLY | O_CREAT, 0777); fd_stream ch(fd); diff --git a/native/src/init/init.cpp b/native/src/init/init.cpp index e8f99d3ac..055d178e6 100644 --- a/native/src/init/init.cpp +++ b/native/src/init/init.cpp @@ -60,16 +60,67 @@ void restore_ramdisk_init() { } } -class RecoveryInit : public BaseInit { -public: - using BaseInit::BaseInit; - void start() override { - LOGD("Ramdisk is recovery, abort\n"); - restore_ramdisk_init(); - rm_rf("/.backup"); - exec_init(); +MagiskInit::MagiskInit(char **argv) : argv(argv), config{} { + // Get kernel data using procfs and sysfs + if (access("/proc/cmdline", F_OK) != 0) { + xmkdir("/proc", 0755); + xmount("proc", "/proc", "proc", 0, nullptr); + mount_list.emplace_back("/proc"); } -}; + if (access("/sys/block", F_OK) != 0) { + xmkdir("/sys", 0755); + xmount("sysfs", "/sys", "sysfs", 0, nullptr); + mount_list.emplace_back("/sys"); + } + + // Log to kernel + rust::setup_klog(); + + // Load kernel configs + config.init(); +} + +static void recovery() { + LOGI("Ramdisk is recovery, abort\n"); + restore_ramdisk_init(); + rm_rf("/.backup"); +} + +void MagiskInit::legacy_system_as_root() { + LOGI("Legacy SAR Init\n"); + prepare_data(); + bool is_two_stage = mount_system_root(); + if (is_two_stage) + redirect_second_stage(); + else + patch_ro_root(); +} + +void MagiskInit::rootfs() { + LOGI("RootFS Init\n"); + prepare_data(); + LOGD("Restoring /init\n"); + rename(backup_init(), "/init"); + patch_rw_root(); +} + +void MagiskInit::start() { + if (argv[1] != nullptr && argv[1] == "selinux_setup"sv) + second_stage(); + else if (config.skip_initramfs) + legacy_system_as_root(); + else if (config.force_normal_boot) + first_stage(); + else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0) + recovery(); + else if (check_two_stage()) + first_stage(); + else + rootfs(); + + // Finally execute the original init + exec_init(); +} int main(int argc, char *argv[]) { umask(0); @@ -81,23 +132,6 @@ int main(int argc, char *argv[]) { if (getpid() != 1) return 1; - BaseInit *init; - BootConfig config; - - if (argc > 1 && argv[1] == "selinux_setup"sv) - init = new SecondStageInit(argv, &config); - else if (config.skip_initramfs) - init = new LegacySARInit(argv, &config); - else if (config.force_normal_boot) - init = new FirstStageInit(argv, &config); - else if (access("/sbin/recovery", F_OK) == 0 || access("/system/bin/recovery", F_OK) == 0) - init = new RecoveryInit(argv, &config); - else if (check_two_stage()) - init = new FirstStageInit(argv, &config); - else - init = new RootFSInit(argv, &config); - - // Run the main routine - init->start(); - exit(1); + MagiskInit init(argv); + init.start(); } diff --git a/native/src/init/init.hpp b/native/src/init/init.hpp index e22d753ab..c2cd3a097 100644 --- a/native/src/init/init.hpp +++ b/native/src/init/init.hpp @@ -6,18 +6,18 @@ using kv_pairs = std::vector>; struct BootConfig { - bool skip_initramfs = false; - bool force_normal_boot = false; - bool rootwait = false; - bool emulator = false; - char slot[3]{}; - char dt_dir[64]{}; - char fstab_suffix[32]{}; - char hardware[32]{}; - char hardware_plat[32]{}; + bool skip_initramfs; + bool force_normal_boot; + bool rootwait; + bool emulator; + char slot[3]; + char dt_dir[64]; + char fstab_suffix[32]; + char hardware[32]; + char hardware_plat[32]; kv_pairs partition_map; - BootConfig(); + void init(); private: void set(const kv_pairs &); void print(); @@ -27,121 +27,45 @@ private: #define INIT_PATH "/system/bin/init" #define REDIR_PATH "/data/magiskinit" -extern std::vector mount_list; - int magisk_proxy_main(int argc, char *argv[]); bool unxz(out_stream &strm, rust::Slice bytes); bool check_two_stage(); const char *backup_init(); void restore_ramdisk_init(); -/*************** - * Base classes - ***************/ - -class BaseInit { -protected: - BootConfig *config; - char **argv; - - [[noreturn]] void exec_init(); - void prepare_data(); - dev_t find_block(const char *partname); - void collect_devices(); -public: - BaseInit(char *argv[], BootConfig *config) : config(config), argv(argv) {} - virtual ~BaseInit() = default; - virtual void start() = 0; -}; - -class MagiskInit : public BaseInit { +class MagiskInit { private: std::string preinit_dev; + std::vector mount_list; + char **argv; + BootConfig config; - void parse_config_file(); - void patch_sepolicy(const char *in, const char *out); - bool hijack_sepolicy(); + // Setup mounts and environment void setup_tmp(const char *path); + void collect_devices(); void mount_preinit_dir(); -protected: + void prepare_data(); + dev_t find_block(const char *partname); + bool mount_system_root(); + + // Setup and patch root directory + void parse_config_file(); void patch_rw_root(); void patch_ro_root(); + + // Two stage init + void redirect_second_stage(); + void first_stage(); + void second_stage(); + + // SELinux + void patch_sepolicy(const char *in, const char *out); + bool hijack_sepolicy(); + + [[noreturn]] void exec_init(); + void legacy_system_as_root(); + void rootfs(); public: - using BaseInit::BaseInit; -}; - -/*************** - * 2 Stage Init - ***************/ - -class FirstStageInit : public BaseInit { -private: - void prepare(); -public: - FirstStageInit(char *argv[], BootConfig *config) : BaseInit(argv, config) { - LOGD("%s\n", __FUNCTION__); - }; - void start() override { - prepare(); - exec_init(); - } -}; - -class SecondStageInit : public MagiskInit { -private: - bool prepare(); -public: - SecondStageInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) { - LOGD("%s\n", __FUNCTION__); - }; - - void start() override { - bool is_rootfs = prepare(); - if (is_rootfs) - patch_rw_root(); - else - patch_ro_root(); - exec_init(); - } -}; - -/************* - * Legacy SAR - *************/ - -class LegacySARInit : public MagiskInit { -private: - bool mount_system_root(); - void first_stage_prep(); -public: - LegacySARInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) { - LOGD("%s\n", __FUNCTION__); - }; - void start() override { - prepare_data(); - bool is_two_stage = mount_system_root(); - if (is_two_stage) - first_stage_prep(); - else - patch_ro_root(); - exec_init(); - } -}; - -/************ - * Initramfs - ************/ - -class RootFSInit : public MagiskInit { -private: - void prepare(); -public: - RootFSInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) { - LOGD("%s\n", __FUNCTION__); - } - void start() override { - prepare(); - patch_rw_root(); - exec_init(); - } + explicit MagiskInit(char *argv[]); + void start(); }; diff --git a/native/src/init/mount.cpp b/native/src/init/mount.cpp index effdeec22..084cd5a55 100644 --- a/native/src/init/mount.cpp +++ b/native/src/init/mount.cpp @@ -45,7 +45,7 @@ static void parse_device(devinfo *dev, const char *uevent) { }); } -void BaseInit::collect_devices() { +void MagiskInit::collect_devices() { char path[PATH_MAX]; devinfo dev{}; if (auto dir = xopen_dir("/sys/dev/block"); dir) { @@ -59,9 +59,9 @@ void BaseInit::collect_devices() { auto name = rtrim(full_read(path)); strscpy(dev.dmname, name.data(), sizeof(dev.dmname)); } - if (auto it = std::ranges::find_if(config->partition_map, [&](const auto &i) { + if (auto it = std::ranges::find_if(config.partition_map, [&](const auto &i) { return i.first == dev.devname; - }); dev.partname[0] == '\0' && it != config->partition_map.end()) { + }); dev.partname[0] == '\0' && it != config.partition_map.end()) { // use androidboot.partition_map as partname fallback. strscpy(dev.partname, it->second.data(), sizeof(dev.partname)); } @@ -72,7 +72,7 @@ void BaseInit::collect_devices() { } } -dev_t BaseInit::find_block(const char *partname) { +dev_t MagiskInit::find_block(const char *partname) { if (dev_list.empty()) collect_devices(); @@ -143,7 +143,7 @@ void MagiskInit::mount_preinit_dir() { } } -bool LegacySARInit::mount_system_root() { +bool MagiskInit::mount_system_root() { LOGD("Mounting system_root\n"); // there's no /dev in stub cpio @@ -163,13 +163,13 @@ bool LegacySARInit::mount_system_root() { // Try normal partname char sys_part[32]; - sprintf(sys_part, "system%s", config->slot); + sprintf(sys_part, "system%s", config.slot); dev = find_block(sys_part); if (dev > 0) goto mount_root; // Poll forever if rootwait was given in cmdline - } while (config->rootwait); + } while (config.rootwait); // We don't really know what to do at this point... LOGE("Cannot find root partition, abort\n"); @@ -198,7 +198,7 @@ mount_root: // For API 28 AVD, it uses legacy SAR setup that requires // special hacks in magiskinit to work properly. - if (!is_two_stage && config->emulator) { + if (!is_two_stage && config.emulator) { avd_hack = true; // These values are hardcoded for API 28 AVD auto vendor_dev = find_block("vendor"); @@ -210,7 +210,7 @@ mount_root: return is_two_stage; } -void BaseInit::exec_init() { +void MagiskInit::exec_init() { // Unmount in reverse order for (auto &p : reversed(mount_list)) { if (xumount2(p.data(), MNT_DETACH) == 0) @@ -220,12 +220,12 @@ void BaseInit::exec_init() { exit(1); } -void BaseInit::prepare_data() { +void MagiskInit::prepare_data() { LOGD("Setup data tmp\n"); xmkdir("/data", 0755); xmount("magisk", "/data", "tmpfs", 0, "mode=755"); - cp_afc("/init", "/data/magiskinit"); + cp_afc("/init", REDIR_PATH); cp_afc("/.backup", "/data/.backup"); cp_afc("/overlay.d", "/data/overlay.d"); } diff --git a/native/src/init/rootdir.cpp b/native/src/init/rootdir.cpp index 2f7ff0b30..a640de3d3 100644 --- a/native/src/init/rootdir.cpp +++ b/native/src/init/rootdir.cpp @@ -347,12 +347,6 @@ void MagiskInit::patch_ro_root() { chdir("/"); } -void RootFSInit::prepare() { - prepare_data(); - LOGD("Restoring /init\n"); - rename(backup_init(), "/init"); -} - #define PRE_TMPSRC "/magisk" #define PRE_TMPDIR PRE_TMPSRC "/tmp" diff --git a/native/src/init/selinux.cpp b/native/src/init/selinux.cpp index 740b6253f..5b0088d22 100644 --- a/native/src/init/selinux.cpp +++ b/native/src/init/selinux.cpp @@ -64,7 +64,7 @@ bool MagiskInit::hijack_sepolicy() { // This only happens on Android 8.0 - 9.0 char buf[4096]; - ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config->dt_dir); + ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config.dt_dir); dt_compat = full_read(buf); if (dt_compat.empty()) { // Device does not do early mount and uses monolithic policy @@ -106,7 +106,7 @@ bool MagiskInit::hijack_sepolicy() { int fd = xopen(MOCK_COMPAT, O_WRONLY); char buf[4096]; - ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config->dt_dir); + ssprintf(buf, sizeof(buf), "%s/fstab/compatible", config.dt_dir); xumount2(buf, MNT_DETACH); hijack(); diff --git a/native/src/init/twostage.cpp b/native/src/init/twostage.cpp index 41ebbef3f..c9076cd4e 100644 --- a/native/src/init/twostage.cpp +++ b/native/src/init/twostage.cpp @@ -8,12 +8,13 @@ using namespace std; -void FirstStageInit::prepare() { +void MagiskInit::first_stage() { + LOGI("First Stage Init\n"); prepare_data(); 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) { + 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"); @@ -29,8 +30,8 @@ void FirstStageInit::prepare() { 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"); + xmount(REDIR_PATH, "/sdcard", nullptr, MS_BIND, nullptr); + LOGD("Bind mount " REDIR_PATH " -> /sdcard\n"); } restore_ramdisk_init(); } else { @@ -44,7 +45,7 @@ void FirstStageInit::prepare() { } } -void LegacySARInit::first_stage_prep() { +void MagiskInit::redirect_second_stage() { // Patch init binary int src = xopen("/init", O_RDONLY); int dest = xopen("/data/init", O_CREAT | O_WRONLY, 0); @@ -61,7 +62,8 @@ void LegacySARInit::first_stage_prep() { xmount("/data/init", "/init", nullptr, MS_BIND, nullptr); } -bool SecondStageInit::prepare() { +void MagiskInit::second_stage() { + LOGI("Second Stage Init\n"); umount2("/init", MNT_DETACH); umount2(INIT_PATH, MNT_DETACH); // just in case unlink("/data/init"); @@ -76,7 +78,8 @@ bool SecondStageInit::prepare() { // We are still on rootfs, so make sure we will execute the init of the 2nd stage unlink("/init"); xsymlink(INIT_PATH, "/init"); - return true; + patch_rw_root(); + } else { + patch_ro_root(); } - return false; }