blob: eae4200f3484fce551d772e81fc151988de5b64b [file] [log] [blame]
// 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 <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 <brillo/blkdev_utils/loop_device_fake.h>
#include <cryptohome/cryptolib.h>
#include <cryptohome/mock_platform.h>
using ::testing::_;
using ::testing::DoAll;
using ::testing::Return;
using ::testing::SetArgPointee;
namespace cryptohome {
class EncryptedFsTest : public ::testing::Test {
public:
EncryptedFsTest()
: device_mapper_(base::Bind(&brillo::fake::CreateDevmapperTask)) {
CHECK(tmpdir_.CreateUniqueTempDir());
CHECK(base::SetPosixFilePermissions(tmpdir_.GetPath(), 0707));
CHECK(base::CreateDirectory(
tmpdir_.GetPath().AppendASCII("mnt/stateful_partition/")));
CHECK(base::CreateDirectory(tmpdir_.GetPath().AppendASCII("var/")));
CHECK(base::CreateDirectory(tmpdir_.GetPath().AppendASCII("home/chronos")));
// Setup EncryptedFs with temp directory.
encrypted_fs_ = std::make_unique<EncryptedFs>(
tmpdir_.GetPath(), &platform_, &loopdev_manager_, &device_mapper_);
// Setup paths to check.
brillo::SecureBlob digest = cryptohome::CryptoLib::Sha256(
brillo::SecureBlob(tmpdir_.GetPath().value()));
std::string hex = cryptohome::CryptoLib::SecureBlobToHex(digest);
dmcrypt_name_ = "encstateful_" + hex.substr(0, 16);
dmcrypt_device_ = base::FilePath(
base::StringPrintf("/dev/mapper/%s", dmcrypt_name_.c_str()));
mount_point_ = tmpdir_.GetPath().Append("mnt/stateful_partition/encrypted");
// Set encryption key.
brillo::SecureBlob::HexStringToSecureBlob("0123456789ABCDEF", &secret_);
}
MockPlatform platform_;
base::ScopedTempDir tmpdir_;
std::string dmcrypt_name_;
base::FilePath dmcrypt_device_;
base::FilePath loopback_device_;
base::FilePath mount_point_;
brillo::fake::FakeLoopDeviceManager loopdev_manager_;
brillo::DeviceMapper device_mapper_;
brillo::SecureBlob secret_;
std::unique_ptr<EncryptedFs> encrypted_fs_;
};
TEST_F(EncryptedFsTest, RebuildStateful) {
// Platform functions used
EXPECT_CALL(platform_, CreateSparseFile(_, _)).WillOnce(Return(true));
EXPECT_CALL(platform_, FormatExt4(dmcrypt_device_, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, GetBlkSize(_, _))
.WillOnce(DoAll(SetArgPointee<1>(40920000), Return(true)));
EXPECT_CALL(platform_, Mount(dmcrypt_device_, mount_point_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, Bind(_, _)).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(platform_, Unmount(_, _, _))
.Times(3)
.WillRepeatedly(Return(true));
EXPECT_CALL(platform_, Access(_, _)).WillRepeatedly(Return(0));
// Check if dm device is mounted and has the correct key.
EXPECT_EQ(encrypted_fs_->Setup(secret_, true), RESULT_SUCCESS);
EXPECT_EQ(encrypted_fs_->GetKey(), secret_);
// Check if loop device is mounted.
std::unique_ptr<brillo::LoopDevice> loopdev =
loopdev_manager_.GetAttachedDeviceByName(dmcrypt_name_);
EXPECT_TRUE(loopdev->IsValid());
EXPECT_EQ(encrypted_fs_->Teardown(), RESULT_SUCCESS);
EXPECT_EQ(loopdev_manager_.GetAttachedDevices().size(), 0);
}
TEST_F(EncryptedFsTest, OldStateful) {
// Create functions should never be called.
EXPECT_CALL(platform_, CreateSparseFile(_, _)).Times(0);
EXPECT_CALL(platform_, FormatExt4(_, _, _)).Times(0);
EXPECT_CALL(platform_, GetBlkSize(_, _))
.WillOnce(DoAll(SetArgPointee<1>(40920000), Return(true)));
EXPECT_CALL(platform_, Mount(dmcrypt_device_, mount_point_, _, _, _))
.WillOnce(Return(true));
EXPECT_CALL(platform_, Bind(_, _)).Times(2).WillRepeatedly(Return(true));
EXPECT_CALL(platform_, Unmount(_, _, _))
.Times(3)
.WillRepeatedly(Return(true));
EXPECT_CALL(platform_, Access(_, _)).WillRepeatedly(Return(0));
// Expect setup to succeed.
EXPECT_EQ(encrypted_fs_->Setup(secret_, false), RESULT_SUCCESS);
EXPECT_EQ(encrypted_fs_->Teardown(), RESULT_SUCCESS);
}
TEST_F(EncryptedFsTest, LoopdevTeardown) {
// BlkSize == 0 --> Teardown loopdev
EXPECT_CALL(platform_, GetBlkSize(_, _))
.WillOnce(DoAll(SetArgPointee<1>(40920000), Return(true)));
// Expect setup to fail.
EXPECT_EQ(encrypted_fs_->Setup(secret_, false), RESULT_FAIL_FATAL);
// Make sure no loop device is left attached
EXPECT_EQ(loopdev_manager_.GetAttachedDevices().size(), 0);
}
TEST_F(EncryptedFsTest, DevmapperTeardown) {
// Mount failed --> Teardown devmapper
EXPECT_CALL(platform_, GetBlkSize(_, _))
.WillOnce(DoAll(SetArgPointee<1>(40920000), Return(true)));
EXPECT_CALL(platform_, Mount(_, _, _, _, _)).WillOnce(Return(false));
brillo::DevmapperTable empty_table(0, 0, "", brillo::SecureBlob());
// Expect setup to fail.
EXPECT_EQ(encrypted_fs_->Setup(secret_, false), RESULT_FAIL_FATAL);
// Make sure no loop device is left attached.
EXPECT_EQ(loopdev_manager_.GetAttachedDevices().size(), 0);
// Make sure no devmapper device is left.
EXPECT_EQ(device_mapper_.GetTable(dmcrypt_name_).ToSecureBlob(),
empty_table.ToSecureBlob());
}
} // namespace cryptohome