From 9c62b75063fa3af17f401821db77bf71ffb19efb Mon Sep 17 00:00:00 2001 From: David Anderson Date: Mon, 10 Jan 2022 02:41:06 +0000 Subject: [PATCH] libfiemap: Add a helper to verify image fiemaps. Bug: 213646061 Test: gsid verify-image-maps Change-Id: I5a0058142bd196838e989ef16960122b4c8fae6a --- fs_mgr/libfiemap/image_manager.cpp | 110 ++++++++++++++++++ .../include/libfiemap/image_manager.h | 3 + fs_mgr/libfiemap/metadata.h | 5 + 3 files changed, 118 insertions(+) diff --git a/fs_mgr/libfiemap/image_manager.cpp b/fs_mgr/libfiemap/image_manager.cpp index 2c14c8ac0..e3f5716c0 100644 --- a/fs_mgr/libfiemap/image_manager.cpp +++ b/fs_mgr/libfiemap/image_manager.cpp @@ -744,6 +744,116 @@ bool ImageManager::MapAllImages(const std::function)> return CreateLogicalPartitions(*metadata.get(), data_partition_name); } +std::ostream& operator<<(std::ostream& os, android::fs_mgr::Extent* extent) { + if (auto e = extent->AsLinearExtent()) { + return os << "physical_sector() << ", end:" << e->end_sector() + << ", device:" << e->device_index() << ">"; + } + return os << ""; +} + +static bool CompareExtent(android::fs_mgr::Extent* a, android::fs_mgr::Extent* b) { + if (auto linear_a = a->AsLinearExtent()) { + auto linear_b = b->AsLinearExtent(); + if (!linear_b) { + return false; + } + return linear_a->physical_sector() == linear_b->physical_sector() && + linear_a->num_sectors() == linear_b->num_sectors() && + linear_a->device_index() == linear_b->device_index(); + } + return false; +} + +static bool CompareExtents(android::fs_mgr::Partition* oldp, android::fs_mgr::Partition* newp) { + const auto& old_extents = oldp->extents(); + const auto& new_extents = newp->extents(); + + auto old_iter = old_extents.begin(); + auto new_iter = new_extents.begin(); + while (true) { + if (old_iter == old_extents.end()) { + if (new_iter == new_extents.end()) { + break; + } + LOG(ERROR) << "Unexpected extent added: " << (*new_iter); + return false; + } + if (new_iter == new_extents.end()) { + LOG(ERROR) << "Unexpected extent removed: " << (*old_iter); + return false; + } + + if (!CompareExtent(old_iter->get(), new_iter->get())) { + LOG(ERROR) << "Extents do not match: " << old_iter->get() << ", " << new_iter->get(); + return false; + } + + old_iter++; + new_iter++; + } + return true; +} + +bool ImageManager::ValidateImageMaps() { + if (!MetadataExists(metadata_dir_)) { + LOG(INFO) << "ImageManager skipping verification; no images for " << metadata_dir_; + return true; + } + + auto metadata = OpenMetadata(metadata_dir_); + if (!metadata) { + LOG(ERROR) << "ImageManager skipping verification; failed to open " << metadata_dir_; + return true; + } + + for (const auto& partition : metadata->partitions) { + auto name = GetPartitionName(partition); + auto image_path = GetImageHeaderPath(name); + auto fiemap = SplitFiemap::Open(image_path); + if (fiemap == nullptr) { + LOG(ERROR) << "SplitFiemap::Open(\"" << image_path << "\") failed"; + return false; + } + if (!fiemap->HasPinnedExtents()) { + LOG(ERROR) << "Image doesn't have pinned extents: " << image_path; + return false; + } + + android::fs_mgr::PartitionOpener opener; + auto builder = android::fs_mgr::MetadataBuilder::New(*metadata.get(), &opener); + if (!builder) { + LOG(ERROR) << "Could not create metadata builder: " << image_path; + return false; + } + + auto new_p = builder->AddPartition("_temp_for_verify", 0); + if (!new_p) { + LOG(ERROR) << "Could not add temporary partition: " << image_path; + return false; + } + + auto partition_size = android::fs_mgr::GetPartitionSize(*metadata.get(), partition); + if (!FillPartitionExtents(builder.get(), new_p, fiemap.get(), partition_size)) { + LOG(ERROR) << "Could not fill partition extents: " << image_path; + return false; + } + + auto old_p = builder->FindPartition(name); + if (!old_p) { + LOG(ERROR) << "Could not find metadata for " << image_path; + return false; + } + + if (!CompareExtents(old_p, new_p)) { + LOG(ERROR) << "Metadata for " << image_path << " does not match fiemap"; + return false; + } + } + + return true; +} + std::unique_ptr MappedDevice::Open(IImageManager* manager, const std::chrono::milliseconds& timeout_ms, const std::string& name) { diff --git a/fs_mgr/libfiemap/include/libfiemap/image_manager.h b/fs_mgr/libfiemap/include/libfiemap/image_manager.h index 3c8700025..b23a7f79d 100644 --- a/fs_mgr/libfiemap/include/libfiemap/image_manager.h +++ b/fs_mgr/libfiemap/include/libfiemap/image_manager.h @@ -174,6 +174,9 @@ class ImageManager final : public IImageManager { // Writes |bytes| zeros at the beginning of the passed image FiemapStatus ZeroFillNewImage(const std::string& name, uint64_t bytes); + // Validate that all images still have the same block map. + bool ValidateImageMaps(); + private: ImageManager(const std::string& metadata_dir, const std::string& data_dir, const DeviceInfo& device_info); diff --git a/fs_mgr/libfiemap/metadata.h b/fs_mgr/libfiemap/metadata.h index 4eb3ad5c5..30b2c61b1 100644 --- a/fs_mgr/libfiemap/metadata.h +++ b/fs_mgr/libfiemap/metadata.h @@ -20,6 +20,7 @@ #include #include +#include #include namespace android { @@ -34,5 +35,9 @@ bool AddAttributes(const std::string& metadata_dir, const std::string& partition bool RemoveImageMetadata(const std::string& metadata_dir, const std::string& partition_name); bool RemoveAllMetadata(const std::string& dir); +bool FillPartitionExtents(android::fs_mgr::MetadataBuilder* builder, + android::fs_mgr::Partition* partition, android::fiemap::SplitFiemap* file, + uint64_t partition_size); + } // namespace fiemap } // namespace android