Merge changes from topic "mount-vendor-in-microdroid" into main

* changes:
  Support for conditionally mounting /vendor partition in Microdroid
  Small refactoring in first_stage_mount
This commit is contained in:
Nikita Ioffe 2023-07-07 15:28:33 +00:00 committed by Gerrit Code Review
commit 230af76757
3 changed files with 115 additions and 95 deletions

View file

@ -257,6 +257,16 @@ static BootMode GetBootMode(const std::string& cmdline, const std::string& bootc
return BootMode::NORMAL_MODE;
}
static std::unique_ptr<FirstStageMount> CreateFirstStageMount(const std::string& cmdline) {
auto ret = FirstStageMount::Create(cmdline);
if (ret.ok()) {
return std::move(*ret);
} else {
LOG(ERROR) << "Failed to create FirstStageMount : " << ret.error();
return nullptr;
}
}
int FirstStageMain(int argc, char** argv) {
if (REBOOT_BOOTLOADER_ON_PANIC) {
InstallRebootSignalHandlers();
@ -381,12 +391,17 @@ int FirstStageMain(int argc, char** argv) {
<< module_elapse_time.count() << " ms";
}
std::unique_ptr<FirstStageMount> fsm;
bool created_devices = false;
if (want_console == FirstStageConsoleParam::CONSOLE_ON_FAILURE) {
if (!IsRecoveryMode()) {
created_devices = DoCreateDevices();
if (!created_devices) {
LOG(ERROR) << "Failed to create device nodes early";
fsm = CreateFirstStageMount(cmdline);
if (fsm) {
created_devices = fsm->DoCreateDevices();
if (!created_devices) {
LOG(ERROR) << "Failed to create device nodes early";
}
}
}
StartConsole(cmdline);
@ -437,8 +452,23 @@ int FirstStageMain(int argc, char** argv) {
SwitchRoot("/first_stage_ramdisk");
}
if (!DoFirstStageMount(!created_devices)) {
LOG(FATAL) << "Failed to mount required partitions early ...";
if (IsRecoveryMode()) {
LOG(INFO) << "First stage mount skipped (recovery mode)";
} else {
if (!fsm) {
fsm = CreateFirstStageMount(cmdline);
}
if (!fsm) {
LOG(FATAL) << "FirstStageMount not available";
}
if (!created_devices && !fsm->DoCreateDevices()) {
LOG(FATAL) << "Failed to create devices required for first stage mount";
}
if (!fsm->DoFirstStageMount()) {
LOG(FATAL) << "Failed to mount required partitions early ...";
}
}
struct stat new_root_info;

View file

@ -76,21 +76,21 @@ namespace init {
// Class Declarations
// ------------------
class FirstStageMount {
class FirstStageMountVBootV2 : public FirstStageMount {
public:
FirstStageMount(Fstab fstab);
virtual ~FirstStageMount() = default;
friend void SetInitAvbVersionInRecovery();
// The factory method to create a FirstStageMountVBootV2 instance.
static Result<std::unique_ptr<FirstStageMount>> Create();
bool DoCreateDevices(); // Creates devices and logical partitions from storage devices
bool DoFirstStageMount(); // Mounts fstab entries read from device tree.
FirstStageMountVBootV2(Fstab fstab);
virtual ~FirstStageMountVBootV2() = default;
bool DoCreateDevices() override;
bool DoFirstStageMount() override;
private:
bool InitDevices();
protected:
bool InitRequiredDevices(std::set<std::string> devices);
bool CreateLogicalPartitions();
bool CreateSnapshotPartitions(android::snapshot::SnapshotManager* sm);
bool CreateSnapshotPartitions(SnapshotManager* sm);
bool MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end = nullptr);
@ -106,9 +106,10 @@ class FirstStageMount {
// revocation check by DSU installation service.
void CopyDsuAvbKeys();
// Pure virtual functions.
virtual bool GetDmVerityDevices(std::set<std::string>* devices) = 0;
virtual bool SetUpDmVerity(FstabEntry* fstab_entry) = 0;
bool GetDmVerityDevices(std::set<std::string>* devices);
bool SetUpDmVerity(FstabEntry* fstab_entry);
bool InitAvbHandle();
bool need_dm_verity_;
bool dsu_not_on_userdata_ = false;
@ -122,19 +123,6 @@ class FirstStageMount {
// Reads all AVB keys before chroot into /system, as they might be used
// later when mounting other partitions, e.g., /vendor and /product.
std::map<std::string, std::vector<std::string>> preload_avb_key_blobs_;
};
class FirstStageMountVBootV2 : public FirstStageMount {
public:
friend void SetInitAvbVersionInRecovery();
FirstStageMountVBootV2(Fstab fstab);
~FirstStageMountVBootV2() override = default;
protected:
bool GetDmVerityDevices(std::set<std::string>* devices) override;
bool SetUpDmVerity(FstabEntry* fstab_entry) override;
bool InitAvbHandle();
std::vector<std::string> vbmeta_partitions_;
AvbUniquePtr avb_handle_;
@ -150,7 +138,7 @@ static inline bool IsDtVbmetaCompatible(const Fstab& fstab) {
return is_android_dt_value_expected("vbmeta/compatible", "android,vbmeta");
}
static Result<Fstab> ReadFirstStageFstab() {
static Result<Fstab> ReadFirstStageFstabAndroid() {
Fstab fstab;
if (!ReadFstabFromDt(&fstab)) {
if (ReadDefaultFstab(&fstab)) {
@ -166,6 +154,24 @@ static Result<Fstab> ReadFirstStageFstab() {
return fstab;
}
// Note: this is a temporary solution to avoid blocking devs that depend on /vendor partition in
// Microdroid. For the proper solution the /vendor fstab should probably be defined in the DT.
// TODO(b/285855430): refactor this
// TODO(b/285855436): verify key microdroid-vendor was signed with.
// TODO(b/285855436): should be mounted on top of dm-verity device.
static Result<Fstab> ReadFirstStageFstabMicrodroid(const std::string& cmdline) {
Fstab fstab;
if (!ReadDefaultFstab(&fstab)) {
return Error() << "failed to read fstab";
}
if (cmdline.find("androidboot.microdroid.mount_vendor=1") == std::string::npos) {
// We weren't asked to mount /vendor partition, filter it out from the fstab.
auto predicate = [](const auto& entry) { return entry.mount_point == "/vendor"; };
fstab.erase(std::remove_if(fstab.begin(), fstab.end(), predicate), fstab.end());
}
return fstab;
}
static bool GetRootEntry(FstabEntry* root_entry) {
Fstab proc_mounts;
if (!ReadFstabFromFile("/proc/mounts", &proc_mounts)) {
@ -218,14 +224,13 @@ static bool IsStandaloneImageRollback(const AvbHandle& builtin_vbmeta,
return rollbacked;
}
// Class Definitions
// -----------------
FirstStageMount::FirstStageMount(Fstab fstab) : need_dm_verity_(false), fstab_(std::move(fstab)) {
super_partition_name_ = fs_mgr_get_super_partition_name();
}
Result<std::unique_ptr<FirstStageMount>> FirstStageMount::Create() {
auto fstab = ReadFirstStageFstab();
Result<std::unique_ptr<FirstStageMount>> FirstStageMount::Create(const std::string& cmdline) {
Result<Fstab> fstab;
if (IsMicrodroid()) {
fstab = ReadFirstStageFstabMicrodroid(cmdline);
} else {
fstab = ReadFirstStageFstabAndroid();
}
if (!fstab.ok()) {
return fstab.error();
}
@ -233,7 +238,7 @@ Result<std::unique_ptr<FirstStageMount>> FirstStageMount::Create() {
return std::make_unique<FirstStageMountVBootV2>(std::move(*fstab));
}
bool FirstStageMount::DoCreateDevices() {
bool FirstStageMountVBootV2::DoCreateDevices() {
if (!InitDevices()) return false;
// Mount /metadata before creating logical partitions, since we need to
@ -255,7 +260,7 @@ bool FirstStageMount::DoCreateDevices() {
return true;
}
bool FirstStageMount::DoFirstStageMount() {
bool FirstStageMountVBootV2::DoFirstStageMount() {
if (!IsDmLinearEnabled() && fstab_.empty()) {
// Nothing to mount.
LOG(INFO) << "First stage mount skipped (missing/incompatible/empty fstab in device tree)";
@ -267,7 +272,7 @@ bool FirstStageMount::DoFirstStageMount() {
return true;
}
bool FirstStageMount::InitDevices() {
bool FirstStageMountVBootV2::InitDevices() {
std::set<std::string> devices;
GetSuperDeviceName(&devices);
@ -288,14 +293,14 @@ bool FirstStageMount::InitDevices() {
return true;
}
bool FirstStageMount::IsDmLinearEnabled() {
bool FirstStageMountVBootV2::IsDmLinearEnabled() {
for (const auto& entry : fstab_) {
if (entry.fs_mgr_flags.logical) return true;
}
return false;
}
void FirstStageMount::GetSuperDeviceName(std::set<std::string>* devices) {
void FirstStageMountVBootV2::GetSuperDeviceName(std::set<std::string>* devices) {
// Add any additional devices required for dm-linear mappings.
if (!IsDmLinearEnabled()) {
return;
@ -307,7 +312,7 @@ void FirstStageMount::GetSuperDeviceName(std::set<std::string>* devices) {
// Creates devices with uevent->partition_name matching ones in the given set.
// Found partitions will then be removed from it for the subsequent member
// function to check which devices are NOT created.
bool FirstStageMount::InitRequiredDevices(std::set<std::string> devices) {
bool FirstStageMountVBootV2::InitRequiredDevices(std::set<std::string> devices) {
if (!block_dev_init_.InitDeviceMapper()) {
return false;
}
@ -317,7 +322,8 @@ bool FirstStageMount::InitRequiredDevices(std::set<std::string> devices) {
return block_dev_init_.InitDevices(std::move(devices));
}
bool FirstStageMount::InitDmLinearBackingDevices(const android::fs_mgr::LpMetadata& metadata) {
bool FirstStageMountVBootV2::InitDmLinearBackingDevices(
const android::fs_mgr::LpMetadata& metadata) {
std::set<std::string> devices;
auto partition_names = android::fs_mgr::GetBlockDevicePartitionNames(metadata);
@ -334,7 +340,7 @@ bool FirstStageMount::InitDmLinearBackingDevices(const android::fs_mgr::LpMetada
return InitRequiredDevices(std::move(devices));
}
bool FirstStageMount::CreateLogicalPartitions() {
bool FirstStageMountVBootV2::CreateLogicalPartitions() {
if (!IsDmLinearEnabled()) {
return true;
}
@ -365,7 +371,7 @@ bool FirstStageMount::CreateLogicalPartitions() {
return android::fs_mgr::CreateLogicalPartitions(*metadata.get(), super_path_);
}
bool FirstStageMount::CreateSnapshotPartitions(SnapshotManager* sm) {
bool FirstStageMountVBootV2::CreateSnapshotPartitions(SnapshotManager* sm) {
// When COW images are present for snapshots, they are stored on
// the data partition.
if (!InitRequiredDevices({"userdata"})) {
@ -400,8 +406,8 @@ bool FirstStageMount::CreateSnapshotPartitions(SnapshotManager* sm) {
return true;
}
bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end) {
bool FirstStageMountVBootV2::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
Fstab::iterator* end) {
// Sets end to begin + 1, so we can just return on failure below.
if (end) {
*end = begin + 1;
@ -445,7 +451,7 @@ bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_sa
return mounted;
}
void FirstStageMount::PreloadAvbKeys() {
void FirstStageMountVBootV2::PreloadAvbKeys() {
for (const auto& entry : fstab_) {
// No need to cache the key content if it's empty, or is already cached.
if (entry.avb_keys.empty() || preload_avb_key_blobs_.count(entry.avb_keys)) {
@ -492,7 +498,7 @@ void FirstStageMount::PreloadAvbKeys() {
// If system is in the fstab then we're not a system-as-root device, and in
// this case, we mount system first then pivot to it. From that point on,
// we are effectively identical to a system-as-root device.
bool FirstStageMount::TrySwitchSystemAsRoot() {
bool FirstStageMountVBootV2::TrySwitchSystemAsRoot() {
UseDsuIfPresent();
// Preloading all AVB keys from the ramdisk before switching root to /system.
PreloadAvbKeys();
@ -521,7 +527,7 @@ bool FirstStageMount::TrySwitchSystemAsRoot() {
return true;
}
bool FirstStageMount::MountPartitions() {
bool FirstStageMountVBootV2::MountPartitions() {
if (!TrySwitchSystemAsRoot()) return false;
if (!SkipMountingPartitions(&fstab_, true /* verbose */)) return false;
@ -604,7 +610,7 @@ bool FirstStageMount::MountPartitions() {
// copy files to /metadata is NOT fatal, because it is auxiliary to perform
// public key matching before booting into DSU images on next boot. The actual
// public key matching will still be done on next boot to DSU.
void FirstStageMount::CopyDsuAvbKeys() {
void FirstStageMountVBootV2::CopyDsuAvbKeys() {
std::error_code ec;
// Removing existing keys in gsi::kDsuAvbKeyDir as they might be stale.
std::filesystem::remove_all(gsi::kDsuAvbKeyDir, ec);
@ -620,7 +626,7 @@ void FirstStageMount::CopyDsuAvbKeys() {
}
}
void FirstStageMount::UseDsuIfPresent() {
void FirstStageMountVBootV2::UseDsuIfPresent() {
std::string error;
if (!android::gsi::CanBootIntoGsi(&error)) {
@ -657,10 +663,10 @@ void FirstStageMount::UseDsuIfPresent() {
TransformFstabForDsu(&fstab_, active_dsu, dsu_partitions);
}
// First retrieve any vbmeta partitions from device tree (legacy) then read through the fstab
// for any further vbmeta partitions.
FirstStageMountVBootV2::FirstStageMountVBootV2(Fstab fstab)
: FirstStageMount(std::move(fstab)), avb_handle_(nullptr) {
: need_dm_verity_(false), fstab_(std::move(fstab)), avb_handle_(nullptr) {
super_partition_name_ = fs_mgr_get_super_partition_name();
std::string device_tree_vbmeta_parts;
read_android_dt_file("vbmeta/parts", &device_tree_vbmeta_parts);
@ -793,46 +799,13 @@ bool FirstStageMountVBootV2::InitAvbHandle() {
return true;
}
// Public functions
// ----------------
// Creates devices and logical partitions from storage devices
bool DoCreateDevices() {
auto fsm = FirstStageMount::Create();
if (!fsm.ok()) {
LOG(ERROR) << "Failed to create FirstStageMount: " << fsm.error();
return false;
}
return (*fsm)->DoCreateDevices();
}
// Mounts partitions specified by fstab in device tree.
bool DoFirstStageMount(bool create_devices) {
// Skips first stage mount if we're in recovery mode.
if (IsRecoveryMode()) {
LOG(INFO) << "First stage mount skipped (recovery mode)";
return true;
}
auto fsm = FirstStageMount::Create();
if (!fsm.ok()) {
LOG(ERROR) << "Failed to create FirstStageMount " << fsm.error();
return false;
}
if (create_devices) {
if (!(*fsm)->DoCreateDevices()) return false;
}
return (*fsm)->DoFirstStageMount();
}
void SetInitAvbVersionInRecovery() {
if (!IsRecoveryMode()) {
LOG(INFO) << "Skipped setting INIT_AVB_VERSION (not in recovery mode)";
return;
}
auto fstab = ReadFirstStageFstab();
auto fstab = ReadFirstStageFstabAndroid();
if (!fstab.ok()) {
LOG(ERROR) << fstab.error();
return;

View file

@ -16,11 +16,28 @@
#pragma once
#include <memory>
#include "result.h"
namespace android {
namespace init {
bool DoCreateDevices();
bool DoFirstStageMount(bool create_devices);
class FirstStageMount {
public:
virtual ~FirstStageMount() = default;
// The factory method to create a FirstStageMount instance.
static Result<std::unique_ptr<FirstStageMount>> Create(const std::string& cmdline);
// Creates devices and logical partitions from storage devices
virtual bool DoCreateDevices() = 0;
// Mounts fstab entries read from device tree.
virtual bool DoFirstStageMount() = 0;
protected:
FirstStageMount() = default;
};
void SetInitAvbVersionInRecovery();
} // namespace init