From 1e114e677b7196c0b48502f5f53fa32ae76a8a0a Mon Sep 17 00:00:00 2001 From: Nikita Ioffe Date: Tue, 5 Mar 2024 00:23:31 +0000 Subject: [PATCH] Add a step to derive microdroid vendor dice node The derivation happens in the derive_microdroid_vendor_dice_node binary which first_stage_init forks and execvs. Since the derivation requires talking to the dice driver, its initialisation is also moved to the first stage init. The derivation happens before the microdroid vendor partition is verified & mounted. This should be safe because the first_stage_init will fail the boot if the verification of the microdroid vendor partition fails. Bug: 287593065 Test: run microdroid with and without vendor partition Test: atest MicrodroidTests Change-Id: I0d83772eb98a56c315617e66ec64bd03639cfde6 --- init/Android.bp | 2 +- init/block_dev_initializer.cpp | 18 ++++++++---- init/block_dev_initializer.h | 3 ++ init/first_stage_mount.cpp | 54 ++++++++++++++++++++++++++++++++++ 4 files changed, 71 insertions(+), 6 deletions(-) diff --git a/init/Android.bp b/init/Android.bp index 419948454..12ca15ae3 100644 --- a/init/Android.bp +++ b/init/Android.bp @@ -463,7 +463,7 @@ cc_binary { name: "init_first_stage.microdroid", defaults: [ "avf_build_flags_cc", - "init_first_stage_defaults" + "init_first_stage_defaults", ], cflags: ["-DMICRODROID=1"], installable: false, diff --git a/init/block_dev_initializer.cpp b/init/block_dev_initializer.cpp index 05e00edfd..a686d0513 100644 --- a/init/block_dev_initializer.cpp +++ b/init/block_dev_initializer.cpp @@ -132,11 +132,19 @@ bool BlockDevInitializer::InitDevices(std::set devices) { bool BlockDevInitializer::InitDmDevice(const std::string& device) { const std::string device_name(basename(device.c_str())); const std::string syspath = "/sys/block/" + device_name; + return InitDevice(syspath, device_name); +} + +bool BlockDevInitializer::InitPlatformDevice(const std::string& dev_name) { + return InitDevice("/sys/devices/platform", dev_name); +} + +bool BlockDevInitializer::InitDevice(const std::string& syspath, const std::string& device_name) { bool found = false; - auto uevent_callback = [&device_name, &device, this, &found](const Uevent& uevent) { + auto uevent_callback = [&device_name, this, &found](const Uevent& uevent) { if (uevent.device_name == device_name) { - LOG(VERBOSE) << "Creating device-mapper device : " << device; + LOG(VERBOSE) << "Creating device : " << device_name; device_handler_->HandleUevent(uevent); found = true; return ListenerAction::kStop; @@ -146,13 +154,13 @@ bool BlockDevInitializer::InitDmDevice(const std::string& device) { uevent_listener_.RegenerateUeventsForPath(syspath, uevent_callback); if (!found) { - LOG(INFO) << "dm device '" << device << "' not found in /sys, waiting for its uevent"; + LOG(INFO) << "device '" << device_name << "' not found in /sys, waiting for its uevent"; Timer t; uevent_listener_.Poll(uevent_callback, 10s); - LOG(INFO) << "wait for dm device '" << device << "' returned after " << t; + LOG(INFO) << "wait for device '" << device_name << "' returned after " << t; } if (!found) { - LOG(ERROR) << "dm device '" << device << "' not found after polling timeout"; + LOG(ERROR) << "device '" << device_name << "' not found after polling timeout"; return false; } return true; diff --git a/init/block_dev_initializer.h b/init/block_dev_initializer.h index ec39ce084..d5b1f6006 100644 --- a/init/block_dev_initializer.h +++ b/init/block_dev_initializer.h @@ -24,6 +24,7 @@ namespace android { namespace init { +// TODO: should this be renamed to FirstStageDevInitialize? class BlockDevInitializer final { public: BlockDevInitializer(); @@ -32,11 +33,13 @@ class BlockDevInitializer final { bool InitDmUser(const std::string& name); bool InitDevices(std::set devices); bool InitDmDevice(const std::string& device); + bool InitPlatformDevice(const std::string& device); private: ListenerAction HandleUevent(const Uevent& uevent, std::set* devices); bool InitMiscDevice(const std::string& name); + bool InitDevice(const std::string& syspath, const std::string& device); std::unique_ptr device_handler_; UeventListener uevent_listener_; diff --git a/init/first_stage_mount.cpp b/init/first_stage_mount.cpp index c0b928139..836d536c9 100644 --- a/init/first_stage_mount.cpp +++ b/init/first_stage_mount.cpp @@ -16,6 +16,7 @@ #include "first_stage_mount.h" +#include #include #include #include @@ -33,6 +34,7 @@ #include #include #include +#include #include #include #include @@ -272,6 +274,11 @@ bool FirstStageMountVBootV2::DoFirstStageMount() { return true; } +// TODO: should this be in a library in packages/modules/Virtualization first_stage_init links? +static bool IsMicrodroidStrictBoot() { + return access("/proc/device-tree/chosen/avf,strict-boot", F_OK) == 0; +} + bool FirstStageMountVBootV2::InitDevices() { std::set devices; GetSuperDeviceName(&devices); @@ -283,6 +290,14 @@ bool FirstStageMountVBootV2::InitDevices() { return false; } + if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) { + if (IsMicrodroidStrictBoot()) { + if (!block_dev_init_.InitPlatformDevice("open-dice0")) { + return false; + } + } + } + if (IsDmLinearEnabled()) { auto super_symlink = "/dev/block/by-name/"s + super_partition_name_; if (!android::base::Realpath(super_symlink, &super_path_)) { @@ -527,9 +542,48 @@ bool FirstStageMountVBootV2::TrySwitchSystemAsRoot() { return true; } +static bool MaybeDeriveMicrodroidVendorDiceNode(Fstab* fstab) { + std::optional microdroid_vendor_block_dev; + for (auto entry = fstab->begin(); entry != fstab->end(); entry++) { + if (entry->mount_point == "/vendor") { + microdroid_vendor_block_dev.emplace(entry->blk_device); + break; + } + } + if (!microdroid_vendor_block_dev.has_value()) { + LOG(VERBOSE) << "No microdroid vendor partition to mount"; + return true; + } + // clang-format off + const std::array args = { + "/system/bin/derive_microdroid_vendor_dice_node", + "--dice-driver", "/dev/open-dice0", + "--microdroid-vendor-disk-image", microdroid_vendor_block_dev->data(), + "--output", "/microdroid_resources/dice_chain.raw", + }; + // clang-format-on + // ForkExecveAndWaitForCompletion calls waitpid to wait for the fork-ed process to finish. + // The first_stage_console adds SA_NOCLDWAIT flag to the SIGCHLD handler, which means that + // waitpid will always return -ECHLD. Here we re-register a default handler, so that waitpid + // works. + LOG(INFO) << "Deriving dice node for microdroid vendor partition"; + signal(SIGCHLD, SIG_DFL); + if (!ForkExecveAndWaitForCompletion(args[0], (char**)args.data())) { + LOG(ERROR) << "Failed to derive microdroid vendor dice node"; + return false; + } + return true; +} + bool FirstStageMountVBootV2::MountPartitions() { if (!TrySwitchSystemAsRoot()) return false; + if (IsMicrodroid() && android::virtualization::IsOpenDiceChangesFlagEnabled()) { + if (!MaybeDeriveMicrodroidVendorDiceNode(&fstab_)) { + return false; + } + } + if (!SkipMountingPartitions(&fstab_, true /* verbose */)) return false; for (auto current = fstab_.begin(); current != fstab_.end();) {