| // Copyright 2022 The ChromiumOS Authors |
| // Use of this source code is governed by a BSD-style license that can be |
| // found in the LICENSE file. |
| |
| #include <stdlib.h> |
| #include <sys/sysmacros.h> |
| #include <sys/types.h> |
| |
| #include <deque> |
| #include <set> |
| #include <string> |
| #include <utility> |
| #include <vector> |
| |
| #include <base/files/file_enumerator.h> |
| #include <base/files/file_util.h> |
| #include <base/logging.h> |
| #include <base/strings/string_split.h> |
| #include <base/strings/string_util.h> |
| #include <base/values.h> |
| #include <gtest/gtest.h> |
| #include <libcrossystem/crossystem_fake.h> |
| #include <libstorage/platform/fake_platform.h> |
| #include <libstorage/platform/mock_platform.h> |
| #include <libhwsec-foundation/tlcl_wrapper/mock_tlcl_wrapper.h> |
| #include <vpd/fake_vpd.h> |
| |
| #include "init/startup/chromeos_startup.h" |
| #include "init/startup/constants.h" |
| #include "init/startup/factory_mode_mount_helper.h" |
| #include "init/startup/fake_startup_dep_impl.h" |
| #include "init/startup/flags.h" |
| #include "init/startup/mount_helper.h" |
| #include "init/startup/mount_helper_factory.h" |
| #include "init/startup/standard_mount_helper.h" |
| #include "init/startup/test_mode_mount_helper.h" |
| |
| using testing::_; |
| using testing::AnyNumber; |
| using testing::ByMove; |
| using testing::DoAll; |
| using testing::HasSubstr; |
| using testing::Return; |
| using testing::SetArgPointee; |
| using testing::StrictMock; |
| |
| namespace startup { |
| |
| namespace { |
| |
| constexpr char kTpmFirmwareUpdateCleanup[] = |
| "usr/sbin/tpm-firmware-update-cleanup"; |
| constexpr char kTpmFirmwareUpdateRequestFlagFile[] = |
| "unencrypted/preserve/tpm_firmware_update_request"; |
| constexpr char kLsbRelease[] = "etc/lsb-release"; |
| constexpr char kStatefulPartition[] = "mnt/stateful_partition"; |
| constexpr char kProcCmdLine[] = "proc/cmdline"; |
| constexpr char kSysKeyLog[] = "run/chromeos_startup/create_system_key.log"; |
| constexpr char kMntOptionsFile[] = |
| "dev_image/factory/init/encstateful_mount_option"; |
| constexpr char kLSMDir[] = |
| "sys/kernel/security/chromiumos/inode_security_policies"; |
| |
| void RestoreconTestFunc(libstorage::Platform* platform, |
| const base::FilePath& path, |
| const std::vector<base::FilePath>& exclude, |
| bool is_recursive, |
| bool set_digests) { |
| for (auto excl : exclude) { |
| base::FilePath ex_file = excl.Append("exclude"); |
| platform->WriteStringToFile(ex_file, "exclude"); |
| } |
| base::FilePath restore = path.Append("restore"); |
| platform->WriteStringToFile(restore, "restore"); |
| } |
| |
| } // namespace |
| |
| class EarlySetupTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| kernel_debug_ = base_dir_.Append("sys/kernel/debug"); |
| kernel_config_ = base_dir_.Append("sys/kernel/config"); |
| kernel_tracing_ = base_dir_.Append("sys/kernel/tracing"); |
| security_hardening_ = base_dir_.Append( |
| "usr/share/cros/startup/disable_stateful_security_hardening"); |
| kernel_security_ = base_dir_.Append("sys/kernel/security"); |
| fs_bpf_ = base_dir_.Append("sys/fs/bpf"); |
| namespaces_ = base_dir_.Append("run/namespaces"); |
| platform_ = std::make_unique<libstorage::MockPlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::unique_ptr<vpd::Vpd>(), flags_, base_dir_, base_dir_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| } |
| |
| startup::Flags flags_{}; |
| std::unique_ptr<libstorage::MockPlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| base::FilePath base_dir_{"/"}; |
| base::FilePath kernel_debug_; |
| base::FilePath kernel_tracing_; |
| base::FilePath dev_pts_; |
| base::FilePath dev_shm_; |
| base::FilePath kernel_config_; |
| base::FilePath security_hardening_; |
| base::FilePath kernel_security_; |
| base::FilePath fs_bpf_; |
| base::FilePath namespaces_; |
| }; |
| |
| TEST_F(EarlySetupTest, EarlySetup) { |
| // Part of the root image. |
| ASSERT_TRUE(platform_->CreateDirectory(kernel_config_)); |
| |
| // Check all the mounts happen. |
| EXPECT_CALL(*platform_, |
| Mount(base::FilePath(), kernel_debug_, "debugfs", _, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, |
| Mount(base::FilePath(), kernel_tracing_, "tracefs", _, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, |
| Mount(base::FilePath(), kernel_config_, "configfs", _, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, |
| Mount(base::FilePath(), kernel_security_, "securityfs", _, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, Mount(base::FilePath(), fs_bpf_, "bpf", _, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, Mount(namespaces_, namespaces_, "", MS_BIND, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, |
| Mount(base::FilePath(), namespaces_, "", MS_PRIVATE, _)) |
| .WillOnce(Return(true)); |
| |
| startup_->EarlySetup(); |
| } |
| |
| class DevCheckBlockTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| auto vpd_fake = std::make_unique<vpd::FakeVpd>(); |
| vpd_ = vpd_fake.get(); |
| dev_mode_file = base_dir_.Append(".developer_mode"); |
| platform_ = std::make_unique<libstorage::FakePlatform>(); |
| crossystem_ = platform_->GetCrosssystem(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(std::move(vpd_fake)), flags_, base_dir_, |
| base_dir_, base_dir_, platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("cros_debug", 1)); |
| platform_->CreateDirectory(dev_mode_file.DirName()); |
| startup_->SetDevMode(true); |
| } |
| |
| crossystem::Crossystem* crossystem_; |
| vpd::FakeVpd* vpd_; |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| base::FilePath dev_mode_file; |
| std::unique_ptr<libstorage::FakePlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| }; |
| |
| TEST_F(DevCheckBlockTest, DevSWBoot) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("devsw_boot", 0)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("debug_build", 0)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("recovery_reason", 0)); |
| ASSERT_TRUE(vpd_->WriteValues(vpd::VpdRw, {{"block_devmode", "1"}})); |
| |
| startup_->DevCheckBlockDevMode(dev_mode_file); |
| EXPECT_FALSE(platform_->FileExists(dev_mode_file)); |
| } |
| |
| TEST_F(DevCheckBlockTest, VpdCrosSysBlockDev) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("devsw_boot", 1)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("debug_build", 0)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("recovery_reason", 0)); |
| ASSERT_TRUE(vpd_->WriteValues(vpd::VpdRw, {{"block_devmode", "0"}})); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("block_devmode", 1)); |
| |
| startup_->DevCheckBlockDevMode(dev_mode_file); |
| EXPECT_TRUE(platform_->FileExists(dev_mode_file)); |
| } |
| |
| TEST_F(DevCheckBlockTest, CrosSysBlockDev) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("devsw_boot", 1)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("debug_build", 0)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("recovery_reason", 0)); |
| // No "block_devmode" in VPD. |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("block_devmode", 1)); |
| |
| startup_->DevCheckBlockDevMode(dev_mode_file); |
| EXPECT_TRUE(platform_->FileExists(dev_mode_file)); |
| } |
| |
| class TPMTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| platform_ = std::make_unique<libstorage::MockPlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(), flags_, base_dir_, base_dir_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| } |
| |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| std::unique_ptr<libstorage::MockPlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| }; |
| |
| TEST_F(TPMTest, OwnedTrue) { |
| EXPECT_CALL(*tlcl_, Init()).WillOnce(Return(0)); |
| EXPECT_CALL(*tlcl_, GetOwnership(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(true), Return(0))); |
| EXPECT_CALL(*tlcl_, Close()).WillOnce(Return(0)); |
| EXPECT_TRUE(startup_->IsTPMOwned()); |
| } |
| |
| TEST_F(TPMTest, OwnedFalse) { |
| EXPECT_CALL(*tlcl_, Init()).WillOnce(Return(0)); |
| EXPECT_CALL(*tlcl_, GetOwnership(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(false), Return(0))); |
| EXPECT_CALL(*tlcl_, Close()).WillOnce(Return(0)); |
| EXPECT_FALSE(startup_->IsTPMOwned()); |
| } |
| |
| TEST_F(TPMTest, OwnedUnknown) { |
| EXPECT_CALL(*tlcl_, Init()).WillOnce(Return(0)); |
| EXPECT_CALL(*tlcl_, GetOwnership(_)).WillOnce(Return(1)); |
| EXPECT_CALL(*tlcl_, Close()).WillOnce(Return(0)); |
| EXPECT_TRUE(startup_->IsTPMOwned()); |
| } |
| |
| TEST_F(TPMTest, NeedsClobberTPMOwned) { |
| EXPECT_CALL(*tlcl_, Init()).WillOnce(Return(0)); |
| EXPECT_CALL(*tlcl_, GetOwnership(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(true), Return(0))); |
| EXPECT_CALL(*tlcl_, Close()).WillOnce(Return(0)); |
| EXPECT_FALSE(startup_->NeedsClobberWithoutDevModeFile()); |
| } |
| |
| TEST_F(TPMTest, NeedsClobberTPMNotOwnedEmptyDisk) { |
| EXPECT_CALL(*tlcl_, Init()).WillOnce(Return(0)); |
| EXPECT_CALL(*tlcl_, GetOwnership(_)) |
| .WillOnce(DoAll(SetArgPointee<0>(false), Return(0))); |
| EXPECT_CALL(*tlcl_, Close()).WillOnce(Return(0)); |
| EXPECT_FALSE(startup_->NeedsClobberWithoutDevModeFile()); |
| } |
| |
| #if !USE_TPM2 |
| |
| TEST_F(TPMTest, NeedsClobberPreservationFile) { |
| LOG(INFO) << "test getuid " << getuid(); |
| EXPECT_CALL(*tlcl_, Init()).WillRepeatedly(Return(0)); |
| EXPECT_CALL(*tlcl_, GetOwnership(_)) |
| .WillRepeatedly(DoAll(SetArgPointee<0>(false), Return(0))); |
| EXPECT_CALL(*tlcl_, Close()).WillRepeatedly(Return(0)); |
| EXPECT_FALSE(startup_->IsTPMOwned()); |
| base::FilePath preservation_file = base_dir_.Append("preservation_request"); |
| ASSERT_TRUE(platform_->WriteStringToFile(preservation_file, "0")); |
| EXPECT_CALL(*platform_, GetOwnership(preservation_file, _, nullptr, false)) |
| .WillOnce(DoAll(SetArgPointee<1>(getuid()), Return(true))); |
| base::FilePath cryptohome_key_file = |
| base_dir_.Append("home/.shadow/cryptohome.key"); |
| ASSERT_TRUE(platform_->WriteStringToFile(cryptohome_key_file, "0")); |
| EXPECT_FALSE(startup_->NeedsClobberWithoutDevModeFile()); |
| } |
| |
| TEST_F(TPMTest, NeedsClobberPreservationFileWrongerUid) { |
| LOG(INFO) << "test getuid " << getuid(); |
| EXPECT_CALL(*tlcl_, Init()).WillRepeatedly(Return(0)); |
| EXPECT_CALL(*tlcl_, GetOwnership(_)) |
| .WillRepeatedly(DoAll(SetArgPointee<0>(false), Return(0))); |
| EXPECT_CALL(*tlcl_, Close()).WillRepeatedly(Return(0)); |
| EXPECT_FALSE(startup_->IsTPMOwned()); |
| base::FilePath preservation_file = base_dir_.Append("preservation_request"); |
| ASSERT_TRUE(platform_->WriteStringToFile(preservation_file, "0")); |
| EXPECT_CALL(*platform_, GetOwnership(preservation_file, _, nullptr, false)) |
| .WillOnce(DoAll(SetArgPointee<1>(-1), Return(true))); |
| base::FilePath cryptohome_key_file = |
| base_dir_.Append("home/.shadow/cryptohome.key"); |
| ASSERT_TRUE(platform_->WriteStringToFile(cryptohome_key_file, "0")); |
| EXPECT_TRUE(startup_->NeedsClobberWithoutDevModeFile()); |
| } |
| |
| #endif // !USE_TPM2 |
| |
| TEST_F(TPMTest, NeedsClobberCryptohomeKeyFile) { |
| LOG(INFO) << "test getuid " << getuid(); |
| EXPECT_CALL(*tlcl_, Init()).WillRepeatedly(Return(0)); |
| EXPECT_CALL(*tlcl_, GetOwnership(_)) |
| .WillRepeatedly(DoAll(SetArgPointee<0>(false), Return(0))); |
| EXPECT_CALL(*tlcl_, Close()).WillRepeatedly(Return(0)); |
| EXPECT_FALSE(startup_->IsTPMOwned()); |
| base::FilePath cryptohome_key_file = |
| base_dir_.Append("home/.shadow/cryptohome.key"); |
| ASSERT_TRUE(platform_->WriteStringToFile(cryptohome_key_file, "0")); |
| EXPECT_TRUE(startup_->NeedsClobberWithoutDevModeFile()); |
| } |
| |
| TEST_F(TPMTest, NeedsClobberNeedFinalization) { |
| LOG(INFO) << "test getuid " << getuid(); |
| EXPECT_CALL(*tlcl_, Init()).WillRepeatedly(Return(0)); |
| EXPECT_CALL(*tlcl_, GetOwnership(_)) |
| .WillRepeatedly(DoAll(SetArgPointee<0>(false), Return(0))); |
| EXPECT_CALL(*tlcl_, Close()).WillRepeatedly(Return(0)); |
| EXPECT_FALSE(startup_->IsTPMOwned()); |
| base::FilePath need_finalization_file = |
| base_dir_.Append("encrypted.needs-finalization"); |
| ASSERT_TRUE(platform_->WriteStringToFile(need_finalization_file, "0")); |
| EXPECT_TRUE(startup_->NeedsClobberWithoutDevModeFile()); |
| } |
| |
| TEST_F(TPMTest, PcrExtended) { |
| bool needs_extend = (!USE_TPM_INSECURE_FALLBACK) && USE_TPM2; |
| if (needs_extend) { |
| constexpr int kPcrNum = 13; |
| constexpr uint8_t kExpectedHash[] = {41, 159, 195, 247, 59, 231, 174, 233, |
| 48, 192, 33, 135, 113, 201, 177, 10, |
| 181, 241, 127, 20, 155, 7, 115, 37, |
| 163, 95, 217, 115, 174, 118, 14, 67}; |
| base::FilePath cmdline_path = base_dir_.Append(kProcCmdLine); |
| ASSERT_TRUE( |
| platform_->WriteStringToFile(cmdline_path, "TEST_LSB_CONTENT=true")); |
| |
| EXPECT_CALL(*tlcl_, Init()).WillOnce(Return(0)); |
| EXPECT_CALL(*tlcl_, Extend(kPcrNum, |
| std::vector<uint8_t>( |
| kExpectedHash, |
| kExpectedHash + sizeof(kExpectedHash)), |
| _)) |
| .WillOnce(Return(0)); |
| EXPECT_CALL(*tlcl_, Close()).WillOnce(Return(0)); |
| } else { |
| EXPECT_CALL(*tlcl_, Init()).Times(0); |
| EXPECT_CALL(*tlcl_, Extend(_, _, _)).Times(0); |
| EXPECT_CALL(*tlcl_, Close()).Times(0); |
| } |
| |
| EXPECT_TRUE(startup_->ExtendPCRForVersionAttestation()); |
| } |
| |
| class StatefulWipeTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| stateful_ = base_dir_.Append("mnt/stateful_partition"); |
| platform_ = std::make_unique<libstorage::FakePlatform>(); |
| crossystem_ = platform_->GetCrosssystem(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(), flags_, base_dir_, stateful_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, stateful_), |
| std::move(tlcl)); |
| ASSERT_TRUE(platform_->CreateDirectory(stateful_)); |
| } |
| |
| crossystem::Crossystem* crossystem_; |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| base::FilePath stateful_; |
| std::unique_ptr<libstorage::FakePlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| }; |
| |
| // Tests path for requested powerwash, but the reset file is now owned by us. |
| TEST_F(StatefulWipeTest, PowerwashForced) { |
| base::FilePath reset_file = stateful_.Append("factory_install_reset"); |
| ASSERT_TRUE(platform_->CreateSymbolicLink(reset_file, |
| base::FilePath("/file_not_exist"))); |
| startup_->CheckForStatefulWipe(); |
| EXPECT_EQ(startup_dep_->GetBootAlertForArg("power_wash"), 1); |
| std::string res; |
| startup_dep_->GetClobberLog(&res); |
| EXPECT_EQ(res, "Powerwash initiated by Reset file presence, but invalid"); |
| std::set<std::string> expected = {"keepimg"}; |
| EXPECT_EQ(startup_dep_->GetClobberArgs(), expected); |
| } |
| |
| // Tests normal path for user requested powerwash. |
| TEST_F(StatefulWipeTest, PowerwashNormal) { |
| base::FilePath reset_file = stateful_.Append("factory_install_reset"); |
| ASSERT_TRUE( |
| platform_->WriteStringToFile(reset_file, "keepimg slow test powerwash")); |
| ASSERT_TRUE(platform_->SetOwnership(reset_file, getuid(), 8888, false)); |
| startup_->CheckForStatefulWipe(); |
| EXPECT_EQ(startup_dep_->GetBootAlertForArg("power_wash"), 1); |
| std::string res; |
| startup_dep_->GetClobberLog(&res); |
| EXPECT_EQ(res, "Powerwash initiated by Reset file presence"); |
| std::set<std::string> expected = {"keepimg", "slow", "test", "powerwash"}; |
| EXPECT_EQ(startup_dep_->GetClobberArgs(), expected); |
| } |
| |
| // Test there is no wipe when there is no physical stateful partition. |
| TEST_F(StatefulWipeTest, NoStateDev) { |
| startup_->SetStateDev(base::FilePath()); |
| startup_->CheckForStatefulWipe(); |
| EXPECT_EQ(startup_dep_->GetBootAlertForArg("power_wash"), 0); |
| EXPECT_EQ(startup_dep_->GetBootAlertForArg("leave_dev"), 0); |
| std::string res; |
| startup_dep_->GetClobberLog(&res); |
| EXPECT_EQ(res, ""); |
| std::set<std::string> expected = {}; |
| EXPECT_EQ(startup_dep_->GetClobberArgs(), expected); |
| } |
| |
| // Test transitioning to verified mode, dev_mode_allowed file is owned by us. |
| TEST_F(StatefulWipeTest, TransitionToVerifiedDevModeFile) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("devsw_boot", 0)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyString("mainfw_type", "not_rec")); |
| base::FilePath dev_mode_allowed = stateful_.Append(".developer_mode"); |
| ASSERT_TRUE(platform_->WriteStringToFile(dev_mode_allowed, "0")); |
| ASSERT_TRUE(platform_->SetOwnership(dev_mode_allowed, getuid(), 8888, false)); |
| startup_->SetDevMode(false); |
| startup_->SetDevModeAllowedFile(dev_mode_allowed); |
| base::FilePath state_dev = base_dir_.Append("state_dev"); |
| startup_->SetStateDev(state_dev); |
| startup_->CheckForStatefulWipe(); |
| EXPECT_EQ(startup_dep_->GetBootAlertForArg("leave_dev"), 1); |
| std::string res; |
| startup_dep_->GetClobberLog(&res); |
| EXPECT_EQ(res, "Leave developer mode, dev_mode file present"); |
| std::set<std::string> expected = {"fast", "keepimg"}; |
| EXPECT_EQ(startup_dep_->GetClobberArgs(), expected); |
| } |
| |
| // Tranisitioning to verified mode, dev is a debug build. |
| // We only want to fast clobber the non-protected paths to |
| // preserve the testing tools. |
| TEST_F(StatefulWipeTest, TransitionToVerifiedDebugBuild) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("devsw_boot", 0)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyString("mainfw_type", "not_rec")); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("debug_build", 1)); |
| base::FilePath dev_mode_allowed = stateful_.Append(".developer_mode"); |
| ASSERT_TRUE(platform_->WriteStringToFile(dev_mode_allowed, "0")); |
| ASSERT_TRUE(platform_->SetOwnership(dev_mode_allowed, getuid(), 8888, false)); |
| startup_->SetDevMode(true); |
| startup_->SetDevModeAllowedFile(dev_mode_allowed); |
| base::FilePath state_dev = base_dir_.Append("state_dev"); |
| startup_->SetStateDev(state_dev); |
| std::unique_ptr<startup::StandardMountHelper> mount_helper_ = |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, stateful_); |
| std::unique_ptr<StatefulMount> stateful_mount = |
| std::make_unique<StatefulMount>(flags_, base_dir_, stateful_, |
| platform_.get(), startup_dep_.get(), |
| mount_helper_.get()); |
| startup_->SetStatefulMount(std::move(stateful_mount)); |
| startup_->CheckForStatefulWipe(); |
| EXPECT_EQ(startup_dep_->GetBootAlertForArg("leave_dev"), 0); |
| std::string res; |
| startup_dep_->GetClobberLog(&res); |
| EXPECT_NE(res.find("Leave developer mode on a debug build"), |
| std::string::npos); |
| std::set<std::string> expected = {}; |
| EXPECT_EQ(startup_dep_->GetClobberArgs(), expected); |
| } |
| |
| // Transitioning to dev mode, dev is not a debug build. |
| // Clobber should be called with |keepimg|, no need to erase |
| // the stateful. |
| TEST_F(StatefulWipeTest, TransitionToDevModeNoDebugBuild) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("devsw_boot", 1)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyString("mainfw_type", "not_rec")); |
| base::FilePath dev_mode_allowed = stateful_.Append(".developer_mode"); |
| ASSERT_TRUE(platform_->WriteStringToFile(dev_mode_allowed, "0")); |
| ASSERT_TRUE(platform_->SetOwnership(dev_mode_allowed, -1, 8888, false)); |
| startup_->SetDevMode(false); |
| startup_->SetDevModeAllowedFile(dev_mode_allowed); |
| base::FilePath state_dev = base_dir_.Append("state_dev"); |
| startup_->SetStateDev(state_dev); |
| startup_->CheckForStatefulWipe(); |
| EXPECT_EQ(startup_dep_->GetBootAlertForArg("enter_dev"), 1); |
| std::string res; |
| startup_dep_->GetClobberLog(&res); |
| EXPECT_EQ(res, "Enter developer mode"); |
| std::set<std::string> expected = {"keepimg"}; |
| EXPECT_EQ(startup_dep_->GetClobberArgs(), expected); |
| } |
| |
| // Transitioning to dev mode, dev is a debug build. |
| // Only fast clobber the non-protected paths in debug build to preserve |
| // the testing tools. |
| TEST_F(StatefulWipeTest, TransitionToDevModeDebugBuild) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("devsw_boot", 1)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyString("mainfw_type", "not_rec")); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("debug_build", 1)); |
| base::FilePath dev_mode_allowed = stateful_.Append(".developer_mode"); |
| ASSERT_TRUE(platform_->TouchFileDurable(dev_mode_allowed)); |
| ASSERT_TRUE(platform_->SetOwnership(dev_mode_allowed, -1, 8888, false)); |
| startup_->SetDevMode(true); |
| startup_->SetDevModeAllowedFile(dev_mode_allowed); |
| base::FilePath state_dev = base_dir_.Append("state_dev"); |
| startup_->SetStateDev(state_dev); |
| std::unique_ptr<startup::StandardMountHelper> mount_helper_ = |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, stateful_); |
| std::unique_ptr<StatefulMount> stateful_mount = |
| std::make_unique<StatefulMount>(flags_, base_dir_, stateful_, |
| platform_.get(), startup_dep_.get(), |
| mount_helper_.get()); |
| startup_->SetStatefulMount(std::move(stateful_mount)); |
| startup_->CheckForStatefulWipe(); |
| EXPECT_EQ(startup_dep_->GetBootAlertForArg("leave_dev"), 0); |
| std::string res; |
| startup_dep_->GetClobberLog(&res); |
| EXPECT_NE(res.find("Enter developer mode on a debug build"), |
| std::string::npos); |
| std::set<std::string> expected = {}; |
| EXPECT_EQ(startup_dep_->GetClobberArgs(), expected); |
| platform_->ReadFileToString(dev_mode_allowed, &res); |
| EXPECT_EQ(res, ""); |
| } |
| |
| class TpmCleanupTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| platform_ = std::make_unique<libstorage::MockPlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(), flags_, base_dir_, base_dir_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| flag_file_ = base_dir_.Append(kTpmFirmwareUpdateRequestFlagFile); |
| tpm_cleanup_ = base_dir_.Append(kTpmFirmwareUpdateCleanup); |
| } |
| |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| std::unique_ptr<libstorage::MockPlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| base::FilePath flag_file_; |
| base::FilePath tpm_cleanup_; |
| }; |
| |
| TEST_F(TpmCleanupTest, TpmCleanupNoFlagFile) { |
| brillo::ProcessMock* process = platform_->mock_process(); |
| EXPECT_CALL(*process, Run()).Times(0); |
| startup_->CleanupTpm(); |
| } |
| |
| TEST_F(TpmCleanupTest, TpmCleanupNoCmdPath) { |
| ASSERT_TRUE(platform_->WriteStringToFile(flag_file_, "exists")); |
| brillo::ProcessMock* process = platform_->mock_process(); |
| EXPECT_CALL(*process, Run()).Times(0); |
| startup_->CleanupTpm(); |
| } |
| |
| TEST_F(TpmCleanupTest, TpmCleanupSuccess) { |
| ASSERT_TRUE(platform_->WriteStringToFile(flag_file_, "exists")); |
| ASSERT_TRUE(platform_->WriteStringToFile(tpm_cleanup_, "exists")); |
| brillo::ProcessMock* process = platform_->mock_process(); |
| EXPECT_CALL(*process, Run()).Times(1); |
| startup_->CleanupTpm(); |
| } |
| |
| class ConfigTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| lsb_file_ = base_dir_.Append(kLsbRelease); |
| stateful_ = base_dir_.Append(kStatefulPartition); |
| platform_ = std::make_unique<libstorage::MockPlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| crossystem_ = platform_->GetCrosssystem(); |
| } |
| |
| std::unique_ptr<startup::MountHelper> GenerateMountHelper() { |
| startup::Flags flags; |
| startup::ChromeosStartup::ParseFlags(&flags); |
| startup::MountHelperFactory factory(platform_.get(), startup_dep_.get(), |
| flags, base_dir_, stateful_, lsb_file_); |
| return factory.Generate(); |
| } |
| |
| crossystem::Crossystem* crossystem_; |
| base::FilePath base_dir_{"/"}; |
| base::FilePath lsb_file_; |
| base::FilePath stateful_; |
| std::unique_ptr<libstorage::MockPlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| }; |
| |
| TEST_F(ConfigTest, NoDevMode) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("cros_debug", 0)); |
| ASSERT_TRUE(platform_->WriteStringToFile( |
| lsb_file_, "CHROMEOS_RELEASE_TRACK=stable-channel\n")); |
| EXPECT_EQ(dynamic_cast<startup::FactoryModeMountHelper*>( |
| GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_EQ( |
| dynamic_cast<startup::TestModeMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_NE( |
| dynamic_cast<startup::StandardMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| } |
| |
| TEST_F(ConfigTest, DevMode) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("cros_debug", 1)); |
| ASSERT_TRUE(platform_->WriteStringToFile( |
| lsb_file_, "CHROMEOS_RELEASE_TRACK=stable-channel\n")); |
| std::unique_ptr<startup::MountHelper> helper = GenerateMountHelper(); |
| EXPECT_EQ(dynamic_cast<startup::FactoryModeMountHelper*>( |
| GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_EQ( |
| dynamic_cast<startup::TestModeMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_NE( |
| dynamic_cast<startup::StandardMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| } |
| |
| TEST_F(ConfigTest, DevModeTest) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("cros_debug", 1)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("debug_build", 0)); |
| ASSERT_TRUE(platform_->WriteStringToFile( |
| lsb_file_, "CHROMEOS_RELEASE_TRACK=testimage-channel\n")); |
| std::string test_lsb; |
| ASSERT_TRUE(platform_->ReadFileToString(lsb_file_, &test_lsb)); |
| std::unique_ptr<startup::MountHelper> helper = GenerateMountHelper(); |
| EXPECT_EQ(dynamic_cast<startup::FactoryModeMountHelper*>( |
| GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_NE( |
| dynamic_cast<startup::TestModeMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_EQ( |
| dynamic_cast<startup::StandardMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| } |
| |
| TEST_F(ConfigTest, DevModeTestFactoryTest) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("cros_debug", 1)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("debug_build", 1)); |
| ASSERT_TRUE(platform_->WriteStringToFile( |
| lsb_file_, "CHROMEOS_RELEASE_TRACK=testimage-channel\n")); |
| base::FilePath factory_en = stateful_.Append("dev_image/factory/enabled"); |
| ASSERT_TRUE(platform_->WriteStringToFile(factory_en, "Enabled")); |
| std::unique_ptr<startup::MountHelper> helper = GenerateMountHelper(); |
| EXPECT_NE(dynamic_cast<startup::FactoryModeMountHelper*>( |
| GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_EQ( |
| dynamic_cast<startup::TestModeMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_EQ( |
| dynamic_cast<startup::StandardMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| } |
| |
| TEST_F(ConfigTest, DevModeTestFactoryInstaller) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("cros_debug", 1)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("debug_build", 0)); |
| ASSERT_TRUE(platform_->WriteStringToFile( |
| lsb_file_, "CHROMEOS_RELEASE_TRACK=testimage-channel\n")); |
| base::FilePath cmdline = base_dir_.Append(kProcCmdLine); |
| ASSERT_TRUE(platform_->WriteStringToFile(cmdline, "cros_factory_install")); |
| std::unique_ptr<startup::MountHelper> helper = GenerateMountHelper(); |
| EXPECT_NE(dynamic_cast<startup::FactoryModeMountHelper*>( |
| GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_EQ( |
| dynamic_cast<startup::TestModeMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_EQ( |
| dynamic_cast<startup::StandardMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| } |
| |
| TEST_F(ConfigTest, DevModeTestFactoryInstallerUsingFile) { |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("cros_debug", 1)); |
| ASSERT_TRUE(crossystem_->VbSetSystemPropertyInt("debug_build", 0)); |
| ASSERT_TRUE(platform_->WriteStringToFile( |
| lsb_file_, "CHROMEOS_RELEASE_TRACK=testimage-channel\n")); |
| base::FilePath cmdline = base_dir_.Append(kProcCmdLine); |
| ASSERT_TRUE(platform_->WriteStringToFile(cmdline, "not_factory_install")); |
| base::FilePath installer = base_dir_.Append("root/.factory_installer"); |
| ASSERT_TRUE(platform_->WriteStringToFile(installer, "factory")); |
| std::unique_ptr<startup::MountHelper> helper = GenerateMountHelper(); |
| EXPECT_NE(dynamic_cast<startup::FactoryModeMountHelper*>( |
| GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_EQ( |
| dynamic_cast<startup::TestModeMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| EXPECT_EQ( |
| dynamic_cast<startup::StandardMountHelper*>(GenerateMountHelper().get()), |
| nullptr); |
| } |
| |
| class MountStackTest : public ::testing::Test { |
| protected: |
| MountStackTest() |
| : base_dir_(base::FilePath("")), |
| platform_(std::make_unique<libstorage::MockPlatform>()), |
| startup_dep_( |
| std::make_unique<startup::FakeStartupDep>(platform_.get())), |
| mount_helper_( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_) { |
| } |
| |
| void SetUp() override {} |
| |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| std::unique_ptr<libstorage::MockPlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| startup::StandardMountHelper mount_helper_; |
| }; |
| |
| TEST_F(MountStackTest, CleanupMountsNoEncrypt) { |
| // Remember 2 mounts, make sure CleanupMountsStack() calls unmount |
| // for all and returns what has been unmounted. |
| base::FilePath root = base_dir_.Append("root"); |
| mount_helper_.RememberMount(root); |
| base::FilePath home = base_dir_.Append("home"); |
| mount_helper_.RememberMount(home); |
| |
| EXPECT_CALL(*platform_, Unmount(root, false, nullptr)).WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, Unmount(home, false, nullptr)).WillOnce(Return(true)); |
| std::vector<base::FilePath> mounts; |
| mount_helper_.CleanupMountsStack(&mounts); |
| EXPECT_EQ(mounts.front(), home); |
| mounts.erase(mounts.begin()); |
| EXPECT_EQ(mounts.front(), root); |
| mounts.erase(mounts.begin()); |
| EXPECT_TRUE(mounts.empty()); |
| } |
| |
| TEST(MountVarAndHomeChronosEncrypted, MountEncrypted) { |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| |
| std::unique_ptr<libstorage::FakePlatform> platform_ = |
| std::make_unique<libstorage::FakePlatform>(); |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_ = |
| std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| startup_dep_->SetMountEncOutputForArg("", "1"); |
| std::unique_ptr<startup::StandardMountHelper> mount_helper_ = |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_); |
| |
| EXPECT_TRUE(mount_helper_->MountVarAndHomeChronosEncrypted()); |
| } |
| |
| TEST(MountVarAndHomeChronosEncrypted, MountEncryptedFail) { |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| |
| std::unique_ptr<libstorage::FakePlatform> platform_ = |
| std::make_unique<libstorage::FakePlatform>(); |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_ = |
| std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<startup::StandardMountHelper> mount_helper_ = |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_); |
| |
| EXPECT_FALSE(mount_helper_->MountVarAndHomeChronosEncrypted()); |
| } |
| |
| class DoMountTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| platform_ = std::make_unique<libstorage::MockPlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| } |
| |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| std::unique_ptr<libstorage::MockPlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| }; |
| |
| TEST_F(DoMountTest, StandardMountHelper) { |
| flags_.encstateful = true; |
| startup_dep_->SetMountEncOutputForArg("", "1"); |
| std::unique_ptr<startup::StandardMountHelper> mount_helper_ = |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_); |
| EXPECT_TRUE(mount_helper_->DoMountVarAndHomeChronos()); |
| } |
| |
| TEST_F(DoMountTest, TestModeMountHelperCreateSystemKey) { |
| flags_.sys_key_util = true; |
| flags_.encstateful = true; |
| base::FilePath no_early = base_dir_.Append(".no_early_system_key"); |
| base::FilePath log_file = base_dir_.Append(kSysKeyLog); |
| ASSERT_TRUE(platform_->WriteStringToFile(no_early, "1")); |
| |
| startup_dep_->SetMountEncOutputForArg("", "1"); |
| std::unique_ptr<startup::TestModeMountHelper> mount_helper_ = |
| std::make_unique<startup::TestModeMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_); |
| EXPECT_TRUE(mount_helper_->DoMountVarAndHomeChronos()); |
| std::string sys_key_log_out; |
| platform_->ReadFileToString(log_file, &sys_key_log_out); |
| EXPECT_EQ(sys_key_log_out, "Opt not to create a system key in advance."); |
| } |
| |
| TEST_F(DoMountTest, TestModeMountHelperMountEncryptFailed) { |
| flags_.sys_key_util = false; |
| flags_.encstateful = true; |
| base::FilePath mnt_encrypt_fail = base_dir_.Append("mount_encrypted_failed"); |
| |
| ASSERT_TRUE(platform_->TouchFileDurable(mnt_encrypt_fail)); |
| startup_dep_->SetMountEncOutputForArg("", "1"); |
| std::unique_ptr<startup::TestModeMountHelper> mount_helper_ = |
| std::make_unique<startup::TestModeMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_); |
| EXPECT_TRUE(mount_helper_->DoMountVarAndHomeChronos()); |
| } |
| |
| TEST_F(DoMountTest, TestModeMountHelperMountVarSuccess) { |
| flags_.sys_key_util = false; |
| flags_.encstateful = true; |
| |
| startup_dep_->SetMountEncOutputForArg("", "1"); |
| std::unique_ptr<startup::TestModeMountHelper> mount_helper_ = |
| std::make_unique<startup::TestModeMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_); |
| EXPECT_TRUE(mount_helper_->DoMountVarAndHomeChronos()); |
| std::string clobber_log_out; |
| startup_dep_->GetClobberLog(&clobber_log_out); |
| EXPECT_EQ(clobber_log_out, ""); |
| } |
| |
| TEST_F(DoMountTest, TestModeMountHelperMountVarFail) { |
| // We already failed one, so at reboot, "mount_encrypted_failed" exists. |
| // Let's fail second time and check we are staving backups. |
| flags_.sys_key_util = false; |
| flags_.encstateful = true; |
| base::FilePath mnt_encrypt_fail = base_dir_.Append("mount_encrypted_failed"); |
| EXPECT_CALL(*platform_, GetOwnership(mnt_encrypt_fail, _, nullptr, false)) |
| .WillOnce(DoAll(SetArgPointee<1>(getuid()), Return(true))); |
| base::FilePath corrupted_enc = base_dir_.Append("corrupted_encryption"); |
| base::FilePath encrypted_test = base_dir_.Append("encrypted.test1"); |
| base::FilePath encrypted_test2 = base_dir_.Append("encrypted.test2"); |
| ASSERT_TRUE(platform_->WriteStringToFile(encrypted_test, "1")); |
| ASSERT_TRUE(platform_->WriteStringToFile(encrypted_test2, "1")); |
| |
| std::unique_ptr<startup::TestModeMountHelper> mount_helper_ = |
| std::make_unique<startup::TestModeMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_); |
| EXPECT_FALSE(mount_helper_->DoMountVarAndHomeChronos()); |
| std::string clobber_log_out; |
| startup_dep_->GetClobberLog(&clobber_log_out); |
| EXPECT_EQ(clobber_log_out, |
| "Failed mounting var and home/chronos; re-created."); |
| EXPECT_TRUE(platform_->FileExists(corrupted_enc.Append("encrypted.test1"))); |
| EXPECT_TRUE(platform_->FileExists(corrupted_enc.Append("encrypted.test2"))); |
| } |
| |
| TEST_F(DoMountTest, FactoryModeMountHelperTmpfsFailMntVar) { |
| flags_.encstateful = true; |
| base::FilePath options_file = base_dir_.Append(kMntOptionsFile); |
| ASSERT_TRUE(platform_->WriteStringToFile(options_file, "tmpfs")); |
| base::FilePath var = base_dir_.Append("var"); |
| EXPECT_CALL(*platform_, Mount(_, var, "tmpfs", _, _)).WillOnce(Return(false)); |
| |
| std::unique_ptr<startup::FactoryModeMountHelper> mount_helper_ = |
| std::make_unique<startup::FactoryModeMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_); |
| EXPECT_FALSE(mount_helper_->DoMountVarAndHomeChronos()); |
| } |
| |
| TEST_F(DoMountTest, FactoryModeMountHelperTmpfsFailMntHomeChronos) { |
| flags_.encstateful = true; |
| base::FilePath options_file = base_dir_.Append(kMntOptionsFile); |
| ASSERT_TRUE(platform_->WriteStringToFile(options_file, "tmpfs")); |
| base::FilePath var = base_dir_.Append("var"); |
| EXPECT_CALL(*platform_, Mount(_, var, "tmpfs", _, _)).WillOnce(Return(true)); |
| |
| base::FilePath stateful_home_chronos = base_dir_.Append("home/chronos"); |
| EXPECT_CALL(*platform_, Mount(stateful_home_chronos, _, _, _, _)) |
| .WillOnce(Return(false)); |
| |
| std::unique_ptr<startup::FactoryModeMountHelper> mount_helper_ = |
| std::make_unique<startup::FactoryModeMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_); |
| EXPECT_FALSE(mount_helper_->DoMountVarAndHomeChronos()); |
| } |
| |
| TEST_F(DoMountTest, FactoryModeMountHelperTmpfsSuccess) { |
| flags_.encstateful = true; |
| base::FilePath stateful = base_dir_.Append("mnt/stateful_partition"); |
| base::FilePath options_file = stateful.Append(kMntOptionsFile); |
| ASSERT_TRUE(platform_->WriteStringToFile(options_file, "tmpfs")); |
| base::FilePath var = base_dir_.Append("var"); |
| EXPECT_CALL(*platform_, Mount(_, var, "tmpfs", _, _)).WillOnce(Return(true)); |
| |
| base::FilePath stateful_home_chronos = stateful.Append("home/chronos"); |
| base::FilePath home_chronos = base_dir_.Append("home/chronos"); |
| EXPECT_CALL(*platform_, |
| Mount(stateful_home_chronos, home_chronos, _, MS_BIND, _)) |
| .WillOnce(Return(true)); |
| |
| std::unique_ptr<startup::FactoryModeMountHelper> mount_helper_ = |
| std::make_unique<startup::FactoryModeMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, stateful); |
| EXPECT_TRUE(mount_helper_->DoMountVarAndHomeChronos()); |
| } |
| |
| TEST_F(DoMountTest, FactoryModeMountHelperUnencryptFailMntVar) { |
| flags_.encstateful = true; |
| base::FilePath stateful = base_dir_.Append("mnt/stateful_partition"); |
| base::FilePath stateful_var = stateful.Append("var"); |
| EXPECT_CALL(*platform_, Mount(stateful_var, _, _, MS_BIND, _)) |
| .WillOnce(Return(false)); |
| |
| std::unique_ptr<startup::FactoryModeMountHelper> mount_helper_ = |
| std::make_unique<startup::FactoryModeMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, stateful); |
| EXPECT_FALSE(mount_helper_->DoMountVarAndHomeChronos()); |
| } |
| |
| TEST_F(DoMountTest, FactoryModeMountHelperUnencryptFailMntHomeChronos) { |
| flags_.encstateful = true; |
| base::FilePath stateful = base_dir_.Append("mnt/stateful_partition"); |
| base::FilePath stateful_var = stateful.Append("var"); |
| base::FilePath var = base_dir_.Append("var"); |
| EXPECT_CALL(*platform_, Mount(stateful_var, var, _, MS_BIND, _)) |
| .WillOnce(Return(true)); |
| |
| base::FilePath stateful_home_chronos = stateful.Append("home/chronos"); |
| EXPECT_CALL(*platform_, Mount(stateful_home_chronos, _, _, MS_BIND, _)) |
| .WillOnce(Return(false)); |
| |
| std::unique_ptr<startup::FactoryModeMountHelper> mount_helper_ = |
| std::make_unique<startup::FactoryModeMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, stateful); |
| EXPECT_FALSE(mount_helper_->DoMountVarAndHomeChronos()); |
| } |
| |
| TEST_F(DoMountTest, FactoryModeMountHelperUnencryptSuccess) { |
| flags_.encstateful = true; |
| base::FilePath stateful = base_dir_.Append("mnt/stateful_partition"); |
| base::FilePath stateful_var = stateful.Append("var"); |
| base::FilePath var = base_dir_.Append("var"); |
| EXPECT_CALL(*platform_, Mount(stateful_var, var, _, MS_BIND, _)) |
| .WillOnce(Return(true)); |
| |
| base::FilePath stateful_home_chronos = stateful.Append("home/chronos"); |
| base::FilePath home_chronos = base_dir_.Append("home/chronos"); |
| EXPECT_CALL(*platform_, |
| Mount(stateful_home_chronos, home_chronos, _, MS_BIND, _)) |
| .WillOnce(Return(true)); |
| |
| std::unique_ptr<startup::FactoryModeMountHelper> mount_helper_ = |
| std::make_unique<startup::FactoryModeMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, stateful); |
| EXPECT_TRUE(mount_helper_->DoMountVarAndHomeChronos()); |
| } |
| |
| class IsVarFullTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| platform_ = std::make_unique<libstorage::MockPlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(), flags_, base_dir_, base_dir_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| } |
| |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| std::unique_ptr<libstorage::MockPlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| }; |
| |
| TEST_F(IsVarFullTest, StatvfsFailure) { |
| // Assume the machine storage where the unit test are running is not full. |
| EXPECT_FALSE(startup_->IsVarFull()); |
| } |
| |
| TEST_F(IsVarFullTest, Failure) { |
| base::FilePath var = base_dir_.Append("var"); |
| |
| struct statvfs st; |
| st.f_bavail = 2600; |
| st.f_favail = 110; |
| st.f_bsize = 4096; |
| EXPECT_CALL(*platform_, StatVFS(var, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(st), Return(true))); |
| EXPECT_FALSE(startup_->IsVarFull()); |
| } |
| |
| TEST_F(IsVarFullTest, TrueBavail) { |
| base::FilePath var = base_dir_.Append("var"); |
| |
| struct statvfs st; |
| st.f_bavail = 1000; |
| st.f_favail = 110; |
| st.f_bsize = 4096; |
| EXPECT_CALL(*platform_, StatVFS(var, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(st), Return(true))); |
| EXPECT_TRUE(startup_->IsVarFull()); |
| } |
| |
| TEST_F(IsVarFullTest, TrueFavail) { |
| base::FilePath var = base_dir_.Append("var"); |
| |
| struct statvfs st; |
| st.f_bavail = 11000; |
| st.f_favail = 90; |
| st.f_bsize = 4096; |
| EXPECT_CALL(*platform_, StatVFS(var, _)) |
| .WillOnce(DoAll(SetArgPointee<1>(st), Return(true))); |
| EXPECT_TRUE(startup_->IsVarFull()); |
| } |
| |
| class DeviceSettingsTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| platform_ = std::make_unique<libstorage::FakePlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(), flags_, base_dir_, base_dir_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| base::FilePath var_lib = base_dir_.Append("var/lib"); |
| whitelist_ = var_lib.Append("whitelist"); |
| devicesettings_ = var_lib.Append("devicesettings"); |
| } |
| |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| std::unique_ptr<libstorage::FakePlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| base::FilePath whitelist_; |
| base::FilePath devicesettings_; |
| }; |
| |
| TEST_F(DeviceSettingsTest, OldPathEmpty) { |
| ASSERT_TRUE(platform_->CreateDirectory(whitelist_)); |
| base::FilePath devicesettings_test = devicesettings_.Append("test"); |
| ASSERT_TRUE(platform_->WriteStringToFile(devicesettings_test, "test")); |
| |
| startup_->MoveToLibDeviceSettings(); |
| EXPECT_FALSE(platform_->DirectoryExists(whitelist_)); |
| EXPECT_TRUE(platform_->FileExists(devicesettings_test)); |
| } |
| |
| TEST_F(DeviceSettingsTest, NewPathEmpty) { |
| ASSERT_TRUE(platform_->CreateDirectory(whitelist_)); |
| ASSERT_TRUE(platform_->CreateDirectory(devicesettings_)); |
| base::FilePath whitelist_test = whitelist_.Append("test"); |
| ASSERT_TRUE(platform_->WriteStringToFile(whitelist_test, "test")); |
| base::FilePath devicesettings_test = devicesettings_.Append("test"); |
| |
| startup_->MoveToLibDeviceSettings(); |
| EXPECT_FALSE(platform_->DirectoryExists(whitelist_)); |
| EXPECT_FALSE(platform_->FileExists(whitelist_test)); |
| EXPECT_TRUE(platform_->FileExists(devicesettings_test)); |
| } |
| |
| TEST_F(DeviceSettingsTest, NeitherPathEmpty) { |
| ASSERT_TRUE(platform_->CreateDirectory(whitelist_)); |
| ASSERT_TRUE(platform_->CreateDirectory(devicesettings_)); |
| base::FilePath whitelist_test = whitelist_.Append("test_w"); |
| ASSERT_TRUE(platform_->WriteStringToFile(whitelist_test, "test_w")); |
| base::FilePath devicesettings_test = devicesettings_.Append("test_d"); |
| ASSERT_TRUE(platform_->WriteStringToFile(devicesettings_test, "test_d")); |
| |
| startup_->MoveToLibDeviceSettings(); |
| EXPECT_TRUE(platform_->DirectoryExists(whitelist_)); |
| EXPECT_TRUE(platform_->FileExists(whitelist_test)); |
| EXPECT_TRUE(platform_->FileExists(devicesettings_test)); |
| } |
| |
| class DaemonStoreTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| platform_ = std::make_unique<libstorage::MockPlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(), flags_, base_dir_, base_dir_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| } |
| |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| std::unique_ptr<libstorage::MockPlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| }; |
| |
| TEST_F(DaemonStoreTest, NonEmptyEtc) { |
| base::FilePath run = base_dir_.Append("run"); |
| base::FilePath etc = base_dir_.Append("etc"); |
| base::FilePath run_daemon = run.Append("daemon-store"); |
| base::FilePath run_daemon_cache = run.Append("daemon-store-cache"); |
| base::FilePath etc_daemon = etc.Append("daemon-store"); |
| base::FilePath etc_file = etc_daemon.Append("test_file"); |
| base::FilePath etc_file_not_ds = etc.Append("test/not_incl"); |
| ASSERT_TRUE(platform_->WriteStringToFile(etc_file, "1")); |
| ASSERT_TRUE(platform_->WriteStringToFile(etc_file_not_ds, "exclude")); |
| base::FilePath subdir = etc_daemon.Append("subdir"); |
| base::FilePath sub_file = subdir.Append("test_file"); |
| ASSERT_TRUE(platform_->WriteStringToFile(sub_file, "1")); |
| |
| base::FilePath run_subdir = run_daemon.Append("subdir"); |
| base::FilePath run_cache_subdir = run_daemon_cache.Append("subdir"); |
| base::FilePath run_test_exclude = run.Append("test/not_incl"); |
| base::FilePath run_ds_exclude = run_daemon.Append("test/not_incl"); |
| EXPECT_CALL(*platform_, Mount(run_subdir, run_subdir, _, MS_BIND, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, Mount(base::FilePath(), run_subdir, _, MS_SHARED, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, |
| Mount(run_cache_subdir, run_cache_subdir, _, MS_BIND, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, |
| Mount(base::FilePath(), run_cache_subdir, _, MS_SHARED, _)) |
| .WillOnce(Return(true)); |
| |
| startup_->CreateDaemonStore(); |
| EXPECT_TRUE(platform_->DirectoryExists(run_subdir)); |
| EXPECT_TRUE(platform_->DirectoryExists(run_cache_subdir)); |
| EXPECT_FALSE(platform_->FileExists(run_test_exclude)); |
| EXPECT_FALSE(platform_->FileExists(run_ds_exclude)); |
| } |
| |
| class RemoveVarEmptyTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| platform_ = std::make_unique<libstorage::FakePlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(), flags_, base_dir_, base_dir_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| } |
| |
| std::unique_ptr<libstorage::FakePlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| }; |
| |
| TEST_F(RemoveVarEmptyTest, NonEmpty) { |
| base::FilePath var_empty = base_dir_.Append("var/empty"); |
| base::FilePath file1 = var_empty.Append("test_file"); |
| ASSERT_TRUE(platform_->WriteStringToFile(file1, "1")); |
| base::FilePath file2 = var_empty.Append("test_file_2"); |
| ASSERT_TRUE(platform_->WriteStringToFile(file2, "1")); |
| |
| startup_->RemoveVarEmpty(); |
| EXPECT_TRUE(!platform_->FileExists(file1)); |
| EXPECT_TRUE(!platform_->FileExists(file2)); |
| EXPECT_TRUE(!platform_->FileExists(var_empty)); |
| } |
| |
| class CheckVarLogTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| platform_ = std::make_unique<libstorage::FakePlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(), flags_, base_dir_, base_dir_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| var_log_ = base_dir_.Append("var/log"); |
| platform_->CreateDirectory(var_log_); |
| } |
| |
| std::unique_ptr<libstorage::FakePlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| base::FilePath var_log_; |
| }; |
| |
| TEST_F(CheckVarLogTest, NoSymLinks) { |
| base::FilePath test_file = var_log_.Append("test_file"); |
| base::FilePath test_dir = var_log_.Append("test_dir"); |
| base::FilePath test_test = test_dir.Append("test"); |
| ASSERT_TRUE(platform_->WriteStringToFile(test_file, "test1")); |
| ASSERT_TRUE(platform_->WriteStringToFile(test_test, "test2")); |
| |
| startup_->CheckVarLog(); |
| EXPECT_TRUE(platform_->FileExists(test_file)); |
| EXPECT_TRUE(platform_->FileExists(test_test)); |
| } |
| |
| TEST_F(CheckVarLogTest, SymLinkInsideVarLog) { |
| base::FilePath test_file = var_log_.Append("test_file"); |
| base::FilePath test_dir = var_log_.Append("test_dir"); |
| base::FilePath test_test = test_dir.Append("test"); |
| base::FilePath test_link = var_log_.Append("test_link"); |
| base::FilePath test_sub_link = test_dir.Append("link"); |
| ASSERT_TRUE(platform_->WriteStringToFile(test_file, "test1")); |
| ASSERT_TRUE(platform_->WriteStringToFile(test_test, "test2")); |
| ASSERT_TRUE(platform_->CreateSymbolicLink(test_link, test_file)); |
| ASSERT_TRUE(platform_->CreateSymbolicLink(test_sub_link, test_test)); |
| |
| startup_->CheckVarLog(); |
| EXPECT_TRUE(platform_->FileExists(test_file)); |
| EXPECT_TRUE(platform_->FileExists(test_test)); |
| EXPECT_TRUE(platform_->IsLink(test_link)); |
| EXPECT_TRUE(platform_->IsLink(test_sub_link)); |
| } |
| |
| TEST_F(CheckVarLogTest, SymLinkOutsideVarLog) { |
| base::FilePath test_file = var_log_.Append("test_file"); |
| base::FilePath test_dir = var_log_.Append("test_dir"); |
| base::FilePath test_test = test_dir.Append("test"); |
| base::FilePath test_link = var_log_.Append("test_link"); |
| base::FilePath test_sub_link = test_dir.Append("link"); |
| base::FilePath outside = base_dir_.Append("outside"); |
| ASSERT_TRUE(platform_->WriteStringToFile(outside, "out")); |
| ASSERT_TRUE(platform_->WriteStringToFile(test_file, "test1")); |
| ASSERT_TRUE(platform_->WriteStringToFile(test_test, "test2")); |
| ASSERT_TRUE(platform_->CreateSymbolicLink(test_link, outside)); |
| ASSERT_TRUE(platform_->CreateSymbolicLink(test_sub_link, outside)); |
| |
| startup_->CheckVarLog(); |
| EXPECT_TRUE(platform_->FileExists(test_file)); |
| EXPECT_TRUE(platform_->FileExists(test_test)); |
| EXPECT_FALSE(platform_->FileExists(test_link)); |
| EXPECT_FALSE(platform_->FileExists(test_sub_link)); |
| } |
| |
| class DevMountPackagesTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| stateful_ = base_dir_.Append("stateful_test"); |
| base::CreateDirectory(stateful_); |
| platform_ = std::make_unique<libstorage::MockPlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| mount_helper_ = std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, stateful_); |
| stateful_mount_ = std::make_unique<startup::StatefulMount>( |
| flags_, base_dir_, stateful_, platform_.get(), startup_dep_.get(), |
| mount_helper_.get()); |
| proc_mounts_ = base_dir_.Append("proc/mounts"); |
| mount_log_ = base_dir_.Append("var/log/mount_options.log"); |
| stateful_dev_image_ = stateful_.Append("dev_image"); |
| usrlocal_ = base_dir_.Append("usr/local"); |
| asan_dir_ = base_dir_.Append("var/log/asan"); |
| lsm_dir_ = base_dir_.Append(kLSMDir); |
| allow_sym_ = lsm_dir_.Append("allow_symlink"); |
| disable_ssh_ = base_dir_.Append( |
| "usr/share/cros/startup/disable_stateful_security_hardening"); |
| var_overlay_ = stateful_.Append("var_overlay"); |
| var_portage_ = base_dir_.Append("var/lib/portage"); |
| ASSERT_TRUE(platform_->WriteStringToFile(allow_sym_, "")); |
| ASSERT_TRUE(platform_->CreateDirectory(stateful_dev_image_)); |
| ASSERT_TRUE(platform_->CreateDirectory(usrlocal_)); |
| ASSERT_TRUE(platform_->CreateDirectory(var_overlay_)); |
| ASSERT_TRUE(platform_->CreateDirectory(var_portage_)); |
| |
| // Collect all writes to sysfs attribute "allow_symlink" to a local |
| // variable, ignore the rest. |
| EXPECT_CALL(*platform_, WriteStringToFile(_, _)).Times(AnyNumber()); |
| EXPECT_CALL(*platform_, WriteStringToFile(allow_sym_, _)) |
| .WillRepeatedly( |
| [this](const base::FilePath&, const std::string& c) -> bool { |
| allow_sym_contents_ += c; |
| return true; |
| }); |
| } |
| |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| std::unique_ptr<libstorage::MockPlatform> platform_; |
| base::FilePath stateful_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| std::unique_ptr<startup::StandardMountHelper> mount_helper_; |
| std::unique_ptr<startup::StatefulMount> stateful_mount_; |
| base::FilePath proc_mounts_; |
| base::FilePath mount_log_; |
| base::FilePath stateful_dev_image_; |
| base::FilePath usrlocal_; |
| base::FilePath asan_dir_; |
| base::FilePath lsm_dir_; |
| base::FilePath allow_sym_; |
| std::string allow_sym_contents_; |
| base::FilePath disable_ssh_; |
| base::FilePath var_overlay_; |
| base::FilePath var_portage_; |
| }; |
| |
| TEST_F(DevMountPackagesTest, NoDeviceDisableStatefulSecurity) { |
| platform_->CreateDirectory(disable_ssh_); |
| |
| std::string mount_contents = |
| R"(/dev/root / ext2 ro,seclabel,relatime 0 0 )" |
| R"(devtmpfs /dev devtmpfs rw,seclabel,nosuid,noexec,relatime,)" |
| R"(size=4010836k,nr_inodes=1002709,mode=755 0 0)" |
| R"(proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0)" |
| R"(sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0)"; |
| |
| ASSERT_TRUE(platform_->WriteStringToFile(proc_mounts_, mount_contents)); |
| |
| EXPECT_CALL(*platform_, Mount(stateful_dev_image_, usrlocal_, _, MS_BIND, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, Mount(base::FilePath(), usrlocal_, _, MS_REMOUNT, _)) |
| .WillOnce(Return(true)); |
| |
| stateful_mount_->DevMountPackages(); |
| |
| EXPECT_TRUE(platform_->DirectoryExists(asan_dir_)); |
| |
| std::string mount_log_contents; |
| platform_->ReadFileToString(mount_log_, &mount_log_contents); |
| EXPECT_EQ(mount_contents, mount_log_contents); |
| |
| EXPECT_EQ("", allow_sym_contents_); |
| } |
| |
| TEST_F(DevMountPackagesTest, WithDeviceNoDisableStatefulSecurity) { |
| std::string mount_contents = |
| R"(/dev/root / ext2 ro,seclabel,relatime 0 0 )" |
| R"(devtmpfs /dev devtmpfs rw,seclabel,nosuid,noexec,relatime,)" |
| R"(size=4010836k,nr_inodes=1002709,mode=755 0 0)" |
| R"(proc /proc proc rw,nosuid,nodev,noexec,relatime 0 0)" |
| R"(sysfs /sys sysfs rw,seclabel,nosuid,nodev,noexec,relatime 0 0)"; |
| |
| ASSERT_TRUE(platform_->WriteStringToFile(proc_mounts_, mount_contents)); |
| |
| EXPECT_CALL(*platform_, Mount(stateful_dev_image_, usrlocal_, _, MS_BIND, _)) |
| .WillOnce(Return(true)); |
| EXPECT_CALL(*platform_, Mount(base::FilePath(), usrlocal_, _, MS_REMOUNT, _)) |
| .WillOnce(Return(true)); |
| |
| base::FilePath portage = var_overlay_.Append("lib/portage"); |
| ASSERT_TRUE(platform_->CreateDirectory(portage)); |
| EXPECT_CALL(*platform_, Mount(portage, var_portage_, _, MS_BIND, _)) |
| .WillOnce(Return(true)); |
| |
| stateful_mount_->DevMountPackages(); |
| |
| EXPECT_TRUE(platform_->DirectoryExists(asan_dir_)); |
| |
| std::string mount_log_contents; |
| platform_->ReadFileToString(mount_log_, &mount_log_contents); |
| EXPECT_EQ(mount_contents, mount_log_contents); |
| |
| // 2 locations are allowed to have symlinks: portage and dev_image. |
| EXPECT_EQ( |
| base_dir_.Append("var/tmp/portage").value() + stateful_dev_image_.value(), |
| allow_sym_contents_); |
| } |
| |
| class RestoreContextsForVarTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| platform_ = std::make_unique<libstorage::FakePlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(), flags_, base_dir_, base_dir_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| } |
| |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| |
| std::unique_ptr<libstorage::FakePlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| }; |
| |
| TEST_F(RestoreContextsForVarTest, Restorecon) { |
| base::FilePath var = base_dir_.Append("var"); |
| ASSERT_TRUE(platform_->CreateDirectory(var)); |
| base::FilePath shadow = base_dir_.Append("home/.shadow"); |
| ASSERT_TRUE(platform_->CreateDirectory(shadow)); |
| base::FilePath cpu = base_dir_.Append("sys/devices/system/cpu"); |
| ASSERT_TRUE(platform_->CreateDirectory(cpu)); |
| |
| base::FilePath selinux = base_dir_.Append("sys/fs/selinux/enforce"); |
| ASSERT_TRUE(platform_->WriteStringToFile(selinux, "1")); |
| |
| startup_->RestoreContextsForVar(&RestoreconTestFunc); |
| |
| EXPECT_TRUE(platform_->FileExists(var.Append("restore"))); |
| EXPECT_TRUE(platform_->FileExists(shadow.Append("restore"))); |
| EXPECT_TRUE(platform_->FileExists(cpu.Append("restore"))); |
| } |
| |
| class RestorePreservedPathsTest : public ::testing::Test { |
| protected: |
| void SetUp() override { |
| platform_ = std::make_unique<libstorage::FakePlatform>(); |
| startup_dep_ = std::make_unique<startup::FakeStartupDep>(platform_.get()); |
| stateful_ = base_dir_.Append("stateful_test"); |
| platform_->CreateDirectory(stateful_); |
| std::unique_ptr<hwsec_foundation::MockTlclWrapper> tlcl = |
| std::make_unique<hwsec_foundation::MockTlclWrapper>(); |
| tlcl_ = tlcl.get(); |
| startup_ = std::make_unique<startup::ChromeosStartup>( |
| std::make_unique<vpd::Vpd>(), flags_, base_dir_, stateful_, base_dir_, |
| platform_.get(), startup_dep_.get(), |
| std::make_unique<startup::StandardMountHelper>( |
| platform_.get(), startup_dep_.get(), flags_, base_dir_, base_dir_), |
| std::move(tlcl)); |
| startup_->SetDevMode(true); |
| } |
| |
| std::unique_ptr<libstorage::FakePlatform> platform_; |
| std::unique_ptr<startup::FakeStartupDep> startup_dep_; |
| startup::Flags flags_{}; |
| base::FilePath base_dir_{"/"}; |
| base::FilePath stateful_; |
| hwsec_foundation::MockTlclWrapper* tlcl_; |
| |
| std::unique_ptr<startup::ChromeosStartup> startup_; |
| }; |
| |
| TEST_F(RestorePreservedPathsTest, PopPaths) { |
| std::string libservo("var/lib/servod"); |
| std::string wifi_cred("usr/local/etc/wifi_creds"); |
| base::FilePath preserve_dir = stateful_.Append("unencrypted/preserve"); |
| base::FilePath libservo_path = base_dir_.Append(libservo); |
| base::FilePath wifi_cred_path = base_dir_.Append(wifi_cred); |
| base::FilePath libservo_preserve = preserve_dir.Append(libservo); |
| base::FilePath wifi_cred_preserve = preserve_dir.Append(wifi_cred); |
| |
| ASSERT_TRUE( |
| platform_->WriteStringToFile(libservo_preserve.Append("file1"), "1")); |
| ASSERT_TRUE( |
| platform_->WriteStringToFile(wifi_cred_preserve.Append("file2"), "1")); |
| |
| startup_->RestorePreservedPaths(); |
| EXPECT_TRUE(platform_->FileExists(libservo_path.Append("file1"))); |
| EXPECT_TRUE(platform_->FileExists(wifi_cred_path.Append("file2"))); |
| EXPECT_FALSE(platform_->FileExists(libservo_preserve.Append("file1"))); |
| EXPECT_FALSE(platform_->FileExists(wifi_cred_preserve.Append("file2"))); |
| } |
| |
| } // namespace startup |