Cleanup mount code in magiskinit

This commit is contained in:
topjohnwu 2024-12-02 17:14:38 -08:00
parent 837c679a31
commit c8e9ce7627
4 changed files with 90 additions and 110 deletions

View File

@ -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() {

View File

@ -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();

View File

@ -6,16 +6,19 @@
using kv_pairs = std::vector<std::pair<std::string, std::string>>;
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<std::string> mount_list;
int magisk_proxy_main(int argc, char *argv[]);
bool unxz(out_stream &strm, rust::Slice<const uint8_t> 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__);
};

View File

@ -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");