diff options
| -rw-r--r-- | omaha_request_action.cc | 67 | ||||
| -rw-r--r-- | omaha_request_action.h | 16 | ||||
| -rw-r--r-- | omaha_request_action_unittest.cc | 198 | ||||
| -rw-r--r-- | update_manager/rollback_prefs.h | 4 |
4 files changed, 284 insertions, 1 deletions
diff --git a/omaha_request_action.cc b/omaha_request_action.cc index d08768e4..424cb667 100644 --- a/omaha_request_action.cc +++ b/omaha_request_action.cc @@ -35,6 +35,7 @@ #include <brillo/key_value_store.h> #include <expat.h> #include <metrics/metrics_library.h> +#include <policy/libpolicy.h> #include "update_engine/common/action_pipe.h" #include "update_engine/common/constants.h" @@ -52,6 +53,7 @@ using base::Time; using base::TimeDelta; +using chromeos_update_manager::kRollforwardInfinity; using std::map; using std::string; using std::vector; @@ -619,12 +621,14 @@ OmahaRequestAction::OmahaRequestAction( std::unique_ptr<HttpFetcher> http_fetcher, bool ping_only) : system_state_(system_state), + params_(system_state->request_params()), event_(event), http_fetcher_(std::move(http_fetcher)), + policy_provider_(std::make_unique<policy::PolicyProvider>()), ping_only_(ping_only), ping_active_days_(0), ping_roll_call_days_(0) { - params_ = system_state->request_params(); + policy_provider_->Reload(); } OmahaRequestAction::~OmahaRequestAction() {} @@ -1195,6 +1199,9 @@ void OmahaRequestAction::TransferComplete(HttpFetcher *fetcher, payload_state->SetUsingP2PForSharing(false); } + // Set the max kernel key version based on whether rollback is allowed. + SetMaxKernelKeyVersionForRollback(); + // Update the payload state with the current response. The payload state // will automatically reset all stale state if this response is different // from what's stored already. We are updating the payload state as late @@ -1799,4 +1806,62 @@ bool OmahaRequestAction::IsUpdateAllowedOverCurrentConnection( return is_allowed; } +bool OmahaRequestAction::IsRollbackEnabled() const { + if (policy_provider_->IsConsumerDevice()) { + LOG(INFO) << "Rollback is not enabled for consumer devices."; + return false; + } + + if (!policy_provider_->device_policy_is_loaded()) { + LOG(INFO) << "No device policy is loaded. Assuming rollback enabled."; + return true; + } + + int allowed_milestones; + if (!policy_provider_->GetDevicePolicy().GetRollbackAllowedMilestones( + &allowed_milestones)) { + LOG(INFO) << "RollbackAllowedMilestones policy can't be read. " + "Defaulting to rollback enabled."; + return true; + } + + LOG(INFO) << "Rollback allows " << allowed_milestones << " milestones."; + return allowed_milestones > 0; +} + +void OmahaRequestAction::SetMaxKernelKeyVersionForRollback() const { + bool max_rollforward_set = false; + if (IsRollbackEnabled()) { + // If rollback is enabled, set the max kernel key version to the current + // kernel key version. This has the effect of freezing kernel key roll + // forwards. + // + // TODO(zentaro): This behavior is temporary, and ensures that no kernel + // key roll forward happens until the server side components of rollback + // are implemented. Future changes will allow the Omaha server to return + // the kernel key version from max_rollback_versions in the past. At that + // point the max kernel key version will be set to that value, creating a + // sliding window of versions that can be rolled back to. + int min_kernel_version = + system_state_->hardware()->GetMinKernelKeyVersion(); + LOG(INFO) << "Rollback is enabled. Setting max_kernel_rollforward to " + << min_kernel_version; + max_rollforward_set = system_state_->hardware()->SetMaxKernelKeyRollforward( + min_kernel_version); + } else { + // For devices that are not rollback enabled (ie. consumer devices), the + // max kernel key version is set to 0xfffffffe, which is logically + // infinity. This maintains the previous behavior that that kernel key + // versions roll forward each time they are incremented. + LOG(INFO) << "Rollback is disabled. Setting max_kernel_rollforward to " + << kRollforwardInfinity; + max_rollforward_set = system_state_->hardware()->SetMaxKernelKeyRollforward( + kRollforwardInfinity); + } + + if (!max_rollforward_set) { + LOG(ERROR) << "Failed to set max_kernel_rollforward"; + } +} + } // namespace chromeos_update_engine diff --git a/omaha_request_action.h b/omaha_request_action.h index f1c4a021..7f526ec1 100644 --- a/omaha_request_action.h +++ b/omaha_request_action.h @@ -39,6 +39,10 @@ // The Omaha Request action makes a request to Omaha and can output // the response on the output ActionPipe. +namespace policy { +class PolicyProvider; +} + namespace chromeos_update_engine { // Encodes XML entities in a given string. Input must be ASCII-7 valid. If @@ -172,6 +176,7 @@ class OmahaRequestAction : public Action<OmahaRequestAction>, bool IsEvent() const { return event_.get() != nullptr; } private: + friend class OmahaRequestActionTest; FRIEND_TEST(OmahaRequestActionTest, GetInstallDateWhenNoPrefsNorOOBE); FRIEND_TEST(OmahaRequestActionTest, GetInstallDateWhenOOBECompletedWithInvalidDate); @@ -303,6 +308,14 @@ class OmahaRequestAction : public Action<OmahaRequestAction>, bool IsUpdateAllowedOverCurrentConnection( ErrorCode* error, const OmahaResponse& response) const; + // Returns true if rollback is enabled. Always returns false for consumer + // devices. + bool IsRollbackEnabled() const; + + // Sets the appropriate max kernel key version based on whether rollback is + // enabled. + void SetMaxKernelKeyVersionForRollback() const; + // Global system context. SystemState* system_state_; @@ -315,6 +328,9 @@ class OmahaRequestAction : public Action<OmahaRequestAction>, // pointer to the HttpFetcher that does the http work std::unique_ptr<HttpFetcher> http_fetcher_; + // Used for fetching information about the device policy. + std::unique_ptr<policy::PolicyProvider> policy_provider_; + // If true, only include the <ping> element in the request. bool ping_only_; diff --git a/omaha_request_action_unittest.cc b/omaha_request_action_unittest.cc index 73da467b..cb6c5bdb 100644 --- a/omaha_request_action_unittest.cc +++ b/omaha_request_action_unittest.cc @@ -20,6 +20,7 @@ #include <memory> #include <string> +#include <utility> #include <vector> #include <base/bind.h> @@ -35,6 +36,8 @@ #include <brillo/message_loops/message_loop.h> #include <brillo/message_loops/message_loop_utils.h> #include <gtest/gtest.h> +#include <policy/libpolicy.h> +#include <policy/mock_libpolicy.h> #include "update_engine/common/action_pipe.h" #include "update_engine/common/constants.h" @@ -49,9 +52,11 @@ #include "update_engine/mock_connection_manager.h" #include "update_engine/mock_payload_state.h" #include "update_engine/omaha_request_params.h" +#include "update_engine/update_manager/rollback_prefs.h" using base::Time; using base::TimeDelta; +using chromeos_update_manager::kRollforwardInfinity; using std::string; using std::vector; using testing::AllOf; @@ -61,6 +66,7 @@ using testing::Ge; using testing::Le; using testing::NiceMock; using testing::Return; +using testing::ReturnRef; using testing::ReturnPointee; using testing::SaveArg; using testing::SetArgPointee; @@ -68,6 +74,10 @@ using testing::_; namespace { +static_assert(kRollforwardInfinity == 0xfffffffe, + "Don't change the value of kRollforward infinity unless its " + "size has been changed in firmware."); + const char kTestAppId[] = "test-app-id"; const char kTestAppId2[] = "test-app2-id"; @@ -254,6 +264,21 @@ class OmahaRequestActionTest : public ::testing::Test { bool TestUpdateCheck(const string& http_response, int fail_http_response_code, bool ping_only, + bool is_consumer_device, + int rollback_allowed_milestones, + bool is_policy_loaded, + ErrorCode expected_code, + metrics::CheckResult expected_check_result, + metrics::CheckReaction expected_check_reaction, + metrics::DownloadErrorCode expected_download_error_code, + OmahaResponse* out_response, + brillo::Blob* out_post_data); + + // Overload of TestUpdateCheck that does not supply |is_consumer_device| or + // |rollback_allowed_milestones| which are only required for rollback tests. + bool TestUpdateCheck(const string& http_response, + int fail_http_response_code, + bool ping_only, ErrorCode expected_code, metrics::CheckResult expected_check_result, metrics::CheckReaction expected_check_reaction, @@ -261,6 +286,10 @@ class OmahaRequestActionTest : public ::testing::Test { OmahaResponse* out_response, brillo::Blob* out_post_data); + void TestRollbackCheck(bool is_consumer_device, + int rollback_allowed_milestones, + bool is_policy_loaded); + // Runs and checks a ping test. |ping_only| indicates whether it should send // only a ping or also an updatecheck. void PingTest(bool ping_only); @@ -357,6 +386,9 @@ bool OmahaRequestActionTest::TestUpdateCheck( const string& http_response, int fail_http_response_code, bool ping_only, + bool is_consumer_device, + int rollback_allowed_milestones, + bool is_policy_loaded, ErrorCode expected_code, metrics::CheckResult expected_check_result, metrics::CheckReaction expected_check_reaction, @@ -379,6 +411,24 @@ bool OmahaRequestActionTest::TestUpdateCheck( nullptr, base::WrapUnique(fetcher), ping_only); + auto mock_policy_provider = + std::make_unique<NiceMock<policy::MockPolicyProvider>>(); + EXPECT_CALL(*mock_policy_provider, IsConsumerDevice()) + .WillRepeatedly(Return(is_consumer_device)); + + EXPECT_CALL(*mock_policy_provider, device_policy_is_loaded()) + .WillRepeatedly(Return(is_policy_loaded)); + + const policy::MockDevicePolicy device_policy; + const bool get_allowed_milestone_succeeds = rollback_allowed_milestones >= 0; + EXPECT_CALL(device_policy, GetRollbackAllowedMilestones(_)) + .WillRepeatedly(DoAll(SetArgPointee<0>(rollback_allowed_milestones), + Return(get_allowed_milestone_succeeds))); + + EXPECT_CALL(*mock_policy_provider, GetDevicePolicy()) + .WillRepeatedly(ReturnRef(device_policy)); + + action.policy_provider_ = std::move(mock_policy_provider); OmahaRequestActionTestProcessorDelegate delegate; delegate.expected_code_ = expected_code; @@ -413,6 +463,50 @@ bool OmahaRequestActionTest::TestUpdateCheck( return collector_action.has_input_object_; } +bool OmahaRequestActionTest::TestUpdateCheck( + const string& http_response, + int fail_http_response_code, + bool ping_only, + ErrorCode expected_code, + metrics::CheckResult expected_check_result, + metrics::CheckReaction expected_check_reaction, + metrics::DownloadErrorCode expected_download_error_code, + OmahaResponse* out_response, + brillo::Blob* out_post_data) { + return TestUpdateCheck(http_response, + fail_http_response_code, + ping_only, + true, // is_consumer_device + 0, // rollback_allowed_milestones + false, // is_policy_loaded + expected_code, + expected_check_result, + expected_check_reaction, + expected_download_error_code, + out_response, + out_post_data); +} + +void OmahaRequestActionTest::TestRollbackCheck(bool is_consumer_device, + int rollback_allowed_milestones, + bool is_policy_loaded) { + OmahaResponse response; + fake_update_response_.deadline = "20101020"; + ASSERT_TRUE(TestUpdateCheck(fake_update_response_.GetUpdateResponse(), + -1, + false, // ping_only + is_consumer_device, + rollback_allowed_milestones, + is_policy_loaded, + ErrorCode::kSuccess, + metrics::CheckResult::kUpdateAvailable, + metrics::CheckReaction::kUpdating, + metrics::DownloadErrorCode::kUnset, + &response, + nullptr)); + ASSERT_TRUE(response.update_exists); +} + // Tests Event requests -- they should always succeed. |out_post_data| // may be null; if non-null, the post-data received by the mock // HttpFetcher is returned. @@ -2593,4 +2687,108 @@ TEST_F(OmahaRequestActionTest, GetInstallDateWhenOOBECompletedDateChanges) { EXPECT_EQ(prefs_days, 28); } +// Verifies that a device with no device policy, and is not a consumer +// device sets the max kernel key version to the current version. +// ie. the same behavior as if rollback is enabled. +TEST_F(OmahaRequestActionTest, NoPolicyEnterpriseDevicesSetMaxRollback) { + FakeHardware* fake_hw = fake_system_state_.fake_hardware(); + + // Setup and verify some initial default values for the kernel TPM + // values that control verified boot and rollback. + const int min_kernel_version = 4; + fake_hw->SetMinKernelKeyVersion(min_kernel_version); + fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity); + EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion()); + EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward()); + + TestRollbackCheck(false /* is_consumer_device */, + 3 /* rollback_allowed_milestones */, + false /* is_policy_loaded */); + + // Verify max_kernel_rollforward was set to the current minimum + // kernel key version. This has the effect of freezing roll + // forwards indefinitely. This will hold the rollback window + // open until a future change will be able to move this forward + // relative the configured window. + EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion()); + EXPECT_EQ(min_kernel_version, fake_hw->GetMaxKernelKeyRollforward()); +} + +// Verifies that a conmsumer device with no device policy sets the +// max kernel key version to the current version. ie. the same +// behavior as if rollback is enabled. +TEST_F(OmahaRequestActionTest, NoPolicyConsumerDevicesSetMaxRollback) { + FakeHardware* fake_hw = fake_system_state_.fake_hardware(); + + // Setup and verify some initial default values for the kernel TPM + // values that control verified boot and rollback. + const int min_kernel_version = 3; + fake_hw->SetMinKernelKeyVersion(min_kernel_version); + fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity); + EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion()); + EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward()); + + TestRollbackCheck(true /* is_consumer_device */, + 3 /* rollback_allowed_milestones */, + false /* is_policy_loaded */); + + // Verify that with rollback disabled that max_kernel_rollforward + // was set to logical infinity. This is the expected behavior for + // consumer devices and matches the existing behavior prior to the + // rollback features. + EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion()); + EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward()); +} + +// Verifies that a device with rollback enabled sets max_kernel_rollforward +// in the TPM to prevent roll forward. +TEST_F(OmahaRequestActionTest, RollbackEnabledDevicesSetMaxRollback) { + FakeHardware* fake_hw = fake_system_state_.fake_hardware(); + + // Setup and verify some initial default values for the kernel TPM + // values that control verified boot and rollback. + const int allowed_milestones = 4; + const int min_kernel_version = 3; + fake_hw->SetMinKernelKeyVersion(min_kernel_version); + fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity); + EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion()); + EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward()); + + TestRollbackCheck(false /* is_consumer_device */, + allowed_milestones, + true /* is_policy_loaded */); + + // Verify that with rollback enabled that max_kernel_rollforward + // was set to the current minimum kernel key version. This has + // the effect of freezing roll forwards indefinitely. This will + // hold the rollback window open until a future change will + // be able to move this forward relative the configured window. + EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion()); + EXPECT_EQ(min_kernel_version, fake_hw->GetMaxKernelKeyRollforward()); +} + +// Verifies that a device with rollback disabled sets max_kernel_rollforward +// in the TPM to logical infinity, to allow roll forward. +TEST_F(OmahaRequestActionTest, RollbackDisabledDevicesSetMaxRollback) { + FakeHardware* fake_hw = fake_system_state_.fake_hardware(); + + // Setup and verify some initial default values for the kernel TPM + // values that control verified boot and rollback. + const int allowed_milestones = 0; + const int min_kernel_version = 3; + fake_hw->SetMinKernelKeyVersion(min_kernel_version); + fake_hw->SetMaxKernelKeyRollforward(kRollforwardInfinity); + EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion()); + EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward()); + + TestRollbackCheck(false /* is_consumer_device */, + allowed_milestones, + true /* is_policy_loaded */); + + // Verify that with rollback disabled that max_kernel_rollforward + // was set to logical infinity. + EXPECT_EQ(min_kernel_version, fake_hw->GetMinKernelKeyVersion()); + EXPECT_EQ(kRollforwardInfinity, fake_hw->GetMaxKernelKeyRollforward()); +} + } // namespace chromeos_update_engine diff --git a/update_manager/rollback_prefs.h b/update_manager/rollback_prefs.h index 0305a466..1783eb00 100644 --- a/update_manager/rollback_prefs.h +++ b/update_manager/rollback_prefs.h @@ -19,6 +19,10 @@ namespace chromeos_update_manager { +// Value used to represent that kernel key versions can always roll-forward. +// This is the maximum value of a kernel key version. +constexpr int kRollforwardInfinity = 0xfffffffe; + // Whether the device should roll back to the target version, and if yes, which // type of rollback should it do. Matches chrome_device_policy.proto's // AutoUpdateSettingsProto::RollbackToTargetVersion. |
