diff --git a/native/src/init/getinfo.cpp b/native/src/init/getinfo.cpp index 9ab9ec8d1..8ba5e330a 100644 --- a/native/src/init/getinfo.cpp +++ b/native/src/init/getinfo.cpp @@ -148,6 +148,12 @@ void BootConfig::set(const kv_pairs &kv) { strscpy(fstab_suffix, value.data(), sizeof(fstab_suffix)); } else if (key == "qemu") { emulator = true; + } else if (key == "androidboot.partition_map") { + // androidboot.partition_map allows mapping a partition name to a raw block device. + // For example, "androidboot.partition_map=vdb,metadata;vdc,userdata" maps + // "vdb" to "metadata", and "vdc" to "userdata". + // https://android.googlesource.com/platform/system/core/+/refs/heads/android13-release/init/devices.cpp#191 + partition_map = parse_partition_map(value); } } } @@ -165,41 +171,44 @@ void BootConfig::print() { } #define read_dt(name, key) \ -ssprintf(file_name, sizeof(file_name), "%s/" name, config->dt_dir); \ +ssprintf(file_name, sizeof(file_name), "%s/" name, dt_dir); \ if (access(file_name, R_OK) == 0) { \ string data = full_read(file_name); \ if (!data.empty()) { \ data.pop_back(); \ - strscpy(config->key, data.data(), sizeof(config->key)); \ + strscpy(key, data.data(), sizeof(key)); \ } \ } -void load_kernel_info(BootConfig *config) { +BootConfig::BootConfig() { // Get kernel data using procfs and sysfs - xmkdir("/proc", 0755); - xmount("proc", "/proc", "proc", 0, nullptr); - xmkdir("/sys", 0755); - xmount("sysfs", "/sys", "sysfs", 0, nullptr); - - mount_list.emplace_back("/proc"); - mount_list.emplace_back("/sys"); + 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(); - config->set(parse_cmdline(full_read("/proc/cmdline"))); - config->set(parse_bootconfig(full_read("/proc/bootconfig"))); + set(parse_cmdline(full_read("/proc/cmdline"))); + set(parse_bootconfig(full_read("/proc/bootconfig"))); - parse_prop_file("/.backup/.magisk", [=](auto key, auto value) -> bool { + parse_prop_file("/.backup/.magisk", [&](auto key, auto value) -> bool { if (key == "RECOVERYMODE" && value == "true") { - config->skip_initramfs = config->emulator || !check_key_combo(); + skip_initramfs = emulator || !check_key_combo(); return false; } return true; }); - if (config->dt_dir[0] == '\0') - strscpy(config->dt_dir, DEFAULT_DT_DIR, sizeof(config->dt_dir)); + if (dt_dir[0] == '\0') + strscpy(dt_dir, DEFAULT_DT_DIR, sizeof(dt_dir)); char file_name[128]; read_dt("fstab_suffix", fstab_suffix) @@ -207,26 +216,7 @@ void load_kernel_info(BootConfig *config) { read_dt("hardware.platform", hardware_plat) LOGD("Device config:\n"); - config->print(); -} - -// `androidboot.partition_map` allows associating a partition name for a raw block device -// through a comma separated and semicolon deliminated list. For example, -// `androidboot.partition_map=vdb,metadata;vdc,userdata` maps `vdb` to `metadata` and `vdc` to -// `userdata`. -// https://android.googlesource.com/platform/system/core/+/refs/heads/android13-release/init/devices.cpp#191 - -kv_pairs load_partition_map() { - const string_view kPartitionMapKey = "androidboot.partition_map"; - for (const auto &[key, value] : parse_cmdline(full_read("/proc/cmdline"))) { - if (key == kPartitionMapKey) - return parse_partition_map(value); - } - for (const auto &[key, value] : parse_bootconfig(full_read("/proc/bootconfig"))) { - if (key == kPartitionMapKey) - return parse_partition_map(value); - } - return {}; + print(); } bool check_two_stage() { diff --git a/native/src/init/init.cpp b/native/src/init/init.cpp index c71313325..e8f99d3ac 100644 --- a/native/src/init/init.cpp +++ b/native/src/init/init.cpp @@ -82,26 +82,20 @@ int main(int argc, char *argv[]) { return 1; BaseInit *init; - BootConfig config{}; + BootConfig config; - if (argc > 1 && argv[1] == "selinux_setup"sv) { - rust::setup_klog(); - init = new SecondStageInit(argv); - } else { - // This will also mount /sys and /proc - load_kernel_info(&config); - - 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); - } + 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(); diff --git a/native/src/init/init.hpp b/native/src/init/init.hpp index 912aa5aec..e22d753ab 100644 --- a/native/src/init/init.hpp +++ b/native/src/init/init.hpp @@ -6,16 +6,19 @@ using kv_pairs = std::vector>; struct BootConfig { - 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]; + 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]{}; + kv_pairs partition_map; + BootConfig(); +private: void set(const kv_pairs &); void print(); }; @@ -28,8 +31,6 @@ extern std::vector mount_list; int magisk_proxy_main(int argc, char *argv[]); bool unxz(out_stream &strm, rust::Slice bytes); -void load_kernel_info(BootConfig *config); -kv_pairs load_partition_map(); bool check_two_stage(); const char *backup_init(); void restore_ramdisk_init(); @@ -40,13 +41,15 @@ void restore_ramdisk_init(); class BaseInit { protected: - BootConfig *config = nullptr; - char **argv = nullptr; + 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 = nullptr) : config(config), argv(argv) {} + BaseInit(char *argv[], BootConfig *config) : config(config), argv(argv) {} virtual ~BaseInit() = default; virtual void start() = 0; }; @@ -59,6 +62,7 @@ private: void patch_sepolicy(const char *in, const char *out); bool hijack_sepolicy(); void setup_tmp(const char *path); + void mount_preinit_dir(); protected: void patch_rw_root(); void patch_ro_root(); @@ -87,7 +91,7 @@ class SecondStageInit : public MagiskInit { private: bool prepare(); public: - SecondStageInit(char *argv[]) : MagiskInit(argv) { + SecondStageInit(char *argv[], BootConfig *config) : MagiskInit(argv, config) { LOGD("%s\n", __FUNCTION__); }; diff --git a/native/src/init/mount.cpp b/native/src/init/mount.cpp index a09f7cbec..effdeec22 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) { }); } -static void collect_devices(const auto &partition_map) { +void BaseInit::collect_devices() { char path[PATH_MAX]; devinfo dev{}; if (auto dir = xopen_dir("/sys/dev/block"); dir) { @@ -59,9 +59,9 @@ static void collect_devices(const auto &partition_map) { auto name = rtrim(full_read(path)); strscpy(dev.dmname, name.data(), sizeof(dev.dmname)); } - if (auto it = std::ranges::find_if(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 != 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,52 +72,45 @@ static void collect_devices(const auto &partition_map) { } } -static struct { - char partname[32]; - char block_dev[64]; -} blk_info; - -static dev_t setup_block() { - static const auto partition_map = load_partition_map(); +dev_t BaseInit::find_block(const char *partname) { if (dev_list.empty()) - collect_devices(partition_map); + collect_devices(); for (int tries = 0; tries < 3; ++tries) { for (auto &dev : dev_list) { - if (strcasecmp(dev.partname, blk_info.partname) == 0) - LOGD("Setup %s: [%s] (%d, %d)\n", dev.partname, dev.devname, dev.major, dev.minor); - else if (strcasecmp(dev.dmname, blk_info.partname) == 0) - LOGD("Setup %s: [%s] (%d, %d)\n", dev.dmname, dev.devname, dev.major, dev.minor); - else if (strcasecmp(dev.devname, blk_info.partname) == 0) - LOGD("Setup %s: [%s] (%d, %d)\n", dev.devname, dev.devname, dev.major, dev.minor); - else if (std::string_view(dev.devpath).ends_with("/"s + blk_info.partname)) - LOGD("Setup %s: [%s] (%d, %d)\n", dev.devpath, dev.devname, dev.major, dev.minor); + const char *name; + if (strcasecmp(dev.partname, partname) == 0) + name = dev.partname; + else if (strcasecmp(dev.dmname, partname) == 0) + name = dev.dmname; + else if (strcasecmp(dev.devname, partname) == 0) + name = dev.devname; + else if (std::string_view(dev.devpath).ends_with("/"s + partname)) + name = dev.devpath; else continue; - dev_t rdev = makedev(dev.major, dev.minor); - xmknod(blk_info.block_dev, S_IFBLK | 0600, rdev); - return rdev; + LOGD("Found %s: [%s] (%d, %d)\n", name, dev.devname, dev.major, dev.minor); + return makedev(dev.major, dev.minor); } // Wait 10ms and try again usleep(10000); dev_list.clear(); - collect_devices(partition_map); + collect_devices(); } // The requested partname does not exist return 0; } -static void mount_preinit_dir(string preinit_dev) { +void MagiskInit::mount_preinit_dir() { if (preinit_dev.empty()) return; - strcpy(blk_info.partname, preinit_dev.data()); - strcpy(blk_info.block_dev, PREINITDEV); - auto dev = setup_block(); + auto dev = find_block(preinit_dev.data()); if (dev == 0) { LOGE("Cannot find preinit %s, abort!\n", preinit_dev.data()); return; } + xmknod(PREINITDEV, S_IFBLK | 0600, dev); xmkdir(MIRRDIR, 0); bool mounted = false; // First, find if it is already mounted @@ -156,23 +149,22 @@ bool LegacySARInit::mount_system_root() { // there's no /dev in stub cpio xmkdir("/dev", 0777); - strcpy(blk_info.block_dev, "/dev/root"); - + dev_t dev; do { // Try legacy SAR dm-verity - strcpy(blk_info.partname, "vroot"); - auto dev = setup_block(); + dev = find_block("vroot"); if (dev > 0) goto mount_root; // Try NVIDIA naming scheme - strcpy(blk_info.partname, "APP"); - dev = setup_block(); + dev = find_block("APP"); if (dev > 0) goto mount_root; - sprintf(blk_info.partname, "system%s", config->slot); - dev = setup_block(); + // Try normal partname + char sys_part[32]; + sprintf(sys_part, "system%s", config->slot); + dev = find_block(sys_part); if (dev > 0) goto mount_root; @@ -184,6 +176,7 @@ bool LegacySARInit::mount_system_root() { exit(1); mount_root: + xmknod("/dev/root", S_IFBLK | 0600, dev); xmkdir("/system_root", 0755); if (xmount("/dev/root", "/system_root", "ext4", MS_RDONLY, nullptr)) { @@ -208,11 +201,10 @@ mount_root: if (!is_two_stage && config->emulator) { avd_hack = true; // These values are hardcoded for API 28 AVD + auto vendor_dev = find_block("vendor"); xmkdir("/dev/block", 0755); - strcpy(blk_info.block_dev, "/dev/block/vde1"); - strcpy(blk_info.partname, "vendor"); - setup_block(); - xmount(blk_info.block_dev, "/vendor", "ext4", MS_RDONLY, nullptr); + xmknod("/dev/block/vde1", S_IFBLK | 0600, vendor_dev); + xmount("/dev/block/vde1", "/vendor", "ext4", MS_RDONLY, nullptr); } return is_two_stage; @@ -246,7 +238,7 @@ void MagiskInit::setup_tmp(const char *path) { xmkdir(DEVICEDIR, 0711); xmkdir(WORKERDIR, 0); - mount_preinit_dir(preinit_dev); + mount_preinit_dir(); cp_afc(".backup/.magisk", MAIN_CONFIG); rm_rf(".backup");