diff options
author | Paul Lawrence <paullawrence@google.com> | 2019-06-25 14:36:52 -0700 |
---|---|---|
committer | Paul Lawrence <paullawrence@google.com> | 2019-06-27 17:42:51 +0000 |
commit | d3aee48096dde6fd08bafc9ddb13618bec389996 (patch) | |
tree | eedfd029916a186129cfccbf507ef3a998c6e58c | |
parent | 64e64eb990cf9444ed8a38f96a32a3e7266d2984 (diff) | |
download | core-d3aee48096dde6fd08bafc9ddb13618bec389996.tar.gz |
Make ext4 userdata checkpoints work with metadata encryption
When both ext4 user data checkpoints and metadata encryption are
enabled, we are creating two stacked dm devices. This had not been
properly thought through or debugged.
Test: Enable metadata encryption on taimen (add
keydirectory=/metadata/vold/metadata_encryption to flags for userdata in
fstab.hardware)
Unfortunately metadata is not wiped by fastboot -w, so it is
necessary to rm metadata/vold -rf whenever you wipe data.
fastboot flashall -w works
fastboot reboot -w works
A normal boot works
Disable checkpoint commits with
setprop persist.vold.dont_commit_checkpoint 1
vdc checkpoint startCheckpoint 10
adb reboot
wait for device to fully boot then
adb reboot
Wait for device to fully boot then
adb logcat -d | grep Checkpoint shows the rollback in the logs
This tests encryption on top of checkpoints with commit, encryption
without checkpoints, and rollback, which seems to be the key cases.
Also ran same tests on unmodified Taimen and Blueline
Bug: 135905679
Merged-In: I24387a2943dce28b918c34894f24911b20429be7
Change-Id: I24387a2943dce28b918c34894f24911b20429be7
-rw-r--r-- | fs_mgr/fs_mgr.cpp | 118 | ||||
-rw-r--r-- | fs_mgr/include/fs_mgr.h | 4 |
2 files changed, 88 insertions, 34 deletions
diff --git a/fs_mgr/fs_mgr.cpp b/fs_mgr/fs_mgr.cpp index 3ea479e79..f1ce1254a 100644 --- a/fs_mgr/fs_mgr.cpp +++ b/fs_mgr/fs_mgr.cpp @@ -923,7 +923,7 @@ class CheckpointManager { public: CheckpointManager(int needs_checkpoint = -1) : needs_checkpoint_(needs_checkpoint) {} - bool Update(FstabEntry* entry) { + bool Update(FstabEntry* entry, const std::string& block_device = std::string()) { if (!entry->fs_mgr_flags.checkpoint_blk && !entry->fs_mgr_flags.checkpoint_fs) { return true; } @@ -942,7 +942,7 @@ class CheckpointManager { return true; } - if (!UpdateCheckpointPartition(entry)) { + if (!UpdateCheckpointPartition(entry, block_device)) { LERROR << "Could not set up checkpoint partition, skipping!"; return false; } @@ -972,7 +972,7 @@ class CheckpointManager { } private: - bool UpdateCheckpointPartition(FstabEntry* entry) { + bool UpdateCheckpointPartition(FstabEntry* entry, const std::string& block_device) { if (entry->fs_mgr_flags.checkpoint_fs) { if (is_f2fs(entry->fs_type)) { entry->fs_options += ",checkpoint=disable"; @@ -980,39 +980,43 @@ class CheckpointManager { LERROR << entry->fs_type << " does not implement checkpoints."; } } else if (entry->fs_mgr_flags.checkpoint_blk) { - unique_fd fd(TEMP_FAILURE_RETRY(open(entry->blk_device.c_str(), O_RDONLY | O_CLOEXEC))); - if (fd < 0) { - PERROR << "Cannot open device " << entry->blk_device; - return false; - } + auto actual_block_device = block_device.empty() ? entry->blk_device : block_device; + if (fs_mgr_find_bow_device(actual_block_device).empty()) { + unique_fd fd( + TEMP_FAILURE_RETRY(open(entry->blk_device.c_str(), O_RDONLY | O_CLOEXEC))); + if (fd < 0) { + PERROR << "Cannot open device " << entry->blk_device; + return false; + } - uint64_t size = get_block_device_size(fd) / 512; - if (!size) { - PERROR << "Cannot get device size"; - return false; - } + uint64_t size = get_block_device_size(fd) / 512; + if (!size) { + PERROR << "Cannot get device size"; + return false; + } - android::dm::DmTable table; - if (!table.AddTarget( - std::make_unique<android::dm::DmTargetBow>(0, size, entry->blk_device))) { - LERROR << "Failed to add bow target"; - return false; - } + android::dm::DmTable table; + if (!table.AddTarget(std::make_unique<android::dm::DmTargetBow>( + 0, size, entry->blk_device))) { + LERROR << "Failed to add bow target"; + return false; + } - DeviceMapper& dm = DeviceMapper::Instance(); - if (!dm.CreateDevice("bow", table)) { - PERROR << "Failed to create bow device"; - return false; - } + DeviceMapper& dm = DeviceMapper::Instance(); + if (!dm.CreateDevice("bow", table)) { + PERROR << "Failed to create bow device"; + return false; + } - std::string name; - if (!dm.GetDmDevicePathByName("bow", &name)) { - PERROR << "Failed to get bow device name"; - return false; - } + std::string name; + if (!dm.GetDmDevicePathByName("bow", &name)) { + PERROR << "Failed to get bow device name"; + return false; + } - device_map_[name] = entry->blk_device; - entry->blk_device = name; + device_map_[name] = entry->blk_device; + entry->blk_device = name; + } } return true; } @@ -1022,6 +1026,50 @@ class CheckpointManager { std::map<std::string, std::string> device_map_; }; +std::string fs_mgr_find_bow_device(const std::string& block_device) { + if (block_device.substr(0, 5) != "/dev/") { + LOG(ERROR) << "Expected block device, got " << block_device; + return std::string(); + } + + std::string sys_dir = std::string("/sys/") + block_device.substr(5); + + for (;;) { + std::string name; + if (!android::base::ReadFileToString(sys_dir + "/dm/name", &name)) { + PLOG(ERROR) << block_device << " is not dm device"; + return std::string(); + } + + if (name == "bow\n") return sys_dir; + + std::string slaves = sys_dir + "/slaves"; + std::unique_ptr<DIR, decltype(&closedir)> directory(opendir(slaves.c_str()), closedir); + if (!directory) { + PLOG(ERROR) << "Can't open slave directory " << slaves; + return std::string(); + } + + int count = 0; + for (dirent* entry = readdir(directory.get()); entry; entry = readdir(directory.get())) { + if (entry->d_type != DT_LNK) continue; + + if (count == 1) { + LOG(ERROR) << "Too many slaves in " << slaves; + return std::string(); + } + + ++count; + sys_dir = std::string("/sys/block/") + entry->d_name; + } + + if (count != 1) { + LOG(ERROR) << "No slave in " << slaves; + return std::string(); + } + } +} + static bool IsMountPointMounted(const std::string& mount_point) { // Check if this is already mounted. Fstab fstab; @@ -1160,7 +1208,8 @@ int fs_mgr_mount_all(Fstab* fstab, int mount_mode) { } encryptable = status; if (status == FS_MGR_MNTALL_DEV_NEEDS_METADATA_ENCRYPTION) { - if (!call_vdc({"cryptfs", "encryptFstab", attempted_entry.mount_point})) { + if (!call_vdc({"cryptfs", "encryptFstab", attempted_entry.blk_device, + attempted_entry.mount_point})) { LERROR << "Encryption failed"; return FS_MGR_MNTALL_FAIL; } @@ -1231,7 +1280,8 @@ int fs_mgr_mount_all(Fstab* fstab, int mount_mode) { encryptable = FS_MGR_MNTALL_DEV_MIGHT_BE_ENCRYPTED; } else if (mount_errno != EBUSY && mount_errno != EACCES && should_use_metadata_encryption(attempted_entry)) { - if (!call_vdc({"cryptfs", "mountFstab", attempted_entry.mount_point})) { + if (!call_vdc({"cryptfs", "mountFstab", attempted_entry.blk_device, + attempted_entry.mount_point})) { ++error_count; } encryptable = FS_MGR_MNTALL_DEV_IS_METADATA_ENCRYPTED; @@ -1361,7 +1411,7 @@ static int fs_mgr_do_mount_helper(Fstab* fstab, const std::string& n_name, } } - if (!checkpoint_manager.Update(&fstab_entry)) { + if (!checkpoint_manager.Update(&fstab_entry, n_blk_device)) { LERROR << "Could not set up checkpoint partition, skipping!"; continue; } diff --git a/fs_mgr/include/fs_mgr.h b/fs_mgr/include/fs_mgr.h index 88b2f8f4f..bdec7bee5 100644 --- a/fs_mgr/include/fs_mgr.h +++ b/fs_mgr/include/fs_mgr.h @@ -104,3 +104,7 @@ enum FsMgrUmountStatus : int { // fs_mgr_umount_all() is the reverse of fs_mgr_mount_all. In particular, // it destroys verity devices from device mapper after the device is unmounted. int fs_mgr_umount_all(android::fs_mgr::Fstab* fstab); + +// Finds the dm_bow device on which this block device is stacked, or returns +// empty string +std::string fs_mgr_find_bow_device(const std::string& block_device); |