Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 230af767 authored by Nikita Ioffe's avatar Nikita Ioffe Committed by Gerrit Code Review
Browse files

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
parents 314e7096 440354af
Loading
Loading
Loading
Loading
+35 −5
Original line number Diff line number Diff line
@@ -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,14 +391,19 @@ 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();
            fsm = CreateFirstStageMount(cmdline);
            if (fsm) {
                created_devices = fsm->DoCreateDevices();
                if (!created_devices) {
                    LOG(ERROR) << "Failed to create device nodes early";
                }
            }
        }
        StartConsole(cmdline);
    }

@@ -437,9 +452,24 @@ int FirstStageMain(int argc, char** argv) {
        SwitchRoot("/first_stage_ramdisk");
    }

    if (!DoFirstStageMount(!created_devices)) {
    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;
    if (stat("/", &new_root_info) != 0) {
+61 −88
Original line number Diff line number Diff line
@@ -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.
    bool InitDevices();
    FirstStageMountVBootV2(Fstab fstab);
    virtual ~FirstStageMountVBootV2() = default;

    bool DoCreateDevices() override;
    bool DoFirstStageMount() override;

  protected:
  private:
    bool InitDevices();
    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(const std::string& cmdline) {
    Result<Fstab> fstab;
    if (IsMicrodroid()) {
        fstab = ReadFirstStageFstabMicrodroid(cmdline);
    } else {
        fstab = ReadFirstStageFstabAndroid();
    }

Result<std::unique_ptr<FirstStageMount>> FirstStageMount::Create() {
    auto fstab = ReadFirstStageFstab();
    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,7 +406,7 @@ bool FirstStageMount::CreateSnapshotPartitions(SnapshotManager* sm) {
    return true;
}

bool FirstStageMount::MountPartition(const Fstab::iterator& begin, bool erase_same_mounts,
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) {
@@ -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;
+19 −2
Original line number Diff line number Diff line
@@ -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