| // Copyright 2018 The Chromium OS Authors. All rights reserved. |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include "cryptohome/mount_encrypted/encrypted_fs.h" |
| |
| #include <gmock/gmock.h> |
| #include <gtest/gtest.h> |
| #include <memory> |
| #include <utility> |
| |
| #include <base/files/file_util.h> |
| #include <base/files/scoped_temp_dir.h> |
| #include <base/logging.h> |
| #include <base/strings/string_number_conversions.h> |
| #include <base/strings/stringprintf.h> |
| #include <brillo/blkdev_utils/device_mapper_fake.h> |
| |
| #include "cryptohome/mock_platform.h" |
| #include "cryptohome/storage/encrypted_container/backing_device.h" |
| #include "cryptohome/storage/encrypted_container/dmcrypt_container.h" |
| #include "cryptohome/storage/encrypted_container/encrypted_container.h" |
| #include "cryptohome/storage/encrypted_container/fake_backing_device.h" |
| #include "cryptohome/storage/encrypted_container/filesystem_key.h" |
| |
| using ::testing::_; |
| using ::testing::DoAll; |
| using ::testing::NiceMock; |
| using ::testing::Return; |
| using ::testing::SetArgPointee; |
| |
| namespace mount_encrypted { |
| |
| class EncryptedFsTest : public ::testing::Test { |
| public: |
| EncryptedFsTest() |
| : dmcrypt_name_("encstateful"), |
| dmcrypt_device_(base::FilePath("/dev/mapper/encstateful")), |
| mount_point_(base::FilePath("/mnt/stateful_partition/encrypted")), |
| config_({.backing_device_config = |
| {.type = cryptohome::BackingDeviceType::kLoopbackDevice, |
| .name = "encstateful"}, |
| .dmcrypt_device_name = dmcrypt_name_, |
| .dmcrypt_cipher = "aes-cbc-essiv:sha256", |
| .mkfs_opts = {"-O", "encrypt,verity"}, |
| .tune2fs_opts = {"-Q", "project"}}), |
| device_mapper_(base::Bind(&brillo::fake::CreateDevmapperTask)), |
| fake_backing_device_factory_(&platform_) { |
| // Set up a fake backing device. |
| auto fake_backing_device = |
| fake_backing_device_factory_.Generate(config_.backing_device_config); |
| backing_device_ = fake_backing_device.get(); |
| |
| // Set encryption key. |
| brillo::SecureBlob secret; |
| brillo::SecureBlob::HexStringToSecureBlob("0123456789ABCDEF", &secret); |
| key_.fek = secret; |
| |
| auto container = std::make_unique<cryptohome::DmcryptContainer>( |
| config_, std::move(fake_backing_device), key_reference_, &platform_, |
| std::make_unique<brillo::DeviceMapper>( |
| base::Bind(&brillo::fake::CreateDevmapperTask))); |
| |
| encrypted_fs_ = std::make_unique<EncryptedFs>( |
| base::FilePath("/"), 3UL * 1024 * 1024 * 1024, dmcrypt_name_, |
| std::move(container), &platform_, &device_mapper_); |
| } |
| ~EncryptedFsTest() override = default; |
| |
| void SetUp() override { |
| ASSERT_TRUE( |
| platform_.CreateDirectory(base::FilePath("/mnt/stateful_partition/"))); |
| ASSERT_TRUE(platform_.CreateDirectory(base::FilePath("/var"))); |
| ASSERT_TRUE(platform_.CreateDirectory(base::FilePath("/home/chronos"))); |
| |
| platform_.GetFake()->SetStandardUsersAndGroups(); |
| } |
| |
| void ExpectSetup() { |
| EXPECT_CALL(platform_, StatVFS(_, _)).WillOnce(Return(true)); |
| EXPECT_CALL(platform_, GetBlkSize(_, _)) |
| .WillRepeatedly(DoAll(SetArgPointee<1>(40920000), Return(true))); |
| EXPECT_CALL(platform_, UdevAdmSettle(_, _)).WillOnce(Return(true)); |
| EXPECT_CALL(platform_, Tune2Fs(_, _)).WillOnce(Return(true)); |
| EXPECT_CALL(platform_, Access(_, _)).WillRepeatedly(Return(0)); |
| } |
| |
| void ExpectCreate() { |
| EXPECT_CALL(platform_, FormatExt4(dmcrypt_device_, _, _)) |
| .WillOnce(Return(true)); |
| } |
| |
| void ExpectMount() { |
| EXPECT_CALL(platform_, Mount(dmcrypt_device_, mount_point_, _, _, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(platform_, Bind(_, _, _, false)) |
| .Times(2) |
| .WillRepeatedly(Return(true)); |
| } |
| |
| void ExpectUnmount() { |
| EXPECT_CALL(platform_, Unmount(_, _, _)) |
| .Times(3) |
| .WillRepeatedly(Return(true)); |
| } |
| |
| protected: |
| const std::string dmcrypt_name_; |
| const base::FilePath dmcrypt_device_; |
| const base::FilePath mount_point_; |
| cryptohome::DmcryptConfig config_; |
| |
| NiceMock<cryptohome::MockPlatform> platform_; |
| brillo::DeviceMapper device_mapper_; |
| cryptohome::FakeBackingDeviceFactory fake_backing_device_factory_; |
| cryptohome::FileSystemKey key_; |
| cryptohome::FileSystemKeyReference key_reference_; |
| cryptohome::BackingDevice* backing_device_; |
| std::unique_ptr<EncryptedFs> encrypted_fs_; |
| }; |
| |
| TEST_F(EncryptedFsTest, RebuildStateful) { |
| ExpectSetup(); |
| ExpectCreate(); |
| ExpectMount(); |
| ExpectUnmount(); |
| |
| // Check if dm device is mounted and has the correct key. |
| EXPECT_EQ(encrypted_fs_->Setup(key_, true), RESULT_SUCCESS); |
| |
| // Check that the dm-crypt device is created and has the correct key. |
| EXPECT_EQ(encrypted_fs_->GetKey(), key_.fek); |
| // Check if backing device is attached. |
| EXPECT_EQ(backing_device_->GetPath(), base::FilePath("/dev/encstateful")); |
| |
| EXPECT_EQ(encrypted_fs_->Teardown(), RESULT_SUCCESS); |
| |
| // Make sure no devmapper device is left. |
| EXPECT_EQ(device_mapper_.GetTable(dmcrypt_name_).CryptGetKey(), |
| brillo::SecureBlob()); |
| // Check if backing device is not attached. |
| EXPECT_EQ(backing_device_->GetPath(), base::nullopt); |
| } |
| |
| TEST_F(EncryptedFsTest, OldStateful) { |
| ExpectSetup(); |
| ExpectMount(); |
| ExpectUnmount(); |
| |
| // Create the fake backing device. |
| ASSERT_TRUE(backing_device_->Create()); |
| |
| // Expect setup to succeed. |
| EXPECT_EQ(encrypted_fs_->Setup(key_, false), RESULT_SUCCESS); |
| // Check that the dm-crypt device is created and has the correct key. |
| EXPECT_EQ(encrypted_fs_->GetKey(), key_.fek); |
| // Check if backing device is attached. |
| EXPECT_EQ(backing_device_->GetPath(), base::FilePath("/dev/encstateful")); |
| |
| EXPECT_EQ(encrypted_fs_->Teardown(), RESULT_SUCCESS); |
| // Make sure no devmapper device is left. |
| EXPECT_EQ(device_mapper_.GetTable(dmcrypt_name_).CryptGetKey(), |
| brillo::SecureBlob()); |
| // Check if backing device is not attached. |
| EXPECT_EQ(backing_device_->GetPath(), base::nullopt); |
| } |
| |
| TEST_F(EncryptedFsTest, LoopdevTeardown) { |
| // BlkSize == 0 --> Teardown loopdev |
| EXPECT_CALL(platform_, GetBlkSize(_, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(0), Return(true))); |
| |
| // Create the fake backing device. |
| ASSERT_TRUE(backing_device_->Create()); |
| // Expect setup to fail. |
| EXPECT_EQ(encrypted_fs_->Setup(key_, false), RESULT_FAIL_FATAL); |
| // Make sure that the backing device is not left attached. |
| EXPECT_EQ(backing_device_->GetPath(), base::nullopt); |
| } |
| |
| TEST_F(EncryptedFsTest, DevmapperTeardown) { |
| // Mount failed --> Teardown devmapper |
| ExpectSetup(); |
| EXPECT_CALL(platform_, Mount(_, _, _, _, _)).WillOnce(Return(false)); |
| |
| // Create the fake backing device. |
| ASSERT_TRUE(backing_device_->Create()); |
| // Expect setup to fail. |
| EXPECT_EQ(encrypted_fs_->Setup(key_, false), RESULT_FAIL_FATAL); |
| // Make sure that the backing device is no left attached. |
| EXPECT_EQ(backing_device_->GetPath(), base::nullopt); |
| } |
| |
| } // namespace mount_encrypted |