| // Copyright 2021 The ChromiumOS Authors | |
| // Use of this source code is governed by a BSD-style license that can be | |
| // found in the LICENSE file. | |
| #include "rmad/utils/futility_utils_impl.h" | |
| #include <cstdint> | |
| #include <memory> | |
| #include <utility> | |
| #include <base/files/file_path.h> | |
| #include <base/files/file_util.h> | |
| #include <base/files/scoped_temp_dir.h> | |
| #include <gmock/gmock.h> | |
| #include <gtest/gtest.h> | |
| #include "rmad/utils/hwid_utils_impl.h" | |
| #include "rmad/utils/mock_cmd_utils.h" | |
| using testing::_; | |
| using testing::DoAll; | |
| using testing::InSequence; | |
| using testing::Return; | |
| using testing::SetArgPointee; | |
| using testing::StrictMock; | |
| namespace { | |
| constexpr char kFutilityWriteProtectEnabledOutput[] = R"(WP status: enabled.)"; | |
| constexpr char kFutilityWriteProtectDisabledOutput[] = R"(WP status: disabled)"; | |
| constexpr char kFutilityWriteProtectMisconfiguredOutput[] = | |
| R"(WP status: misconfigured (srp = 1, start = 0000000000, length = 0000000000))"; | |
| } // namespace | |
| namespace rmad { | |
| class FutilityUtilsTest : public testing::Test { | |
| public: | |
| FutilityUtilsTest() = default; | |
| ~FutilityUtilsTest() override = default; | |
| protected: | |
| void SetUp() override { ASSERT_TRUE(temp_dir_.CreateUniqueTempDir()); } | |
| base::ScopedTempDir temp_dir_; | |
| }; | |
| TEST_F(FutilityUtilsTest, GetApWriteProtectionStatus_Enabled) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutput(_, _)) | |
| .WillOnce(DoAll(SetArgPointee<1>(kFutilityWriteProtectEnabledOutput), | |
| Return(true))); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| auto enabled = futility_utils->GetApWriteProtectionStatus(); | |
| EXPECT_TRUE(enabled.has_value()); | |
| EXPECT_TRUE(enabled.value()); | |
| } | |
| TEST_F(FutilityUtilsTest, GetApWriteProtectionStatus_Disabled) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutput(_, _)) | |
| .WillOnce(DoAll(SetArgPointee<1>(kFutilityWriteProtectDisabledOutput), | |
| Return(true))); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| auto enabled = futility_utils->GetApWriteProtectionStatus(); | |
| EXPECT_TRUE(enabled.has_value()); | |
| EXPECT_FALSE(enabled.value()); | |
| } | |
| TEST_F(FutilityUtilsTest, GetApWriteProtectionStatus_Misconfigured) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutput(_, _)) | |
| .WillOnce( | |
| DoAll(SetArgPointee<1>(kFutilityWriteProtectMisconfiguredOutput), | |
| Return(true))); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| auto enabled = futility_utils->GetApWriteProtectionStatus(); | |
| EXPECT_TRUE(enabled.has_value()); | |
| EXPECT_TRUE(enabled.value()); | |
| } | |
| TEST_F(FutilityUtilsTest, GetApWriteProtectionStatus_Failed) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutput(_, _)).WillOnce(Return(false)); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| auto enabled = futility_utils->GetApWriteProtectionStatus(); | |
| EXPECT_FALSE(enabled.has_value()); | |
| } | |
| TEST_F(FutilityUtilsTest, EnableApSoftwareWriteProtection_Success) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| { | |
| InSequence seq; | |
| // Futility set AP WP range. | |
| EXPECT_CALL(*mock_cmd_utils, GetOutput(_, _)).WillOnce(Return(true)); | |
| } | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| EXPECT_TRUE(futility_utils->EnableApSoftwareWriteProtection()); | |
| } | |
| TEST_F(FutilityUtilsTest, EnableApSoftwareWriteProtection_EnableApWpFail) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| { | |
| InSequence seq; | |
| // Futility set AP WP range. | |
| EXPECT_CALL(*mock_cmd_utils, GetOutput(_, _)).WillOnce(Return(false)); | |
| } | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| EXPECT_FALSE(futility_utils->EnableApSoftwareWriteProtection()); | |
| } | |
| TEST_F(FutilityUtilsTest, SetHwidSuccess) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutputAndError(_, _)).WillOnce(Return(true)); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| EXPECT_TRUE(futility_utils->SetHwid("MODEL-CODE A1B-C2D-E2J")); | |
| } | |
| TEST_F(FutilityUtilsTest, SetHwidInvalidHwidFormatFail) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutputAndError(_, _)).Times(0); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| EXPECT_FALSE(futility_utils->SetHwid("MODEL-CODE A1BC2DE2J")); | |
| } | |
| TEST_F(FutilityUtilsTest, SetHwidIncorrectChecksumFail) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutputAndError(_, _)).Times(0); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| EXPECT_FALSE(futility_utils->SetHwid("MODEL-CODE A1B-C2D-E2K")); | |
| } | |
| TEST_F(FutilityUtilsTest, SetHwidGetOutputFail) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutputAndError(_, _)).WillOnce(Return(false)); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| EXPECT_FALSE(futility_utils->SetHwid("MODEL-CODE A1B-C2D-E2J")); | |
| } | |
| TEST_F(FutilityUtilsTest, GetFlashSizeSuccess) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutputAndError(_, _)) | |
| .WillOnce( | |
| DoAll(SetArgPointee<1>("Flash size: 0x00800000"), Return(true))); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| auto size = futility_utils->GetFlashSize(); | |
| const uint64_t expected = 0x800000; | |
| EXPECT_TRUE(size.has_value()); | |
| EXPECT_EQ(expected, size.value()); | |
| } | |
| TEST_F(FutilityUtilsTest, GetFlashSizeGetOutputAndErrorFail) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutputAndError(_, _)).WillOnce(Return(false)); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| auto size = futility_utils->GetFlashSize(); | |
| EXPECT_FALSE(size.has_value()); | |
| } | |
| TEST_F(FutilityUtilsTest, GetFlashSizeFailToParseFail) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutputAndError(_, _)) | |
| .WillOnce( | |
| DoAll(SetArgPointee<1>("Flash size: 0xGGGGGGGG"), Return(true))); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| auto size = futility_utils->GetFlashSize(); | |
| EXPECT_FALSE(size.has_value()); | |
| } | |
| TEST_F(FutilityUtilsTest, GetFlashInfoSuccess) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutputAndError(_, _)) | |
| .WillOnce(DoAll(SetArgPointee<1>( | |
| "PR0: Warning: 0xFFFFFFFF-0xFFFFFFFF is read-only.\n" | |
| "GPR0: Warning: 0xFFFFFFFF-0xFFFFFFFF is read-only.\n" | |
| "At least some flash regions are write protected. " | |
| "For write operations,\n" | |
| "you should use a flash layout and include only " | |
| "writable regions. See\n" | |
| "manpage for more details.\n" | |
| "Flash vendor: test vendor\n" | |
| "Flash name: test flash name\n" | |
| "Flash vid-pid: 0xFFFFFFFFFF\n" | |
| "Flash size: 0xFFFFFFFF\n" | |
| "Warning: Setting BIOS Control at 0xaa from 0xbb to " | |
| "0xcc failed.\n" | |
| "New value is 0xFF.\n" | |
| "Expected WP SR configuration by FW image: (start = " | |
| "0x11110000, length = 0xffff0000)"), | |
| Return(true))); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| auto flash_info = futility_utils->GetFlashInfo(); | |
| const std::string expected_flash_name = "test flash name"; | |
| const uint64_t expected_start = 0x11110000; | |
| const uint64_t expected_length = 0xffff0000; | |
| EXPECT_TRUE(flash_info.has_value()); | |
| EXPECT_EQ(expected_flash_name, flash_info->flash_name); | |
| EXPECT_EQ(expected_start, flash_info->wpsr_start); | |
| EXPECT_EQ(expected_length, flash_info->wpsr_length); | |
| } | |
| TEST_F(FutilityUtilsTest, GetArmFlashInfoSuccess) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutputAndError(_, _)) | |
| .WillOnce(DoAll( | |
| SetArgPointee<1>("Flash vendor: Programmer\n" | |
| "Flash name: Opaque flash chip\n" | |
| "Flash vid-pid: 0x000000000000\n" | |
| "Flash size: 0x00000000\n" | |
| "Expected WP SR configuration by FW image: (start = " | |
| "0x00000000, length = 0xFFFFFFFF)"), | |
| Return(true))); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| temp_dir_.GetPath()); | |
| auto partname_path = temp_dir_.GetPath().AppendASCII("partname"); | |
| ASSERT_TRUE(base::WriteFile(partname_path, "test arm flash name \n")); | |
| auto flash_info = futility_utils->GetFlashInfo(); | |
| const std::string expected_flash_name = "test arm flash name"; | |
| const uint64_t expected_start = 0x00000000; | |
| const uint64_t expected_length = 0xFFFFFFFF; | |
| EXPECT_TRUE(flash_info.has_value()); | |
| EXPECT_EQ(expected_flash_name, flash_info->flash_name); | |
| EXPECT_EQ(expected_start, flash_info->wpsr_start); | |
| EXPECT_EQ(expected_length, flash_info->wpsr_length); | |
| } | |
| TEST_F(FutilityUtilsTest, GetFlashInfoGetOutputAndErrorFail) { | |
| auto mock_cmd_utils = std::make_unique<StrictMock<MockCmdUtils>>(); | |
| EXPECT_CALL(*mock_cmd_utils, GetOutputAndError(_, _)).WillOnce(Return(false)); | |
| auto futility_utils = std::make_unique<FutilityUtilsImpl>( | |
| std::move(mock_cmd_utils), std::make_unique<HwidUtilsImpl>(), | |
| base::FilePath()); | |
| auto flash_info = futility_utils->GetFlashInfo(); | |
| EXPECT_FALSE(flash_info.has_value()); | |
| } | |
| } // namespace rmad |