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

Commit 29033a81 authored by David Anderson's avatar David Anderson
Browse files

liblp: Fix lack of validation in file serialization.

WriteToImageFile() bypassed some validation checks, which can
confusingly cause ReadMetadata() to fail.

Bug: 408997684
Test: liblp_test
Change-Id: Ib6f3d17a4977769312357baeb068afccfe2bdead
parent 769522da
Loading
Loading
Loading
Loading
+5 −4
Original line number Diff line number Diff line
@@ -88,13 +88,14 @@ cc_defaults {
            static_libs: [
                "libfs_mgr",
            ],
        }
        },
    },
    stl: "libc++_static",
    srcs: [
        "builder_test.cpp",
        "super_layout_builder_test.cpp",
        "utility_test.cpp",
        "writer_test.cpp",
        ":TestPartitionOpener_group",
    ],
}
@@ -105,7 +106,7 @@ cc_test {
    test_suites: ["device-tests"],
    auto_gen_config: true,
    require_root: true,
    host_supported: true
    host_supported: true,
}

cc_test {
+8 −2
Original line number Diff line number Diff line
@@ -112,7 +112,10 @@ std::unique_ptr<LpMetadata> ReadFromImageFile(const std::string& image_file) {

bool WriteToImageFile(borrowed_fd fd, const LpMetadata& input) {
    std::string geometry = SerializeGeometry(input.geometry);
    std::string metadata = SerializeMetadata(input);
    std::string metadata = ValidateAndSerializeMetadata(input);
    if (metadata.empty()) {
        return false;
    }

    std::string everything = geometry + metadata;

@@ -298,7 +301,10 @@ bool ImageBuilder::Build() {
    }

    std::string geometry_blob = SerializeGeometry(geometry_);
    std::string metadata_blob = SerializeMetadata(metadata_);
    std::string metadata_blob = ValidateAndSerializeMetadata(metadata_);
    if (metadata_blob.empty()) {
        return false;
    }
    metadata_blob.resize(geometry_.metadata_max_size);

    // Two copies of geometry, then two copies of each metadata slot.
+4 −1
Original line number Diff line number Diff line
@@ -129,7 +129,10 @@ std::vector<SuperImageExtent> SuperLayoutBuilder::GetImageLayout() {

    // Write the primary and backup copies of each metadata slot. When flashing,
    // all metadata copies are the same, even for different slots.
    std::string metadata_bytes = SerializeMetadata(*metadata.get());
    std::string metadata_bytes = ValidateAndSerializeMetadata(*metadata.get());
    if (metadata_bytes.empty()) {
        return {};
    }

    // Align metadata size to 4KB. This makes the layout easily compatible with
    // libsparse.
+3 −1
Original line number Diff line number Diff line
@@ -46,7 +46,9 @@ TEST(SuperImageTool, Layout) {
    ASSERT_NE(metadata, nullptr);

    auto geometry_blob = std::make_shared<std::string>(SerializeGeometry(metadata->geometry));
    auto metadata_blob = std::make_shared<std::string>(SerializeMetadata(*metadata.get()));
    auto metadata_blob =
            std::make_shared<std::string>(ValidateAndSerializeMetadata(*metadata.get()));
    ASSERT_FALSE(metadata_blob->empty());
    metadata_blob->resize(4_KiB, '\0');

    auto extents = tool.GetImageLayout();
+21 −10
Original line number Diff line number Diff line
@@ -47,7 +47,8 @@ static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeomet
           g1.logical_block_size == g2.logical_block_size;
}

std::string SerializeMetadata(const LpMetadata& input) {
// Unvalidated serialization.
static std::string SerializeMetadata(const LpMetadata& input) {
    LpMetadata metadata = input;
    LpMetadataHeader& header = metadata.header;

@@ -81,25 +82,35 @@ std::string SerializeMetadata(const LpMetadata& input) {
    return header_blob + tables;
}

// Perform checks so we don't accidentally overwrite valid metadata with
// potentially invalid metadata, or random partition data with metadata.
static bool ValidateAndSerializeMetadata([[maybe_unused]] const IPartitionOpener& opener,
                                         const LpMetadata& metadata, std::string* blob) {
// Validated serialization.
std::string ValidateAndSerializeMetadata(const LpMetadata& metadata) {
    const LpMetadataGeometry& geometry = metadata.geometry;

    *blob = SerializeMetadata(metadata);
    std::string blob = SerializeMetadata(metadata);

    // Make sure we're writing within the space reserved.
    if (blob->size() > geometry.metadata_max_size) {
        LERROR << "Logical partition metadata is too large. " << blob->size() << " > "
    if (blob.size() > geometry.metadata_max_size) {
        LERROR << "Logical partition metadata is too large. " << blob.size() << " > "
               << geometry.metadata_max_size;
        return {};
    }
    return blob;
}

// Perform checks so we don't accidentally overwrite valid metadata with
// potentially invalid metadata, or random partition data with metadata.
static bool ValidateAndSerializeMetadata([[maybe_unused]] const IPartitionOpener& opener,
                                         const LpMetadata& metadata, std::string* blob) {
    *blob = ValidateAndSerializeMetadata(metadata);
    if (blob->empty()) {
        return false;
    }

    // Make sure the device has enough space to store two backup copies of the
    // metadata.
    uint64_t reserved_size = LP_METADATA_GEOMETRY_SIZE +
                             uint64_t(geometry.metadata_max_size) * geometry.metadata_slot_count;
    uint64_t reserved_size =
            LP_METADATA_GEOMETRY_SIZE +
            uint64_t(metadata.geometry.metadata_max_size) * metadata.geometry.metadata_slot_count;
    uint64_t total_reserved = LP_PARTITION_RESERVED_BYTES + reserved_size * 2;

    const LpMetadataBlockDevice* super_device = GetMetadataSuperBlockDevice(metadata);
Loading