Don't allow rollback when we are enterprise enrolled.
As stated (and verified) by the device_policy protobuf, we can determine
whether a device is enterprise enrolled by checking if GetOwner is empty.
We use this knowledge to not allow rollback when powerwash is also requested (
the default).
As part of this CL I've figured out how to unittest Rollback and added tests
for both enterprise and non-enterprise rollback.
BUG=chromium:254829
TEST=Tested on both an enrolled and non-enrolled device. Verified only the
latter actually did a powerwash while the other aborted correctly. Also ran
new unittests
Change-Id: Idfe6bfef88819fe1bab7da6b31854faf7642c9ce
Reviewed-on: https://gerrit.chromium.org/gerrit/61645
Reviewed-by: David Zeuthen <zeuthen@chromium.org>
Commit-Queue: Chris Sosa <sosa@chromium.org>
Tested-by: Chris Sosa <sosa@chromium.org>
diff --git a/dbus_service.cc b/dbus_service.cc
index 8619b2d..bc84858 100644
--- a/dbus_service.cc
+++ b/dbus_service.cc
@@ -110,7 +110,7 @@
bool powerwash,
GError **error) {
LOG(INFO) << "Attempting rollback to non-active partitions.";
- return self->system_state_->update_attempter()->Rollback(powerwash);
+ return self->system_state_->update_attempter()->Rollback(powerwash, NULL);
}
gboolean update_engine_service_reset_status(UpdateEngineService* self,
diff --git a/install_plan.h b/install_plan.h
index b070cbe..c2f523e 100644
--- a/install_plan.h
+++ b/install_plan.h
@@ -99,7 +99,10 @@
processor_->ActionComplete(this, kErrorCodeSuccess);
}
- virtual std::string Type() const { return "InstallPlanAction"; }
+ InstallPlan* install_plan() { return &install_plan_; }
+
+ static std::string StaticType() { return "InstallPlanAction"; }
+ virtual std::string Type() const { return StaticType(); }
typedef ActionTraits<InstallPlanAction>::InputObjectType InputObjectType;
typedef ActionTraits<InstallPlanAction>::OutputObjectType OutputObjectType;
diff --git a/update_attempter.cc b/update_attempter.cc
index ca6643b..4104739 100644
--- a/update_attempter.cc
+++ b/update_attempter.cc
@@ -544,7 +544,7 @@
}
}
-bool UpdateAttempter::Rollback(bool powerwash) {
+bool UpdateAttempter::Rollback(bool powerwash, string *install_path) {
CHECK(!processor_->IsRunning());
processor_->set_delegate(this);
@@ -554,11 +554,27 @@
LOG(INFO) << "Setting rollback options.";
InstallPlan install_plan;
- TEST_AND_RETURN_FALSE(utils::GetInstallDev(utils::BootDevice(),
- &install_plan.install_path));
+ if (install_path == NULL) {
+ TEST_AND_RETURN_FALSE(utils::GetInstallDev(utils::BootDevice(),
+ &install_plan.install_path));
+ }
+ else {
+ install_plan.install_path = *install_path;
+ }
+
install_plan.kernel_install_path = utils::BootKernelDevice(
install_plan.install_path);
install_plan.powerwash_required = powerwash;
+ if (powerwash) {
+ // Enterprise-enrolled devices have an empty owner in their device policy.
+ string owner;
+ const policy::DevicePolicy* device_policy = system_state_->device_policy();
+ if (!device_policy->GetOwner(&owner) || owner.empty()) {
+ LOG(ERROR) << "Enterprise device detected. "
+ << "Cannot perform a powerwash for enterprise devices.";
+ return false;
+ }
+ }
LOG(INFO) << "Using this install plan:";
install_plan.Dump();
diff --git a/update_attempter.h b/update_attempter.h
index d6015ee..423fb88 100644
--- a/update_attempter.h
+++ b/update_attempter.h
@@ -147,8 +147,9 @@
// This is the internal entry point for going through a rollback. This will
// attempt to run the postinstall on the non-active partition and set it as
// the partition to boot from. If |powerwash| is True, perform a powerwash
- // as part of rollback. Returns True on success.
- bool Rollback(bool powerwash);
+ // as part of rollback. If |install_path| is set, use this value to determine
+ // the partitions to roll back to (used in testing). Returns True on success.
+ bool Rollback(bool powerwash, std::string* install_path);
// Initiates a reboot if the current state is
// UPDATED_NEED_REBOOT. Returns true on sucess, false otherwise.
diff --git a/update_attempter_unittest.cc b/update_attempter_unittest.cc
index 095de23..2de8ca2 100644
--- a/update_attempter_unittest.cc
+++ b/update_attempter_unittest.cc
@@ -10,6 +10,7 @@
#include "update_engine/action_mock.h"
#include "update_engine/action_processor_mock.h"
#include "update_engine/filesystem_copier_action.h"
+#include "update_engine/install_plan.h"
#include "update_engine/mock_dbus_interface.h"
#include "update_engine/mock_http_fetcher.h"
#include "update_engine/mock_payload_state.h"
@@ -74,8 +75,13 @@
void UpdateTestStart();
void UpdateTestVerify();
+ void RollbackTestStart(bool enterprise_rollback);
+ void RollbackTestVerify();
static gboolean StaticUpdateTestStart(gpointer data);
static gboolean StaticUpdateTestVerify(gpointer data);
+ static gboolean StaticRollbackTestStart(gpointer data);
+ static gboolean StaticEnterpriseRollbackTestStart(gpointer data);
+ static gboolean StaticRollbackTestVerify(gpointer data);
void PingOmahaTestStart();
static gboolean StaticPingOmahaTestStart(gpointer data);
@@ -302,6 +308,21 @@
return FALSE;
}
+gboolean UpdateAttempterTest::StaticRollbackTestStart(gpointer data) {
+ reinterpret_cast<UpdateAttempterTest*>(data)->RollbackTestStart(false);
+ return FALSE;
+}
+
+gboolean UpdateAttempterTest::StaticEnterpriseRollbackTestStart(gpointer data) {
+ reinterpret_cast<UpdateAttempterTest*>(data)->RollbackTestStart(true);
+ return FALSE;
+}
+
+gboolean UpdateAttempterTest::StaticRollbackTestVerify(gpointer data) {
+ reinterpret_cast<UpdateAttempterTest*>(data)->RollbackTestVerify();
+ return FALSE;
+}
+
gboolean UpdateAttempterTest::StaticPingOmahaTestStart(gpointer data) {
reinterpret_cast<UpdateAttempterTest*>(data)->PingOmahaTestStart();
return FALSE;
@@ -350,7 +371,8 @@
}
namespace {
-const string kActionTypes[] = {
+// Actions that will be built as part of an update check.
+const string kUpdateActionTypes[] = {
OmahaRequestAction::StaticType(),
OmahaResponseHandlerAction::StaticType(),
FilesystemCopierAction::StaticType(),
@@ -363,15 +385,22 @@
PostinstallRunnerAction::StaticType(),
OmahaRequestAction::StaticType()
};
+
+// Actions that will be built as part of a user-initiated rollback.
+const string kRollbackActionTypes[] = {
+ InstallPlanAction::StaticType(),
+ PostinstallRunnerAction::StaticType(),
+};
+
} // namespace {}
void UpdateAttempterTest::UpdateTestStart() {
attempter_.set_http_response_code(200);
InSequence s;
- for (size_t i = 0; i < arraysize(kActionTypes); ++i) {
+ for (size_t i = 0; i < arraysize(kUpdateActionTypes); ++i) {
EXPECT_CALL(*processor_,
EnqueueAction(Property(&AbstractAction::Type,
- kActionTypes[i]))).Times(1);
+ kUpdateActionTypes[i]))).Times(1);
}
EXPECT_CALL(*processor_, StartProcessing()).Times(1);
@@ -382,9 +411,9 @@
void UpdateAttempterTest::UpdateTestVerify() {
EXPECT_EQ(0, attempter_.http_response_code());
EXPECT_EQ(&attempter_, processor_->delegate());
- EXPECT_EQ(arraysize(kActionTypes), attempter_.actions_.size());
- for (size_t i = 0; i < arraysize(kActionTypes); ++i) {
- EXPECT_EQ(kActionTypes[i], attempter_.actions_[i]->Type());
+ EXPECT_EQ(arraysize(kUpdateActionTypes), attempter_.actions_.size());
+ for (size_t i = 0; i < arraysize(kUpdateActionTypes); ++i) {
+ EXPECT_EQ(kUpdateActionTypes[i], attempter_.actions_[i]->Type());
}
EXPECT_EQ(attempter_.response_handler_action_.get(),
attempter_.actions_[1].get());
@@ -396,6 +425,62 @@
g_main_loop_quit(loop_);
}
+void UpdateAttempterTest::RollbackTestStart(bool enterprise_rollback) {
+ // Create a device policy so that we can change settings.
+ policy::MockDevicePolicy* device_policy = new policy::MockDevicePolicy();
+ attempter_.policy_provider_.reset(new policy::PolicyProvider(device_policy));
+
+ EXPECT_CALL(*device_policy, LoadPolicy()).WillRepeatedly(Return(true));
+ EXPECT_CALL(mock_system_state_, device_policy()).WillRepeatedly(
+ Return(device_policy));
+
+ string install_path = "/dev/sda3";
+
+ // Non-enterprise enrolled device account with an owner in the device policy.
+ if (!enterprise_rollback) {
+ EXPECT_CALL(*device_policy, GetOwner(_)).WillOnce(
+ DoAll(SetArgumentPointee<0>(std::string("fake.mail@fake.com")),
+ Return(true)));
+
+ InSequence s;
+ for (size_t i = 0; i < arraysize(kRollbackActionTypes); ++i) {
+ EXPECT_CALL(*processor_,
+ EnqueueAction(Property(&AbstractAction::Type,
+ kRollbackActionTypes[i]))).Times(1);
+ }
+ EXPECT_CALL(*processor_, StartProcessing()).Times(1);
+
+ EXPECT_TRUE(attempter_.Rollback(true, &install_path));
+ g_idle_add(&StaticRollbackTestVerify, this);
+ } else {
+ // We return an empty owner as this is an enterprise.
+ EXPECT_CALL(*device_policy, GetOwner(_)).WillOnce(
+ DoAll(SetArgumentPointee<0>(std::string("")),
+ Return(true)));
+
+ // We do not currently support rollbacks for enterprises.
+ EXPECT_FALSE(attempter_.Rollback(true, &install_path));
+ g_main_loop_quit(loop_);
+ }
+}
+
+void UpdateAttempterTest::RollbackTestVerify() {
+ // Verifies the actions that were enqueued.
+ EXPECT_EQ(&attempter_, processor_->delegate());
+ EXPECT_EQ(arraysize(kRollbackActionTypes), attempter_.actions_.size());
+ for (size_t i = 0; i < arraysize(kRollbackActionTypes); ++i) {
+ EXPECT_EQ(kRollbackActionTypes[i], attempter_.actions_[i]->Type());
+ }
+ EXPECT_EQ(UPDATE_STATUS_ATTEMPTING_ROLLBACK, attempter_.status());
+ InstallPlanAction* install_plan_action =
+ dynamic_cast<InstallPlanAction*>(attempter_.actions_[0].get());
+ InstallPlan* install_plan = install_plan_action->install_plan();
+ EXPECT_EQ(install_plan->install_path, string("/dev/sda3"));
+ EXPECT_EQ(install_plan->kernel_install_path, string("/dev/sda2"));
+ EXPECT_EQ(install_plan->powerwash_required, true);
+ g_main_loop_quit(loop_);
+}
+
TEST_F(UpdateAttempterTest, UpdateTest) {
loop_ = g_main_loop_new(g_main_context_default(), FALSE);
g_idle_add(&StaticUpdateTestStart, this);
@@ -404,6 +489,22 @@
loop_ = NULL;
}
+TEST_F(UpdateAttempterTest, RollbackTest) {
+ loop_ = g_main_loop_new(g_main_context_default(), FALSE);
+ g_idle_add(&StaticRollbackTestStart, this);
+ g_main_loop_run(loop_);
+ g_main_loop_unref(loop_);
+ loop_ = NULL;
+}
+
+TEST_F(UpdateAttempterTest, EnterpriseRollbackTest) {
+ loop_ = g_main_loop_new(g_main_context_default(), FALSE);
+ g_idle_add(&StaticEnterpriseRollbackTestStart, this);
+ g_main_loop_run(loop_);
+ g_main_loop_unref(loop_);
+ loop_ = NULL;
+}
+
void UpdateAttempterTest::PingOmahaTestStart() {
EXPECT_CALL(*processor_,
EnqueueAction(Property(&AbstractAction::Type,
diff --git a/utils.cc b/utils.cc
index 2bcc311..9d3bd26 100644
--- a/utils.cc
+++ b/utils.cc
@@ -572,7 +572,7 @@
}
const string BootKernelDevice(const std::string& boot_device) {
- // Currntly this assumes the last digit of the boot device is
+ // Currently this assumes the last digit of the boot device is
// 3, 5, or 7, and changes it to 2, 4, or 6, respectively, to
// get the kernel device.
string ret = boot_device;