summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--omaha_request_action.cc67
-rw-r--r--omaha_request_action.h16
-rw-r--r--omaha_request_action_unittest.cc198
-rw-r--r--update_manager/rollback_prefs.h4
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.