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

Commit 7632f0c2 authored by David Anderson's avatar David Anderson
Browse files

liblp: Fix flashing metadata to multiple block devices.

Although metadata is only stored on the first block device, we ideally
want to validate all the block devices before flashing. This patch does
that and in the process converts ValidateAndSerializeMetadata to use
IPartitionOpener.

Bug: 116802789
Test: manual test
      liblp_test gtest

Change-Id: I3f24cfc6f5607309dc3cded0423326c5ba293d26
parent e0c3a8d9
Loading
Loading
Loading
Loading
+25 −17
Original line number Diff line number Diff line
@@ -82,12 +82,8 @@ std::string SerializeMetadata(const LpMetadata& input) {

// Perform sanity checks so we don't accidentally overwrite valid metadata
// with potentially invalid metadata, or random partition data with metadata.
static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std::string* blob) {
    uint64_t blockdevice_size;
    if (!GetDescriptorSize(fd, &blockdevice_size)) {
        return false;
    }

static bool ValidateAndSerializeMetadata(const IPartitionOpener& opener, const LpMetadata& metadata,
                                         std::string* blob) {
    const LpMetadataHeader& header = metadata.header;
    const LpMetadataGeometry& geometry = metadata.geometry;

@@ -104,7 +100,7 @@ static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std
    // metadata.
    uint64_t reserved_size = LP_METADATA_GEOMETRY_SIZE +
                             uint64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
    uint64_t total_reserved = reserved_size * 2;
    uint64_t total_reserved = LP_PARTITION_RESERVED_BYTES + reserved_size * 2;

    const LpMetadataBlockDevice* super_device = GetMetadataSuperBlockDevice(metadata);
    if (!super_device) {
@@ -112,16 +108,28 @@ static bool ValidateAndSerializeMetadata(int fd, const LpMetadata& metadata, std
        return false;
    }

    if (total_reserved > blockdevice_size ||
        total_reserved > super_device->first_logical_sector * LP_SECTOR_SIZE) {
    if (total_reserved > super_device->first_logical_sector * LP_SECTOR_SIZE) {
        LERROR << "Not enough space to store all logical partition metadata slots.";
        return false;
    }
    if (blockdevice_size != super_device->size) {
        LERROR << "Block device size " << blockdevice_size
               << " does not match metadata requested size " << super_device->size;
    for (const auto& block_device : metadata.block_devices) {
        std::string partition_name = GetBlockDevicePartitionName(block_device);
        if ((block_device.first_logical_sector + 1) * LP_SECTOR_SIZE > block_device.size) {
            LERROR << "Block device " << partition_name << " has invalid first sector "
                   << block_device.first_logical_sector << " for size " << block_device.size;
            return false;
        }
        BlockDeviceInfo info;
        if (!opener.GetInfo(partition_name, &info)) {
            PERROR << partition_name << ": ioctl";
            return false;
        }
        if (info.size != block_device.size) {
            LERROR << "Block device " << partition_name << " size mismatch (expected"
                   << block_device.size << ", got " << info.size << ")";
            return false;
        }
    }

    // Make sure all partition entries reference valid extents.
    for (const auto& partition : metadata.partitions) {
@@ -230,7 +238,7 @@ bool FlashPartitionTable(const IPartitionOpener& opener, const std::string& supe
    // basic checks that the geometry and tables are coherent, and will fit
    // on the given block device.
    std::string metadata_blob;
    if (!ValidateAndSerializeMetadata(fd, metadata, &metadata_blob)) {
    if (!ValidateAndSerializeMetadata(opener, metadata, &metadata_blob)) {
        return false;
    }

@@ -295,7 +303,7 @@ bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& sup
    // basic checks that the geometry and tables are coherent, and will fit
    // on the given block device.
    std::string blob;
    if (!ValidateAndSerializeMetadata(fd, metadata, &blob)) {
    if (!ValidateAndSerializeMetadata(opener, metadata, &blob)) {
        return false;
    }

@@ -327,7 +335,7 @@ bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& sup
        // synchronize the backup copy. This guarantees that a partial write
        // still leaves one copy intact.
        std::string old_blob;
        if (!ValidateAndSerializeMetadata(fd, *primary.get(), &old_blob)) {
        if (!ValidateAndSerializeMetadata(opener, *primary.get(), &old_blob)) {
            LERROR << "Error serializing primary metadata to repair corrupted backup";
            return false;
        }
@@ -339,7 +347,7 @@ bool UpdatePartitionTable(const IPartitionOpener& opener, const std::string& sup
        // The backup copy is coherent, and the primary is not. Sync it for
        // safety.
        std::string old_blob;
        if (!ValidateAndSerializeMetadata(fd, *backup.get(), &old_blob)) {
        if (!ValidateAndSerializeMetadata(opener, *backup.get(), &old_blob)) {
            LERROR << "Error serializing primary metadata to repair corrupted backup";
            return false;
        }