diff --git a/fs_mgr/Android.bp b/fs_mgr/Android.bp index b0b4839e7..923442f90 100644 --- a/fs_mgr/Android.bp +++ b/fs_mgr/Android.bp @@ -57,15 +57,12 @@ cc_library_static { "libavb", "libfstab", "libdm", - "liblp", ], export_static_lib_headers: [ "libfstab", "libdm", - "liblp", ], whole_static_libs: [ - "liblp", "liblogwrap", "libdm", "libfstab", diff --git a/fs_mgr/liblp/Android.bp b/fs_mgr/liblp/Android.bp deleted file mode 100644 index d7bc6b573..000000000 --- a/fs_mgr/liblp/Android.bp +++ /dev/null @@ -1,38 +0,0 @@ -// -// Copyright (C) 2018 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -cc_library_static { - name: "liblp", - host_supported: true, - recovery_available: true, - defaults: ["fs_mgr_defaults"], - srcs: [ - "builder.cpp", - "reader.cpp", - "utility.cpp", - "writer.cpp", - ], - static_libs: [ - "libbase", - "liblog", - "libcrypto", - "libcrypto_utils", - ], - whole_static_libs: [ - "libext2_uuid", - ], - export_include_dirs: ["include"], -} diff --git a/fs_mgr/liblp/builder.cpp b/fs_mgr/liblp/builder.cpp deleted file mode 100644 index bfbf3e550..000000000 --- a/fs_mgr/liblp/builder.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "liblp/builder.h" - -#include - -#include - -#include -#include - -#include "liblp/metadata_format.h" -#include "utility.h" - -namespace android { -namespace fs_mgr { - -// Align a byte count up to the nearest 512-byte sector. -template -static inline T AlignToSector(T value) { - return (value + (LP_SECTOR_SIZE - 1)) & ~T(LP_SECTOR_SIZE - 1); -} - -void LinearExtent::AddTo(LpMetadata* out) const { - out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_LINEAR, physical_sector_}); -} - -void ZeroExtent::AddTo(LpMetadata* out) const { - out->extents.push_back(LpMetadataExtent{num_sectors_, LP_TARGET_TYPE_ZERO, 0}); -} - -Partition::Partition(const std::string& name, const std::string& guid, uint32_t attributes) - : name_(name), guid_(guid), attributes_(attributes), size_(0) {} - -void Partition::AddExtent(std::unique_ptr&& extent) { - size_ += extent->num_sectors() * LP_SECTOR_SIZE; - extents_.push_back(std::move(extent)); -} - -void Partition::RemoveExtents() { - size_ = 0; - extents_.clear(); -} - -void Partition::ShrinkTo(uint64_t requested_size) { - uint64_t aligned_size = AlignToSector(requested_size); - if (size_ <= aligned_size) { - return; - } - if (aligned_size == 0) { - RemoveExtents(); - return; - } - - // Remove or shrink extents of any kind until the total partition size is - // equal to the requested size. - uint64_t sectors_to_remove = (size_ - aligned_size) / LP_SECTOR_SIZE; - while (sectors_to_remove) { - Extent* extent = extents_.back().get(); - if (extent->num_sectors() > sectors_to_remove) { - size_ -= sectors_to_remove * LP_SECTOR_SIZE; - extent->set_num_sectors(extent->num_sectors() - sectors_to_remove); - break; - } - size_ -= (extent->num_sectors() * LP_SECTOR_SIZE); - sectors_to_remove -= extent->num_sectors(); - extents_.pop_back(); - } - DCHECK(size_ == requested_size); -} - -std::unique_ptr MetadataBuilder::New(uint64_t blockdevice_size, - uint32_t metadata_max_size, - uint32_t metadata_slot_count) { - std::unique_ptr builder(new MetadataBuilder()); - if (!builder->Init(blockdevice_size, metadata_max_size, metadata_slot_count)) { - return nullptr; - } - return builder; -} - -std::unique_ptr MetadataBuilder::New(const LpMetadata& metadata) { - std::unique_ptr builder(new MetadataBuilder()); - if (!builder->Init(metadata)) { - return nullptr; - } - return builder; -} - -MetadataBuilder::MetadataBuilder() { - memset(&geometry_, 0, sizeof(geometry_)); - geometry_.magic = LP_METADATA_GEOMETRY_MAGIC; - geometry_.struct_size = sizeof(geometry_); - - memset(&header_, 0, sizeof(header_)); - header_.magic = LP_METADATA_HEADER_MAGIC; - header_.major_version = LP_METADATA_MAJOR_VERSION; - header_.minor_version = LP_METADATA_MINOR_VERSION; - header_.header_size = sizeof(header_); - header_.partitions.entry_size = sizeof(LpMetadataPartition); - header_.extents.entry_size = sizeof(LpMetadataExtent); -} - -bool MetadataBuilder::Init(const LpMetadata& metadata) { - geometry_ = metadata.geometry; - - for (const auto& partition : metadata.partitions) { - Partition* builder = AddPartition(GetPartitionName(partition), GetPartitionGuid(partition), - partition.attributes); - if (!builder) { - return false; - } - - for (size_t i = 0; i < partition.num_extents; i++) { - const LpMetadataExtent& extent = metadata.extents[partition.first_extent_index + i]; - if (extent.target_type == LP_TARGET_TYPE_LINEAR) { - auto copy = std::make_unique(extent.num_sectors, extent.target_data); - builder->AddExtent(std::move(copy)); - } else if (extent.target_type == LP_TARGET_TYPE_ZERO) { - auto copy = std::make_unique(extent.num_sectors); - builder->AddExtent(std::move(copy)); - } - } - } - return true; -} - -bool MetadataBuilder::Init(uint64_t blockdevice_size, uint32_t metadata_max_size, - uint32_t metadata_slot_count) { - if (metadata_max_size < sizeof(LpMetadataHeader)) { - LERROR << "Invalid metadata maximum size."; - return false; - } - if (metadata_slot_count == 0) { - LERROR << "Invalid metadata slot count."; - return false; - } - - // Align the metadata size up to the nearest sector. - metadata_max_size = AlignToSector(metadata_max_size); - - // We reserve a geometry block (4KB) plus space for each copy of the - // maximum size of a metadata blob. Then, we double that space since - // we store a backup copy of everything. - uint64_t reserved = - LP_METADATA_GEOMETRY_SIZE + (uint64_t(metadata_max_size) * metadata_slot_count); - uint64_t total_reserved = reserved * 2; - - if (blockdevice_size < total_reserved || blockdevice_size - total_reserved < LP_SECTOR_SIZE) { - LERROR << "Attempting to create metadata on a block device that is too small."; - return false; - } - - // The last sector is inclusive. We subtract one to make sure that logical - // partitions won't overlap with the same sector as the backup metadata, - // which could happen if the block device was not aligned to LP_SECTOR_SIZE. - geometry_.first_logical_sector = reserved / LP_SECTOR_SIZE; - geometry_.last_logical_sector = ((blockdevice_size - reserved) / LP_SECTOR_SIZE) - 1; - geometry_.metadata_max_size = metadata_max_size; - geometry_.metadata_slot_count = metadata_slot_count; - DCHECK(geometry_.last_logical_sector >= geometry_.first_logical_sector); - return true; -} - -Partition* MetadataBuilder::AddPartition(const std::string& name, const std::string& guid, - uint32_t attributes) { - if (name.empty()) { - LERROR << "Partition must have a non-empty name."; - return nullptr; - } - if (FindPartition(name)) { - LERROR << "Attempting to create duplication partition with name: " << name; - return nullptr; - } - partitions_.push_back(std::make_unique(name, guid, attributes)); - return partitions_.back().get(); -} - -Partition* MetadataBuilder::FindPartition(const std::string& name) { - for (const auto& partition : partitions_) { - if (partition->name() == name) { - return partition.get(); - } - } - return nullptr; -} - -void MetadataBuilder::RemovePartition(const std::string& name) { - for (auto iter = partitions_.begin(); iter != partitions_.end(); iter++) { - if ((*iter)->name() == name) { - partitions_.erase(iter); - return; - } - } -} - -bool MetadataBuilder::GrowPartition(Partition* partition, uint64_t requested_size) { - // Align the space needed up to the nearest sector. - uint64_t aligned_size = AlignToSector(requested_size); - if (partition->size() >= aligned_size) { - return true; - } - - // Figure out how much we need to allocate. - uint64_t space_needed = aligned_size - partition->size(); - uint64_t sectors_needed = space_needed / LP_SECTOR_SIZE; - DCHECK(sectors_needed * LP_SECTOR_SIZE == space_needed); - - struct Interval { - uint64_t start; - uint64_t end; - - Interval(uint64_t start, uint64_t end) : start(start), end(end) {} - bool operator<(const Interval& other) const { return start < other.start; } - }; - std::vector intervals; - - // Collect all extents in the partition table. - for (const auto& partition : partitions_) { - for (const auto& extent : partition->extents()) { - LinearExtent* linear = extent->AsLinearExtent(); - if (!linear) { - continue; - } - intervals.emplace_back(linear->physical_sector(), - linear->physical_sector() + extent->num_sectors()); - } - } - - // Sort extents by starting sector. - std::sort(intervals.begin(), intervals.end()); - - // Find gaps that we can use for new extents. Note we store new extents in a - // temporary vector, and only commit them if we are guaranteed enough free - // space. - std::vector> new_extents; - for (size_t i = 1; i < intervals.size(); i++) { - const Interval& previous = intervals[i - 1]; - const Interval& current = intervals[i]; - - if (previous.end >= current.start) { - // There is no gap between these two extents, try the next one. Note that - // extents may never overlap, but just for safety, we ignore them if they - // do. - DCHECK(previous.end == current.start); - continue; - } - - // This gap is enough to hold the remainder of the space requested, so we - // can allocate what we need and return. - if (current.start - previous.end >= sectors_needed) { - auto extent = std::make_unique(sectors_needed, previous.end); - sectors_needed -= extent->num_sectors(); - new_extents.push_back(std::move(extent)); - break; - } - - // This gap is not big enough to fit the remainder of the space requested, - // so consume the whole thing and keep looking for more. - auto extent = std::make_unique(current.start - previous.end, previous.end); - sectors_needed -= extent->num_sectors(); - new_extents.push_back(std::move(extent)); - } - - // If we still have more to allocate, take it from the remaining free space - // in the allocatable region. - if (sectors_needed) { - uint64_t first_sector; - if (intervals.empty()) { - first_sector = geometry_.first_logical_sector; - } else { - first_sector = intervals.back().end; - } - DCHECK(first_sector <= geometry_.last_logical_sector); - - // Note: the last usable sector is inclusive. - if (first_sector + sectors_needed > geometry_.last_logical_sector) { - LERROR << "Not enough free space to expand partition: " << partition->name(); - return false; - } - auto extent = std::make_unique(sectors_needed, first_sector); - new_extents.push_back(std::move(extent)); - } - - for (auto& extent : new_extents) { - partition->AddExtent(std::move(extent)); - } - return true; -} - -void MetadataBuilder::ShrinkPartition(Partition* partition, uint64_t requested_size) { - partition->ShrinkTo(requested_size); -} - -std::unique_ptr MetadataBuilder::Export() { - std::unique_ptr metadata = std::make_unique(); - metadata->header = header_; - metadata->geometry = geometry_; - - // Flatten the partition and extent structures into an LpMetadata, which - // makes it very easy to validate, serialize, or pass on to device-mapper. - for (const auto& partition : partitions_) { - LpMetadataPartition part; - memset(&part, 0, sizeof(part)); - - if (partition->name().size() > sizeof(part.name)) { - LERROR << "Partition name is too long: " << partition->name(); - return nullptr; - } - if (partition->attributes() & ~(LP_PARTITION_ATTRIBUTE_MASK)) { - LERROR << "Partition " << partition->name() << " has unsupported attribute."; - return nullptr; - } - - strncpy(part.name, partition->name().c_str(), sizeof(part.name)); - if (uuid_parse(partition->guid().c_str(), part.guid) != 0) { - LERROR << "Could not parse guid " << partition->guid() << " for partition " - << partition->name(); - return nullptr; - } - - part.first_extent_index = static_cast(metadata->extents.size()); - part.num_extents = static_cast(partition->extents().size()); - part.attributes = partition->attributes(); - - for (const auto& extent : partition->extents()) { - extent->AddTo(metadata.get()); - } - metadata->partitions.push_back(part); - } - - metadata->header.partitions.num_entries = static_cast(metadata->partitions.size()); - metadata->header.extents.num_entries = static_cast(metadata->extents.size()); - return metadata; -} - -} // namespace fs_mgr -} // namespace android diff --git a/fs_mgr/liblp/include/liblp/builder.h b/fs_mgr/liblp/include/liblp/builder.h deleted file mode 100644 index fb982e27a..000000000 --- a/fs_mgr/liblp/include/liblp/builder.h +++ /dev/null @@ -1,169 +0,0 @@ -// -// Copyright (C) 2018 The Android Open Source Project -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. -// - -#ifndef LIBLP_METADATA_BUILDER_H -#define LIBLP_METADATA_BUILDER_H - -#include -#include - -#include -#include - -#include "metadata_format.h" - -namespace android { -namespace fs_mgr { - -class LinearExtent; - -// Abstraction around dm-targets that can be encoded into logical partition tables. -class Extent { - public: - explicit Extent(uint64_t num_sectors) : num_sectors_(num_sectors) {} - virtual ~Extent() {} - - virtual void AddTo(LpMetadata* out) const = 0; - virtual LinearExtent* AsLinearExtent() { return nullptr; } - - uint64_t num_sectors() const { return num_sectors_; } - void set_num_sectors(uint64_t num_sectors) { num_sectors_ = num_sectors; } - - protected: - uint64_t num_sectors_; -}; - -// This corresponds to a dm-linear target. -class LinearExtent final : public Extent { - public: - LinearExtent(uint64_t num_sectors, uint64_t physical_sector) - : Extent(num_sectors), physical_sector_(physical_sector) {} - - void AddTo(LpMetadata* metadata) const override; - LinearExtent* AsLinearExtent() override { return this; } - - uint64_t physical_sector() const { return physical_sector_; } - - private: - uint64_t physical_sector_; -}; - -// This corresponds to a dm-zero target. -class ZeroExtent final : public Extent { - public: - explicit ZeroExtent(uint64_t num_sectors) : Extent(num_sectors) {} - - void AddTo(LpMetadata* out) const override; -}; - -class Partition final { - public: - Partition(const std::string& name, const std::string& guid, uint32_t attributes); - - // Add a raw extent. - void AddExtent(std::unique_ptr&& extent); - - // Remove all extents from this partition. - void RemoveExtents(); - - // Remove and/or shrink extents until the partition is the requested size. - // See MetadataBuilder::ShrinkPartition for more information. - void ShrinkTo(uint64_t requested_size); - - const std::string& name() const { return name_; } - uint32_t attributes() const { return attributes_; } - const std::string& guid() const { return guid_; } - const std::vector>& extents() const { return extents_; } - uint64_t size() const { return size_; } - - private: - std::string name_; - std::string guid_; - std::vector> extents_; - uint32_t attributes_; - uint64_t size_; -}; - -class MetadataBuilder { - public: - // Construct an empty logical partition table builder. The block device size - // and maximum metadata size must be specified, as this will determine which - // areas of the physical partition can be flashed for metadata vs for logical - // partitions. - // - // If the parameters would yield invalid metadata, nullptr is returned. This - // could happen if the block device size is too small to store the metadata - // and backup copies. - static std::unique_ptr New(uint64_t blockdevice_size, - uint32_t metadata_max_size, - uint32_t metadata_slot_count); - - // Import an existing table for modification. If the table is not valid, for - // example it contains duplicate partition names, then nullptr is returned. - static std::unique_ptr New(const LpMetadata& metadata); - - // Export metadata so it can be serialized to an image, to disk, or mounted - // via device-mapper. - std::unique_ptr Export(); - - // Add a partition, returning a handle so it can be sized as needed. If a - // partition with the given name already exists, nullptr is returned. - Partition* AddPartition(const std::string& name, const std::string& guid, uint32_t attributes); - - // Delete a partition by name if it exists. - void RemovePartition(const std::string& name); - - // Find a partition by name. If no partition is found, nullptr is returned. - Partition* FindPartition(const std::string& name); - - // Grow a partition to the requested size. If the partition's size is already - // greater or equal to the requested size, this will return true and the - // partition table will not be changed. Otherwise, a greedy algorithm is - // used to find free gaps in the partition table and allocate them for this - // partition. If not enough space can be allocated, false is returned, and - // the parition table will not be modified. - // - // The size will be rounded UP to the nearest sector. - // - // Note, this is an in-memory operation, and it does not alter the - // underlying filesystem or contents of the partition on disk. - bool GrowPartition(Partition* partition, uint64_t requested_size); - - // Shrink a partition to the requested size. If the partition is already - // smaller than the given size, this will return and the partition table - // will not be changed. Otherwise, extents will be removed and/or shrunk - // from the end of the partition until it is the requested size. - // - // The size will be rounded UP to the nearest sector. - // - // Note, this is an in-memory operation, and it does not alter the - // underlying filesystem or contents of the partition on disk. - void ShrinkPartition(Partition* partition, uint64_t requested_size); - - private: - MetadataBuilder(); - bool Init(uint64_t blockdevice_size, uint32_t metadata_max_size, uint32_t metadata_slot_count); - bool Init(const LpMetadata& metadata); - - LpMetadataGeometry geometry_; - LpMetadataHeader header_; - std::vector> partitions_; -}; - -} // namespace fs_mgr -} // namespace android - -#endif /* LIBLP_METADATA_BUILDER_H */ diff --git a/fs_mgr/liblp/include/liblp/metadata_format.h b/fs_mgr/liblp/include/liblp/metadata_format.h deleted file mode 100644 index f6262ff63..000000000 --- a/fs_mgr/liblp/include/liblp/metadata_format.h +++ /dev/null @@ -1,263 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LOGICAL_PARTITION_METADATA_FORMAT_H_ -#define LOGICAL_PARTITION_METADATA_FORMAT_H_ - -#ifdef __cplusplus -#include -#include -#endif - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -/* Magic signature for LpMetadataGeometry. */ -#define LP_METADATA_GEOMETRY_MAGIC 0x616c4467 - -/* Space reserved for geometry information. */ -#define LP_METADATA_GEOMETRY_SIZE 4096 - -/* Magic signature for LpMetadataHeader. */ -#define LP_METADATA_HEADER_MAGIC 0x414C5030 - -/* Current metadata version. */ -#define LP_METADATA_MAJOR_VERSION 1 -#define LP_METADATA_MINOR_VERSION 0 - -/* Attributes for the LpMetadataPartition::attributes field. - * - * READONLY - The partition should not be considered writable. When used with - * device mapper, the block device will be created as read-only. - */ -#define LP_PARTITION_ATTR_READONLY 0x1 - -/* Mask that defines all valid attributes. */ -#define LP_PARTITION_ATTRIBUTE_MASK (LP_PARTITION_ATTR_READONLY) - -/* Default name of the physical partition that holds logical partition entries. - * The layout of this partition will look like: - * - * +--------------------+ - * | Disk Geometry | - * +--------------------+ - * | Metadata | - * +--------------------+ - * | Logical Partitions | - * +--------------------+ - * | Backup Metadata | - * +--------------------+ - * | Geometry Backup | - * +--------------------+ - */ -#define LP_METADATA_PARTITION_NAME "android" - -/* Size of a sector is always 512 bytes for compatibility with the Linux kernel. */ -#define LP_SECTOR_SIZE 512 - -/* This structure is stored at sector 0 in the first 4096 bytes of the - * partition, and again in the very last 4096 bytes. It is never modified and - * describes how logical partition information can be located. - */ -typedef struct LpMetadataGeometry { - /* 0: Magic signature (LP_METADATA_GEOMETRY_MAGIC). */ - uint32_t magic; - - /* 4: Size of the LpMetadataGeometry struct. */ - uint32_t struct_size; - - /* 8: SHA256 checksum of this struct, with this field set to 0. */ - uint8_t checksum[32]; - - /* 40: Maximum amount of space a single copy of the metadata can use. */ - uint32_t metadata_max_size; - - /* 44: Number of copies of the metadata to keep. For A/B devices, this - * will be 2. For an A/B/C device, it would be 3, et cetera. For Non-A/B - * it will be 1. A backup copy of each slot is kept, so if this is "2", - * there will be four copies total. - */ - uint32_t metadata_slot_count; - - /* 48: First usable sector for allocating logical partitions. this will be - * the first sector after the initial 4096 geometry block, followed by the - * space consumed by metadata_max_size*metadata_slot_count. - */ - uint64_t first_logical_sector; - - /* 56: Last usable sector, inclusive, for allocating logical partitions. - * At the end of this sector will follow backup metadata slots and the - * backup geometry block at the very end. - */ - uint64_t last_logical_sector; -} __attribute__((packed)) LpMetadataGeometry; - -/* The logical partition metadata has a number of tables; they are described - * in the header via the following structure. - * - * The size of the table can be computed by multiplying entry_size by - * num_entries, and the result must not overflow a 32-bit signed integer. - */ -typedef struct LpMetadataTableDescriptor { - /* 0: Location of the table, relative to the metadata header. */ - uint32_t offset; - /* 4: Number of entries in the table. */ - uint32_t num_entries; - /* 8: Size of each entry in the table, in bytes. */ - uint32_t entry_size; -} __attribute__((packed)) LpMetadataTableDescriptor; - -/* Binary format for the header of the logical partition metadata format. - * - * The format has three sections. The header must occur first, and the - * proceeding tables may be placed in any order after. - * - * +-----------------------------------------+ - * | Header data - fixed size | - * +-----------------------------------------+ - * | Partition table - variable size | - * +-----------------------------------------+ - * | Partition table extents - variable size | - * +-----------------------------------------+ - * - * The "Header" portion is described by LpMetadataHeader. It will always - * precede the other three blocks. - * - * All fields are stored in little-endian byte order when serialized. - * - * This struct is versioned; see the |major_version| and |minor_version| - * fields. - */ -typedef struct LpMetadataHeader { - /* 0: Four bytes equal to LP_METADATA_HEADER_MAGIC. */ - uint32_t magic; - - /* 4: Version number required to read this metadata. If the version is not - * equal to the library version, the metadata should be considered - * incompatible. - */ - uint16_t major_version; - - /* 6: Minor version. A library supporting newer features should be able to - * read metadata with an older minor version. However, an older library - * should not support reading metadata if its minor version is higher. - */ - uint16_t minor_version; - - /* 8: The size of this header struct. */ - uint32_t header_size; - - /* 12: SHA256 checksum of the header, up to |header_size| bytes, computed as - * if this field were set to 0. - */ - uint8_t header_checksum[32]; - - /* 44: The total size of all tables. This size is contiguous; tables may not - * have gaps in between, and they immediately follow the header. - */ - uint32_t tables_size; - - /* 48: SHA256 checksum of all table contents. */ - uint8_t tables_checksum[32]; - - /* 80: Partition table descriptor. */ - LpMetadataTableDescriptor partitions; - /* 92: Extent table descriptor. */ - LpMetadataTableDescriptor extents; -} __attribute__((packed)) LpMetadataHeader; - -/* This struct defines a logical partition entry, similar to what would be - * present in a GUID Partition Table. - */ -typedef struct LpMetadataPartition { - /* 0: Name of this partition in ASCII characters. Any unused characters in - * the buffer must be set to 0. Characters may only be alphanumeric or _. - * The name must include at least one ASCII character, and it must be unique - * across all partition names. The length (36) is the same as the maximum - * length of a GPT partition name. - */ - char name[36]; - - /* 36: Globally unique identifier (GUID) of this partition. */ - uint8_t guid[16]; - - /* 52: Attributes for the partition (see LP_PARTITION_ATTR_* flags above). */ - uint32_t attributes; - - /* 56: Index of the first extent owned by this partition. The extent will - * start at logical sector 0. Gaps between extents are not allowed. - */ - uint32_t first_extent_index; - - /* 60: Number of extents in the partition. Every partition must have at - * least one extent. - */ - uint32_t num_extents; -} __attribute__((packed)) LpMetadataPartition; - -/* This extent is a dm-linear target, and the index is an index into the - * LinearExtent table. - */ -#define LP_TARGET_TYPE_LINEAR 0 - -/* This extent is a dm-zero target. The index is ignored and must be 0. */ -#define LP_TARGET_TYPE_ZERO 1 - -/* This struct defines an extent entry in the extent table block. */ -typedef struct LpMetadataExtent { - /* 0: Length of this extent, in 512-byte sectors. */ - uint64_t num_sectors; - - /* 8: Target type for device-mapper (see LP_TARGET_TYPE_* values). */ - uint32_t target_type; - - /* 12: Contents depends on target_type. - * - * LINEAR: The sector on the physical partition that this extent maps onto. - * ZERO: This field must be 0. - */ - uint64_t target_data; -} __attribute__((packed)) LpMetadataExtent; - -#ifdef __cplusplus -} /* extern "C" */ -#endif - -#ifdef __cplusplus -namespace android { -namespace fs_mgr { - -// Helper structure for easily interpreting deserialized metadata, or -// re-serializing metadata. -struct LpMetadata { - LpMetadataGeometry geometry; - LpMetadataHeader header; - std::vector partitions; - std::vector extents; -}; - -// Helper to extract safe C++ strings from partition info. -std::string GetPartitionName(const LpMetadataPartition& partition); -std::string GetPartitionGuid(const LpMetadataPartition& partition); - -} // namespace fs_mgr -} // namespace android -#endif - -#endif /* LOGICAL_PARTITION_METADATA_FORMAT_H_ */ diff --git a/fs_mgr/liblp/include/liblp/reader.h b/fs_mgr/liblp/include/liblp/reader.h deleted file mode 100644 index e7fa46dcb..000000000 --- a/fs_mgr/liblp/include/liblp/reader.h +++ /dev/null @@ -1,43 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LIBLP_READER_H_ -#define LIBLP_READER_H_ - -#include - -#include - -#include "metadata_format.h" - -namespace android { -namespace fs_mgr { - -// Read logical partition metadata from its predetermined location on a block -// device. If readback fails, we also attempt to load from a backup copy. -std::unique_ptr ReadMetadata(const char* block_device, uint32_t slot_number); - -// Read and validate the logical partition geometry from a block device. -bool ReadLogicalPartitionGeometry(const char* block_device, LpMetadataGeometry* geometry); - -// Read logical partition metadata from an image file that was created with -// WriteToImageFile(). -std::unique_ptr ReadFromImageFile(const char* file); - -} // namespace fs_mgr -} // namespace android - -#endif /* LIBLP_READER_H_ */ diff --git a/fs_mgr/liblp/include/liblp/writer.h b/fs_mgr/liblp/include/liblp/writer.h deleted file mode 100644 index 02fb21fc1..000000000 --- a/fs_mgr/liblp/include/liblp/writer.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LIBLP_WRITER_H -#define LIBLP_WRITER_H - -#include "metadata_format.h" - -namespace android { -namespace fs_mgr { - -// When flashing the initial logical partition layout, we also write geometry -// information at the start and end of the big physical partition. This helps -// locate metadata and backup metadata in the case of corruption or a failed -// update. For normal changes to the metadata, we never modify the geometry. -enum class SyncMode { - // Write geometry information. - Flash, - // Normal update of a single slot. - Update -}; - -// Write the given partition table to the given block device, writing only -// copies according to the given sync mode. -// -// This will perform some verification, such that the device has enough space -// to store the metadata as well as all of its extents. -// -// The slot number indicates which metadata slot to use. -bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode, - uint32_t slot_number); - -// Helper function to serialize geometry and metadata to a normal file, for -// flashing or debugging. -bool WriteToImageFile(const char* file, const LpMetadata& metadata); - -} // namespace fs_mgr -} // namespace android - -#endif /* LIBLP_WRITER_H */ diff --git a/fs_mgr/liblp/reader.cpp b/fs_mgr/liblp/reader.cpp deleted file mode 100644 index 1b70da9a8..000000000 --- a/fs_mgr/liblp/reader.cpp +++ /dev/null @@ -1,307 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include "liblp/reader.h" - -#include -#include -#include - -#include - -#include -#include - -#include "utility.h" - -namespace android { -namespace fs_mgr { - -// Parse an LpMetadataGeometry from a buffer. The buffer must be at least -// LP_METADATA_GEOMETRY_SIZE bytes in size. -static bool ParseGeometry(const void* buffer, LpMetadataGeometry* geometry) { - static_assert(sizeof(*geometry) <= LP_METADATA_GEOMETRY_SIZE); - memcpy(geometry, buffer, sizeof(*geometry)); - - // Check the magic signature. - if (geometry->magic != LP_METADATA_GEOMETRY_MAGIC) { - LERROR << "Logical partition metadata has invalid geometry magic signature."; - return false; - } - // Recompute and check the CRC32. - { - LpMetadataGeometry temp = *geometry; - memset(&temp.checksum, 0, sizeof(temp.checksum)); - SHA256(&temp, sizeof(temp), temp.checksum); - if (memcmp(temp.checksum, geometry->checksum, sizeof(temp.checksum)) != 0) { - LERROR << "Logical partition metadata has invalid geometry checksum."; - return false; - } - } - // Check that the struct size is equal (this will have to change if we ever - // change the struct size in a release). - if (geometry->struct_size != sizeof(LpMetadataGeometry)) { - LERROR << "Logical partition metadata has invalid struct size."; - return false; - } - if (geometry->metadata_slot_count == 0) { - LERROR << "Logical partition metadata has invalid slot count."; - return false; - } - - // Check that the metadata area and logical partition areas don't overlap. - off64_t end_of_metadata = - GetPrimaryMetadataOffset(*geometry, geometry->metadata_slot_count - 1) + - geometry->metadata_max_size; - if (uint64_t(end_of_metadata) > geometry->first_logical_sector * LP_SECTOR_SIZE) { - LERROR << "Logical partition metadata overlaps with logical partition contents."; - return false; - } - return true; -} - -// Read and validate geometry information from a block device that holds -// logical partitions. If the information is corrupted, this will attempt -// to read it from a secondary backup location. -static bool ReadLogicalPartitionGeometry(int fd, LpMetadataGeometry* geometry) { - // Read the first 4096 bytes. - std::unique_ptr buffer = std::make_unique(LP_METADATA_GEOMETRY_SIZE); - if (lseek64(fd, 0, SEEK_SET) == (off64_t)-1) { - PERROR << __PRETTY_FUNCTION__ << "lseek64 failed"; - return false; - } - if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) { - PERROR << __PRETTY_FUNCTION__ << "read " << LP_METADATA_GEOMETRY_SIZE << " bytes failed"; - return false; - } - if (ParseGeometry(buffer.get(), geometry)) { - return true; - } - - // Try the backup copy in the last 4096 bytes. - if (lseek64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) == (off64_t)-1) { - PERROR << __PRETTY_FUNCTION__ << "lseek64 failed, offset " << -LP_METADATA_GEOMETRY_SIZE; - return false; - } - if (!android::base::ReadFully(fd, buffer.get(), LP_METADATA_GEOMETRY_SIZE)) { - PERROR << __PRETTY_FUNCTION__ << "backup read " << LP_METADATA_GEOMETRY_SIZE - << " bytes failed"; - return false; - } - return ParseGeometry(buffer.get(), geometry); -} - -// Helper function to read geometry from a device without an open descriptor. -bool ReadLogicalPartitionGeometry(const char* block_device, LpMetadataGeometry* geometry) { - android::base::unique_fd fd(open(block_device, O_RDONLY)); - if (fd < 0) { - PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device; - return false; - } - return ReadLogicalPartitionGeometry(fd, geometry); -} - -static bool ValidateTableBounds(const LpMetadataHeader& header, - const LpMetadataTableDescriptor& table) { - if (table.offset > header.tables_size) { - return false; - } - uint64_t table_size = uint64_t(table.num_entries) * table.entry_size; - if (header.tables_size - table.offset < table_size) { - return false; - } - return true; -} - -static bool ValidateMetadataHeader(const LpMetadataHeader& header) { - // To compute the header's checksum, we have to temporarily set its checksum - // field to 0. - { - LpMetadataHeader temp = header; - memset(&temp.header_checksum, 0, sizeof(temp.header_checksum)); - SHA256(&temp, sizeof(temp), temp.header_checksum); - if (memcmp(temp.header_checksum, header.header_checksum, sizeof(temp.header_checksum)) != 0) { - LERROR << "Logical partition metadata has invalid checksum."; - return false; - } - } - - // Do basic validation of key metadata bits. - if (header.magic != LP_METADATA_HEADER_MAGIC) { - LERROR << "Logical partition metadata has invalid magic value."; - return false; - } - // Check that the version is compatible. - if (header.major_version != LP_METADATA_MAJOR_VERSION || - header.minor_version > LP_METADATA_MINOR_VERSION) { - LERROR << "Logical partition metadata has incompatible version."; - return false; - } - if (!ValidateTableBounds(header, header.partitions) || - !ValidateTableBounds(header, header.extents)) { - LERROR << "Logical partition metadata has invalid table bounds."; - return false; - } - // Check that table entry sizes can accomodate their respective structs. If - // table sizes change, these checks will have to be adjusted. - if (header.partitions.entry_size != sizeof(LpMetadataPartition)) { - LERROR << "Logical partition metadata has invalid partition table entry size."; - return false; - } - if (header.extents.entry_size != sizeof(LpMetadataExtent)) { - LERROR << "Logical partition metadata has invalid extent table entry size."; - return false; - } - return true; -} - -using ReadMetadataFn = std::function; - -// Parse and validate all metadata at the current position in the given file -// descriptor. -static std::unique_ptr ParseMetadata(int fd) { - // First read and validate the header. - std::unique_ptr metadata = std::make_unique(); - if (!android::base::ReadFully(fd, &metadata->header, sizeof(metadata->header))) { - PERROR << __PRETTY_FUNCTION__ << "read " << sizeof(metadata->header) << "bytes failed"; - return nullptr; - } - if (!ValidateMetadataHeader(metadata->header)) { - return nullptr; - } - - LpMetadataHeader& header = metadata->header; - - // Read the metadata payload. Allocation is fallible in case the metadata is - // corrupt and has some huge value. - std::unique_ptr buffer(new (std::nothrow) uint8_t[header.tables_size]); - if (!buffer) { - LERROR << "Out of memory reading logical partition tables."; - return nullptr; - } - if (!android::base::ReadFully(fd, buffer.get(), header.tables_size)) { - PERROR << __PRETTY_FUNCTION__ << "read " << header.tables_size << "bytes failed"; - return nullptr; - } - - uint8_t checksum[32]; - SHA256(buffer.get(), header.tables_size, checksum); - if (memcmp(checksum, header.tables_checksum, sizeof(checksum)) != 0) { - LERROR << "Logical partition metadata has invalid table checksum."; - return nullptr; - } - - // ValidateTableSize ensured that |cursor| is valid for the number of - // entries in the table. - uint8_t* cursor = buffer.get() + header.partitions.offset; - for (size_t i = 0; i < header.partitions.num_entries; i++) { - LpMetadataPartition partition; - memcpy(&partition, cursor, sizeof(partition)); - cursor += header.partitions.entry_size; - - if (partition.attributes & ~LP_PARTITION_ATTRIBUTE_MASK) { - LERROR << "Logical partition has invalid attribute set."; - return nullptr; - } - if (partition.first_extent_index + partition.num_extents > header.extents.num_entries) { - LERROR << "Logical partition has invalid extent list."; - return nullptr; - } - - metadata->partitions.push_back(partition); - } - - cursor = buffer.get() + header.extents.offset; - for (size_t i = 0; i < header.extents.num_entries; i++) { - LpMetadataExtent extent; - memcpy(&extent, cursor, sizeof(extent)); - cursor += header.extents.entry_size; - - metadata->extents.push_back(extent); - } - - return metadata; -} - -std::unique_ptr ReadMetadata(const char* block_device, uint32_t slot_number) { - android::base::unique_fd fd(open(block_device, O_RDONLY)); - if (fd < 0) { - PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device; - return nullptr; - } - LpMetadataGeometry geometry; - if (!ReadLogicalPartitionGeometry(fd, &geometry)) { - return nullptr; - } - - // First try the primary copy. - off64_t offset = GetPrimaryMetadataOffset(geometry, slot_number); - if (lseek64(fd, offset, SEEK_SET) == (off64_t)-1) { - PERROR << __PRETTY_FUNCTION__ << "lseek64 failed: offset " << offset; - return nullptr; - } - if (std::unique_ptr metadata = ParseMetadata(fd)) { - return metadata; - } - - // Next try the backup copy. - offset = GetBackupMetadataOffset(geometry, slot_number); - if (lseek64(fd, offset, SEEK_END) == (off64_t)-1) { - PERROR << __PRETTY_FUNCTION__ << "lseek64 failed: offset " << offset; - return nullptr; - } - return ParseMetadata(fd); -} - -std::unique_ptr ReadFromImageFile(const char* file) { - android::base::unique_fd fd(open(file, O_RDONLY)); - if (fd < 0) { - PERROR << __PRETTY_FUNCTION__ << "open failed: " << file; - return nullptr; - } - - LpMetadataGeometry geometry; - if (!ReadLogicalPartitionGeometry(fd, &geometry)) { - return nullptr; - } - if (lseek64(fd, LP_METADATA_GEOMETRY_SIZE, SEEK_SET) == (off64_t)-1) { - PERROR << __PRETTY_FUNCTION__ << "lseek64 failed: offset " << LP_METADATA_GEOMETRY_SIZE; - return nullptr; - } - std::unique_ptr metadata = ParseMetadata(fd); - if (!metadata) { - return nullptr; - } - metadata->geometry = geometry; - return metadata; -} - -static std::string NameFromFixedArray(const char* name, size_t buffer_size) { - // If the end of the buffer has a null character, it's safe to assume the - // buffer is null terminated. Otherwise, we cap the string to the input - // buffer size. - if (name[buffer_size - 1] == '\0') { - return std::string(name); - } - return std::string(name, buffer_size); -} - -std::string GetPartitionName(const LpMetadataPartition& partition) { - return NameFromFixedArray(partition.name, sizeof(partition.name)); -} - -} // namespace fs_mgr -} // namespace android diff --git a/fs_mgr/liblp/utility.cpp b/fs_mgr/liblp/utility.cpp deleted file mode 100644 index c4b70288a..000000000 --- a/fs_mgr/liblp/utility.cpp +++ /dev/null @@ -1,89 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include "utility.h" - -namespace android { -namespace fs_mgr { - -bool GetDescriptorSize(int fd, uint64_t* size) { - struct stat s; - if (fstat(fd, &s) < 0) { - PERROR << __PRETTY_FUNCTION__ << "fstat failed"; - return false; - } - - if (S_ISBLK(s.st_mode)) { - if (ioctl(fd, BLKGETSIZE64, size) != -1) { - return true; - } - } - - off64_t result = lseek64(fd, 0, SEEK_END); - if (result == (off64_t)-1) { - PERROR << __PRETTY_FUNCTION__ << "lseek64 failed"; - return false; - } - - *size = result; - return true; -} - -off64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) { - CHECK(slot_number < geometry.metadata_slot_count); - - off64_t offset = LP_METADATA_GEOMETRY_SIZE + geometry.metadata_max_size * slot_number; - CHECK(offset + geometry.metadata_max_size <= - off64_t(geometry.first_logical_sector * LP_SECTOR_SIZE)); - return offset; -} - -off64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number) { - CHECK(slot_number < geometry.metadata_slot_count); - off64_t start = off64_t(-LP_METADATA_GEOMETRY_SIZE) - - off64_t(geometry.metadata_max_size) * geometry.metadata_slot_count; - return start + off64_t(geometry.metadata_max_size * slot_number); -} - -void SHA256(const void* data, size_t length, uint8_t out[32]) { - SHA256_CTX c; - SHA256_Init(&c); - SHA256_Update(&c, data, length); - SHA256_Final(out, &c); -} - -std::string GetPartitionGuid(const LpMetadataPartition& partition) { - // 32 hex characters, four hyphens. Unfortunately libext2_uuid provides no - // macro to assist with buffer sizing. - static const size_t kGuidLen = 36; - char buffer[kGuidLen + 1]; - uuid_unparse(partition.guid, buffer); - return buffer; -} - -} // namespace fs_mgr -} // namespace android diff --git a/fs_mgr/liblp/utility.h b/fs_mgr/liblp/utility.h deleted file mode 100644 index dc559eda3..000000000 --- a/fs_mgr/liblp/utility.h +++ /dev/null @@ -1,53 +0,0 @@ -/* - * Copyright (C) 2018 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#ifndef LIBLP_UTILITY_H -#define LIBLP_UTILITY_H - -#include -#include -#include - -#include - -#include "liblp/metadata_format.h" - -#define LP_TAG "[liblp]" -#define LERROR LOG(ERROR) << LP_TAG -#define PERROR PLOG(ERROR) << LP_TAG - -namespace android { -namespace fs_mgr { - -// Determine the size of a block device (or file). Logs and returns false on -// error. After calling this, the position of |fd| may have changed. -bool GetDescriptorSize(int fd, uint64_t* size); - -// Return the offset of a primary metadata slot, relative to the start of the -// device. -off64_t GetPrimaryMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number); - -// Return the offset of a backup metadata slot, relative to the end of the -// device. -off64_t GetBackupMetadataOffset(const LpMetadataGeometry& geometry, uint32_t slot_number); - -// Compute a SHA256 hash. -void SHA256(const void* data, size_t length, uint8_t out[32]); - -} // namespace fs_mgr -} // namespace android - -#endif // LIBLP_UTILITY_H diff --git a/fs_mgr/liblp/writer.cpp b/fs_mgr/liblp/writer.cpp deleted file mode 100644 index aab244a32..000000000 --- a/fs_mgr/liblp/writer.cpp +++ /dev/null @@ -1,244 +0,0 @@ -/* - * Copyright (C) 2007 The Android Open Source Project - * - * Licensed under the Apache License, Version 2.0 (the "License"); - * you may not use this file except in compliance with the License. - * You may obtain a copy of the License at - * - * http://www.apache.org/licenses/LICENSE-2.0 - * - * Unless required by applicable law or agreed to in writing, software - * distributed under the License is distributed on an "AS IS" BASIS, - * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. - * See the License for the specific language governing permissions and - * limitations under the License. - */ - -#include -#include - -#include - -#include -#include - -#include "liblp/reader.h" -#include "liblp/writer.h" -#include "utility.h" - -namespace android { -namespace fs_mgr { - -static std::string SerializeGeometry(const LpMetadataGeometry& input) { - LpMetadataGeometry geometry = input; - memset(geometry.checksum, 0, sizeof(geometry.checksum)); - SHA256(&geometry, sizeof(geometry), geometry.checksum); - return std::string(reinterpret_cast(&geometry), sizeof(geometry)); -} - -static bool CompareGeometry(const LpMetadataGeometry& g1, const LpMetadataGeometry& g2) { - return g1.metadata_max_size == g2.metadata_max_size && - g1.metadata_slot_count == g2.metadata_slot_count && - g1.first_logical_sector == g2.first_logical_sector && - g1.last_logical_sector == g2.last_logical_sector; -} - -static std::string SerializeMetadata(const LpMetadata& input) { - LpMetadata metadata = input; - LpMetadataHeader& header = metadata.header; - - // Serialize individual tables. - std::string partitions(reinterpret_cast(metadata.partitions.data()), - metadata.partitions.size() * sizeof(LpMetadataPartition)); - std::string extents(reinterpret_cast(metadata.extents.data()), - metadata.extents.size() * sizeof(LpMetadataExtent)); - - // Compute positions of tables. - header.partitions.offset = 0; - header.extents.offset = header.partitions.offset + partitions.size(); - header.tables_size = header.extents.offset + extents.size(); - - // Compute payload checksum. - std::string tables = partitions + extents; - SHA256(tables.data(), tables.size(), header.tables_checksum); - - // Compute header checksum. - memset(header.header_checksum, 0, sizeof(header.header_checksum)); - SHA256(&header, sizeof(header), header.header_checksum); - - std::string header_blob = - std::string(reinterpret_cast(&metadata.header), sizeof(metadata.header)); - return header_blob + tables; -} - -// Perform sanity checks so we don't accidentally overwrite valid metadata -// with potentially invalid metadata, or random partition data with metadata. -static bool ValidateGeometryAndMetadata(const LpMetadata& metadata, uint64_t blockdevice_size, - uint64_t metadata_size) { - const LpMetadataHeader& header = metadata.header; - const LpMetadataGeometry& geometry = metadata.geometry; - // Validate the usable sector range. - if (geometry.first_logical_sector > geometry.last_logical_sector) { - LERROR << "Logical partition metadata has invalid sector range."; - return false; - } - // Make sure we're writing within the space reserved. - if (metadata_size > geometry.metadata_max_size) { - LERROR << "Logical partition metadata is too large."; - 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; - if (reserved_size > blockdevice_size || - reserved_size > geometry.first_logical_sector * LP_SECTOR_SIZE) { - LERROR << "Not enough space to store all logical partition metadata slots."; - return false; - } - if (blockdevice_size - reserved_size < (geometry.last_logical_sector + 1) * LP_SECTOR_SIZE) { - LERROR << "Not enough space to backup all logical partition metadata slots."; - return false; - } - - // Make sure all partition entries reference valid extents. - for (const auto& partition : metadata.partitions) { - if (partition.first_extent_index + partition.num_extents > metadata.extents.size()) { - LERROR << "Partition references invalid extent."; - return false; - } - } - - // Make sure all linear extents have a valid range. - for (const auto& extent : metadata.extents) { - if (extent.target_type == LP_TARGET_TYPE_LINEAR) { - uint64_t physical_sector = extent.target_data; - if (physical_sector < geometry.first_logical_sector || - physical_sector + extent.num_sectors > geometry.last_logical_sector) { - LERROR << "Extent table entry is out of bounds."; - return false; - } - } - } - return true; -} - -bool WritePartitionTable(const char* block_device, const LpMetadata& metadata, SyncMode sync_mode, - uint32_t slot_number) { - android::base::unique_fd fd(open(block_device, O_RDWR | O_SYNC)); - if (fd < 0) { - PERROR << __PRETTY_FUNCTION__ << "open failed: " << block_device; - return false; - } - - uint64_t size; - if (!GetDescriptorSize(fd, &size)) { - return false; - } - - const LpMetadataGeometry& geometry = metadata.geometry; - if (sync_mode != SyncMode::Flash) { - // Verify that the old geometry is identical. If it's not, then we've - // based this new metadata on invalid assumptions. - LpMetadataGeometry old_geometry; - if (!ReadLogicalPartitionGeometry(block_device, &old_geometry)) { - return false; - } - if (!CompareGeometry(geometry, old_geometry)) { - LERROR << "Incompatible geometry in new logical partition metadata"; - return false; - } - } - - // Make sure we're writing to a valid metadata slot. - if (slot_number >= geometry.metadata_slot_count) { - LERROR << "Invalid logical partition metadata slot number."; - return false; - } - - // Before writing geometry and/or logical partition tables, perform some - // basic checks that the geometry and tables are coherent, and will fit - // on the given block device. - std::string blob = SerializeMetadata(metadata); - if (!ValidateGeometryAndMetadata(metadata, size, blob.size())) { - return false; - } - - // First write geometry if this is a flash operation. It gets written to - // the first and last 4096-byte regions of the device. - if (sync_mode == SyncMode::Flash) { - std::string blob = SerializeGeometry(metadata.geometry); - if (lseek64(fd, 0, SEEK_SET) == (off64_t)-1) { - PERROR << __PRETTY_FUNCTION__ << "lseek64 failed: offset 0"; - return false; - } - if (!android::base::WriteFully(fd, blob.data(), blob.size())) { - PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() - << " bytes failed: " << block_device; - return false; - } - if (lseek64(fd, -LP_METADATA_GEOMETRY_SIZE, SEEK_END) == (off64_t)-1) { - PERROR << __PRETTY_FUNCTION__ << "lseek64 failed: offset " << -LP_METADATA_GEOMETRY_SIZE; - return false; - } - if (!android::base::WriteFully(fd, blob.data(), blob.size())) { - PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() - << " bytes failed: " << block_device; - return false; - } - } - - // Write the primary copy of the metadata. - off64_t primary_offset = GetPrimaryMetadataOffset(geometry, slot_number); - if (lseek64(fd, primary_offset, SEEK_SET) == (off64_t)-1) { - PERROR << __PRETTY_FUNCTION__ << "lseek64 failed: offset " << primary_offset; - return false; - } - if (!android::base::WriteFully(fd, blob.data(), blob.size())) { - PERROR << __PRETTY_FUNCTION__ << "write " << blob.size() - << " bytes failed: " << block_device; - return false; - } - - // Write the backup copy of the metadata. - off64_t backup_offset = GetBackupMetadataOffset(geometry, slot_number); - off64_t abs_offset = lseek64(fd, backup_offset, SEEK_END); - if (abs_offset == (off64_t)-1) { - PERROR << __PRETTY_FUNCTION__ << "lseek64 failed: offset " << backup_offset; - return false; - } - if (abs_offset < off64_t((geometry.last_logical_sector + 1) * LP_SECTOR_SIZE)) { - PERROR << __PRETTY_FUNCTION__ << "backup offset " << abs_offset - << " is within logical partition bounds, sector " << geometry.last_logical_sector; - return false; - } - if (!android::base::WriteFully(fd, blob.data(), blob.size())) { - PERROR << __PRETTY_FUNCTION__ << "backup write " << blob.size() - << " bytes failed: " << block_device; - return false; - } - return true; -} - -bool WriteToImageFile(const char* file, const LpMetadata& input) { - std::string geometry = SerializeGeometry(input.geometry); - std::string padding(LP_METADATA_GEOMETRY_SIZE - geometry.size(), '\0'); - std::string metadata = SerializeMetadata(input); - - std::string everything = geometry + padding + metadata; - - android::base::unique_fd fd(open(file, O_CREAT | O_RDWR | O_TRUNC, 0644)); - if (fd < 0) { - PERROR << __PRETTY_FUNCTION__ << "open failed: " << file; - return false; - } - if (!android::base::WriteFully(fd, everything.data(), everything.size())) { - PERROR << __PRETTY_FUNCTION__ << "write " << everything.size() << " bytes failed: " << file; - return false; - } - return true; -} - -} // namespace fs_mgr -} // namespace android