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
This commit is contained in:
Nikita Ioffe 2024-03-05 00:23:31 +00:00
parent fe7b83faea
commit 1e114e677b
4 changed files with 71 additions and 6 deletions

View file

@ -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,

View file

@ -132,11 +132,19 @@ bool BlockDevInitializer::InitDevices(std::set<std::string> 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;

View file

@ -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<std::string> devices);
bool InitDmDevice(const std::string& device);
bool InitPlatformDevice(const std::string& device);
private:
ListenerAction HandleUevent(const Uevent& uevent, std::set<std::string>* devices);
bool InitMiscDevice(const std::string& name);
bool InitDevice(const std::string& syspath, const std::string& device);
std::unique_ptr<DeviceHandler> device_handler_;
UeventListener uevent_listener_;

View file

@ -16,6 +16,7 @@
#include "first_stage_mount.h"
#include <signal.h>
#include <stdlib.h>
#include <sys/mount.h>
#include <unistd.h>
@ -33,6 +34,7 @@
#include <android-base/logging.h>
#include <android-base/stringprintf.h>
#include <android-base/strings.h>
#include <android/avf_cc_flags.h>
#include <fs_avb/fs_avb.h>
#include <fs_mgr.h>
#include <fs_mgr_dm_linear.h>
@ -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<std::string> 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<std::string> 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<const char*, 7> 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();) {