From 1bfcd580c8cca48e0202129281581ec3865fbbda Mon Sep 17 00:00:00 2001 From: David Anderson Date: Wed, 19 Jun 2019 19:03:28 -0700 Subject: [PATCH] libfiemap_writer: Improve device unwrapping to support simple linear devices. Normally we reject complex dm targets that would invalidate or shift the block mappings returned via FIEMAP/FIBMAP. Currently the only targets allowed are crypt, default-key, and bow. This patch adds support for "linear" as long as there is only one linear target and it targets sector 0 of the underlying block device. This is useful for testing gsid, so we can simulate how a metadata-encrypted device works without having to create a dm-crypt or dm-default-key node. Bug: 134536978 Test: manual test Change-Id: I7c12bc20d95ff4c90402e66bafb4cf2fce7818e2 --- fs_mgr/libdm/dm.cpp | 8 ++++++ fs_mgr/libdm/dm_test.cpp | 4 +++ fs_mgr/libdm/include/libdm/dm.h | 2 ++ fs_mgr/libfiemap_writer/fiemap_writer.cpp | 35 +++++++++++++++++------ 4 files changed, 40 insertions(+), 9 deletions(-) diff --git a/fs_mgr/libdm/dm.cpp b/fs_mgr/libdm/dm.cpp index c2917a4b0..d3c0c1f6f 100644 --- a/fs_mgr/libdm/dm.cpp +++ b/fs_mgr/libdm/dm.cpp @@ -368,5 +368,13 @@ void DeviceMapper::InitIo(struct dm_ioctl* io, const std::string& name) const { } } +std::string DeviceMapper::GetTargetType(const struct dm_target_spec& spec) { + if (const void* p = memchr(spec.target_type, '\0', sizeof(spec.target_type))) { + ptrdiff_t length = reinterpret_cast(p) - spec.target_type; + return std::string{spec.target_type, static_cast(length)}; + } + return std::string{spec.target_type, sizeof(spec.target_type)}; +} + } // namespace dm } // namespace android diff --git a/fs_mgr/libdm/dm_test.cpp b/fs_mgr/libdm/dm_test.cpp index dc47c33b0..2bf564310 100644 --- a/fs_mgr/libdm/dm_test.cpp +++ b/fs_mgr/libdm/dm_test.cpp @@ -170,6 +170,10 @@ TEST(libdm, DmLinear) { EXPECT_EQ(targets[1].spec.sector_start, 1); EXPECT_EQ(targets[1].spec.length, 1); + // Test GetTargetType(). + EXPECT_EQ(DeviceMapper::GetTargetType(targets[0].spec), std::string{"linear"}); + EXPECT_EQ(DeviceMapper::GetTargetType(targets[1].spec), std::string{"linear"}); + // Normally the TestDevice destructor would delete this, but at least one // test should ensure that device deletion works. ASSERT_TRUE(dev.Destroy()); diff --git a/fs_mgr/libdm/include/libdm/dm.h b/fs_mgr/libdm/include/libdm/dm.h index d7e8aa91c..fe736a3c1 100644 --- a/fs_mgr/libdm/include/libdm/dm.h +++ b/fs_mgr/libdm/include/libdm/dm.h @@ -136,6 +136,8 @@ class DeviceMapper final { // mapper device from the kernel. bool GetTableInfo(const std::string& name, std::vector* table); + static std::string GetTargetType(const struct dm_target_spec& spec); + private: // Maximum possible device mapper targets registered in the kernel. // This is only used to read the list of targets from kernel so we allocate diff --git a/fs_mgr/libfiemap_writer/fiemap_writer.cpp b/fs_mgr/libfiemap_writer/fiemap_writer.cpp index f06443644..0a3ba6c24 100644 --- a/fs_mgr/libfiemap_writer/fiemap_writer.cpp +++ b/fs_mgr/libfiemap_writer/fiemap_writer.cpp @@ -89,6 +89,31 @@ static bool BlockDeviceToName(uint32_t major, uint32_t minor, std::string* bdev_ return true; } +static bool ValidateDmTarget(const DeviceMapper::TargetInfo& target) { + const auto& entry = target.spec; + if (entry.sector_start != 0) { + LOG(INFO) << "Stopping at target with non-zero starting sector"; + return false; + } + + auto target_type = DeviceMapper::GetTargetType(entry); + if (target_type == "bow" || target_type == "default-key" || target_type == "crypt") { + return true; + } + if (target_type == "linear") { + auto pieces = android::base::Split(target.data, " "); + if (pieces[1] != "0") { + LOG(INFO) << "Stopping at complex linear target with non-zero starting sector: " + << pieces[1]; + return false; + } + return true; + } + + LOG(INFO) << "Stopping at complex target type " << target_type; + return false; +} + static bool DeviceMapperStackPop(const std::string& bdev, std::string* bdev_raw) { *bdev_raw = bdev; @@ -128,15 +153,7 @@ static bool DeviceMapperStackPop(const std::string& bdev, std::string* bdev_raw) LOG(INFO) << "Stopping at complex table for " << dm_name << " at " << bdev; return true; } - const auto& entry = table[0].spec; - std::string target_type(std::string(entry.target_type, sizeof(entry.target_type)).c_str()); - if (target_type != "bow" && target_type != "default-key" && target_type != "crypt") { - LOG(INFO) << "Stopping at complex target-type " << target_type << " for " << dm_name - << " at " << bdev; - return true; - } - if (entry.sector_start != 0) { - LOG(INFO) << "Stopping at target-type with non-zero starting sector"; + if (!ValidateDmTarget(table[0])) { return true; }