Commit 88298ea2 authored by Nicholas Hollingum's avatar Nicholas Hollingum Committed by Commit Bot

borealis: Refactor tasks to be sequence-mutually exclusive

Tasks are deleted on completion (even before crrev.com/c/2507234), this
caused a UAF when a member-object of the AwaitBorealisStartup task was
transitively deleted but its callee.

The chosen solution is to post completion as a separate task rather than
call it from the current completing BorealisTask, we do this is a
mutually-exclusive way so that the deletion of the task is
exclusively-after its completion.

Bug: b/172605172
Change-Id: Iaf23e9ead37196988b24753cef451da318c48436
Reviewed-on: https://chromium-review.googlesource.com/c/chromium/src/+/2521876Reviewed-by: default avatarDaniel Ng <danielng@google.com>
Commit-Queue: Nic Hollingum <hollingum@google.com>
Cr-Commit-Position: refs/heads/master@{#824745}
parent 99167605
...@@ -36,14 +36,13 @@ MATCHER(IsFailureResult, "") { ...@@ -36,14 +36,13 @@ MATCHER(IsFailureResult, "") {
class MockTask : public BorealisTask { class MockTask : public BorealisTask {
public: public:
explicit MockTask(bool success) : success_(success) {} explicit MockTask(bool success) : success_(success) {}
void Run(BorealisContext* context, void RunInternal(BorealisContext* context) override {
BorealisTask::CompletionStatusCallback callback) override {
if (success_) { if (success_) {
context->set_vm_name("test_vm_name"); context->set_vm_name("test_vm_name");
std::move(callback).Run(BorealisContextManager::Status::kSuccess, ""); Complete(BorealisContextManager::Status::kSuccess, "");
} else { } else {
// Just use a random error. // Just use a random error.
std::move(callback).Run(BorealisContextManager::Status::kStartVmFailed, Complete(BorealisContextManager::Status::kStartVmFailed,
"Something went wrong!"); "Something went wrong!");
} }
} }
...@@ -211,8 +210,7 @@ class NeverCompletingContextManager : public BorealisContextManagerImpl { ...@@ -211,8 +210,7 @@ class NeverCompletingContextManager : public BorealisContextManagerImpl {
private: private:
class NeverCompletingTask : public BorealisTask { class NeverCompletingTask : public BorealisTask {
public: public:
void Run(BorealisContext* context, void RunInternal(BorealisContext* context) override {}
CompletionStatusCallback callback) override {}
}; };
base::queue<std::unique_ptr<BorealisTask>> GetTasks() override { base::queue<std::unique_ptr<BorealisTask>> GetTasks() override {
......
...@@ -5,8 +5,10 @@ ...@@ -5,8 +5,10 @@
#include "chrome/browser/chromeos/borealis/borealis_task.h" #include "chrome/browser/chromeos/borealis/borealis_task.h"
#include <string> #include <string>
#include "base/location.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/strings/string_number_conversions.h" #include "base/strings/string_number_conversions.h"
#include "base/threading/sequenced_task_runner_handle.h"
#include "chrome/browser/chromeos/borealis/borealis_context.h" #include "chrome/browser/chromeos/borealis/borealis_context.h"
#include "chrome/browser/chromeos/borealis/borealis_util.h" #include "chrome/browser/chromeos/borealis/borealis_util.h"
#include "chrome/browser/chromeos/profiles/profile_helper.h" #include "chrome/browser/chromeos/profiles/profile_helper.h"
...@@ -17,39 +19,54 @@ ...@@ -17,39 +19,54 @@
namespace borealis { namespace borealis {
BorealisTask::BorealisTask() = default;
BorealisTask::~BorealisTask() = default;
void BorealisTask::Run(BorealisContext* context,
CompletionStatusCallback callback) {
callback_ = std::move(callback);
RunInternal(context);
}
void BorealisTask::Complete(BorealisContextManager::Status status,
std::string message) {
// Task completion is self-mutually-exclusive, because tasks are deleted once
// complete.
base::SequencedTaskRunnerHandle::Get()->PostTask(
FROM_HERE,
base::BindOnce(std::move(callback_), status, std::move(message)));
}
MountDlc::MountDlc() = default; MountDlc::MountDlc() = default;
MountDlc::~MountDlc() = default; MountDlc::~MountDlc() = default;
void MountDlc::Run(BorealisContext* context, void MountDlc::RunInternal(BorealisContext* context) {
CompletionStatusCallback callback) {
// TODO(b/172279567): Ensure the DLC is present before trying to install, // TODO(b/172279567): Ensure the DLC is present before trying to install,
// otherwise we will silently download borealis here. // otherwise we will silently download borealis here.
chromeos::DlcserviceClient::Get()->Install( chromeos::DlcserviceClient::Get()->Install(
kBorealisDlcName, kBorealisDlcName,
base::BindOnce(&MountDlc::OnMountDlc, weak_factory_.GetWeakPtr(), context, base::BindOnce(&MountDlc::OnMountDlc, weak_factory_.GetWeakPtr(),
std::move(callback)), context),
base::DoNothing()); base::DoNothing());
} }
void MountDlc::OnMountDlc( void MountDlc::OnMountDlc(
BorealisContext* context, BorealisContext* context,
CompletionStatusCallback callback,
const chromeos::DlcserviceClient::InstallResult& install_result) { const chromeos::DlcserviceClient::InstallResult& install_result) {
if (install_result.error != dlcservice::kErrorNone) { if (install_result.error != dlcservice::kErrorNone) {
std::move(callback).Run( Complete(BorealisContextManager::Status::kMountFailed,
BorealisContextManager::Status::kMountFailed,
"Mounting the DLC for Borealis failed: " + install_result.error); "Mounting the DLC for Borealis failed: " + install_result.error);
} else { } else {
context->set_root_path(install_result.root_path); context->set_root_path(install_result.root_path);
std::move(callback).Run(BorealisContextManager::Status::kSuccess, ""); Complete(BorealisContextManager::Status::kSuccess, "");
} }
} }
CreateDiskImage::CreateDiskImage() = default; CreateDiskImage::CreateDiskImage() = default;
CreateDiskImage::~CreateDiskImage() = default; CreateDiskImage::~CreateDiskImage() = default;
void CreateDiskImage::Run(BorealisContext* context, void CreateDiskImage::RunInternal(BorealisContext* context) {
CompletionStatusCallback callback) {
vm_tools::concierge::CreateDiskImageRequest request; vm_tools::concierge::CreateDiskImageRequest request;
request.set_disk_path(context->vm_name()); request.set_disk_path(context->vm_name());
request.set_cryptohome_id( request.set_cryptohome_id(
...@@ -59,19 +76,16 @@ void CreateDiskImage::Run(BorealisContext* context, ...@@ -59,19 +76,16 @@ void CreateDiskImage::Run(BorealisContext* context,
request.set_disk_size(0); request.set_disk_size(0);
chromeos::DBusThreadManager::Get()->GetConciergeClient()->CreateDiskImage( chromeos::DBusThreadManager::Get()->GetConciergeClient()->CreateDiskImage(
std::move(request), std::move(request), base::BindOnce(&CreateDiskImage::OnCreateDiskImage,
base::BindOnce(&CreateDiskImage::OnCreateDiskImage, weak_factory_.GetWeakPtr(), context));
weak_factory_.GetWeakPtr(), context, std::move(callback)));
} }
void CreateDiskImage::OnCreateDiskImage( void CreateDiskImage::OnCreateDiskImage(
BorealisContext* context, BorealisContext* context,
CompletionStatusCallback callback,
base::Optional<vm_tools::concierge::CreateDiskImageResponse> response) { base::Optional<vm_tools::concierge::CreateDiskImageResponse> response) {
if (!response) { if (!response) {
context->set_disk_path(base::FilePath()); context->set_disk_path(base::FilePath());
std::move(callback).Run( Complete(BorealisContextManager::Status::kDiskImageFailed,
BorealisContextManager::Status::kDiskImageFailed,
"Failed to create disk image for Borealis: Empty response."); "Failed to create disk image for Borealis: Empty response.");
return; return;
} }
...@@ -79,20 +93,19 @@ void CreateDiskImage::OnCreateDiskImage( ...@@ -79,20 +93,19 @@ void CreateDiskImage::OnCreateDiskImage(
if (response->status() != vm_tools::concierge::DISK_STATUS_EXISTS && if (response->status() != vm_tools::concierge::DISK_STATUS_EXISTS &&
response->status() != vm_tools::concierge::DISK_STATUS_CREATED) { response->status() != vm_tools::concierge::DISK_STATUS_CREATED) {
context->set_disk_path(base::FilePath()); context->set_disk_path(base::FilePath());
std::move(callback).Run(BorealisContextManager::Status::kDiskImageFailed, Complete(BorealisContextManager::Status::kDiskImageFailed,
"Failed to create disk image for Borealis: " + "Failed to create disk image for Borealis: " +
response->failure_reason()); response->failure_reason());
return; return;
} }
context->set_disk_path(base::FilePath(response->disk_path())); context->set_disk_path(base::FilePath(response->disk_path()));
std::move(callback).Run(BorealisContextManager::Status::kSuccess, ""); Complete(BorealisContextManager::Status::kSuccess, "");
} }
StartBorealisVm::StartBorealisVm() = default; StartBorealisVm::StartBorealisVm() = default;
StartBorealisVm::~StartBorealisVm() = default; StartBorealisVm::~StartBorealisVm() = default;
void StartBorealisVm::Run(BorealisContext* context, void StartBorealisVm::RunInternal(BorealisContext* context) {
CompletionStatusCallback callback) {
vm_tools::concierge::StartVmRequest request; vm_tools::concierge::StartVmRequest request;
vm_tools::concierge::VirtualMachineSpec* vm = request.mutable_vm(); vm_tools::concierge::VirtualMachineSpec* vm = request.mutable_vm();
vm->set_kernel(context->root_path() + "/vm_kernel"); vm->set_kernel(context->root_path() + "/vm_kernel");
...@@ -119,31 +132,28 @@ void StartBorealisVm::Run(BorealisContext* context, ...@@ -119,31 +132,28 @@ void StartBorealisVm::Run(BorealisContext* context,
? "enabled" ? "enabled"
: "disabled"); : "disabled");
chromeos::DBusThreadManager::Get()->GetConciergeClient()->StartTerminaVm( chromeos::DBusThreadManager::Get()->GetConciergeClient()->StartTerminaVm(
std::move(request), std::move(request), base::BindOnce(&StartBorealisVm::OnStartBorealisVm,
base::BindOnce(&StartBorealisVm::OnStartBorealisVm, weak_factory_.GetWeakPtr(), context));
weak_factory_.GetWeakPtr(), context, std::move(callback)));
} }
void StartBorealisVm::OnStartBorealisVm( void StartBorealisVm::OnStartBorealisVm(
BorealisContext* context, BorealisContext* context,
CompletionStatusCallback callback,
base::Optional<vm_tools::concierge::StartVmResponse> response) { base::Optional<vm_tools::concierge::StartVmResponse> response) {
if (!response) { if (!response) {
std::move(callback).Run(BorealisContextManager::Status::kStartVmFailed, Complete(BorealisContextManager::Status::kStartVmFailed,
"Failed to start Borealis VM: Empty response."); "Failed to start Borealis VM: Empty response.");
return; return;
} }
if (response->status() == vm_tools::concierge::VM_STATUS_RUNNING || if (response->status() == vm_tools::concierge::VM_STATUS_RUNNING ||
response->status() == vm_tools::concierge::VM_STATUS_STARTING) { response->status() == vm_tools::concierge::VM_STATUS_STARTING) {
std::move(callback).Run(BorealisContextManager::Status::kSuccess, ""); Complete(BorealisContextManager::Status::kSuccess, "");
return; return;
} }
std::move(callback).Run( Complete(BorealisContextManager::Status::kStartVmFailed,
BorealisContextManager::Status::kStartVmFailed, "Failed to start Borealis VM: " + response->failure_reason() +
"Failed to start Borealis VM: " + response->failure_reason() + " (code " + " (code " + base::NumberToString(response->status()) + ")");
base::NumberToString(response->status()) + ")");
} }
AwaitBorealisStartup::AwaitBorealisStartup(Profile* profile, AwaitBorealisStartup::AwaitBorealisStartup(Profile* profile,
...@@ -151,11 +161,10 @@ AwaitBorealisStartup::AwaitBorealisStartup(Profile* profile, ...@@ -151,11 +161,10 @@ AwaitBorealisStartup::AwaitBorealisStartup(Profile* profile,
: watcher_(profile, vm_name) {} : watcher_(profile, vm_name) {}
AwaitBorealisStartup::~AwaitBorealisStartup() = default; AwaitBorealisStartup::~AwaitBorealisStartup() = default;
void AwaitBorealisStartup::Run(BorealisContext* context, void AwaitBorealisStartup::RunInternal(BorealisContext* context) {
CompletionStatusCallback callback) {
watcher_.AwaitLaunch( watcher_.AwaitLaunch(
base::BindOnce(&AwaitBorealisStartup::OnAwaitBorealisStartup, base::BindOnce(&AwaitBorealisStartup::OnAwaitBorealisStartup,
weak_factory_.GetWeakPtr(), context, std::move(callback))); weak_factory_.GetWeakPtr(), context));
} }
BorealisLaunchWatcher& AwaitBorealisStartup::GetWatcherForTesting() { BorealisLaunchWatcher& AwaitBorealisStartup::GetWatcherForTesting() {
...@@ -164,15 +173,13 @@ BorealisLaunchWatcher& AwaitBorealisStartup::GetWatcherForTesting() { ...@@ -164,15 +173,13 @@ BorealisLaunchWatcher& AwaitBorealisStartup::GetWatcherForTesting() {
void AwaitBorealisStartup::OnAwaitBorealisStartup( void AwaitBorealisStartup::OnAwaitBorealisStartup(
BorealisContext* context, BorealisContext* context,
CompletionStatusCallback callback,
base::Optional<std::string> container) { base::Optional<std::string> container) {
if (!container) { if (!container) {
std::move(callback).Run( Complete(BorealisContextManager::Status::kAwaitBorealisStartupFailed,
BorealisContextManager::Status::kAwaitBorealisStartupFailed,
"Awaiting for Borealis launch failed: timed out"); "Awaiting for Borealis launch failed: timed out");
return; return;
} }
context->set_container_name(container.value()); context->set_container_name(container.value());
std::move(callback).Run(BorealisContextManager::Status::kSuccess, ""); Complete(BorealisContextManager::Status::kSuccess, "");
} }
} // namespace borealis } // namespace borealis
...@@ -24,12 +24,21 @@ class BorealisTask { ...@@ -24,12 +24,21 @@ class BorealisTask {
// different status should be used, and an error string provided. // different status should be used, and an error string provided.
using CompletionStatusCallback = using CompletionStatusCallback =
base::OnceCallback<void(BorealisContextManager::Status, std::string)>; base::OnceCallback<void(BorealisContextManager::Status, std::string)>;
BorealisTask() = default;
BorealisTask();
BorealisTask(const BorealisTask&) = delete; BorealisTask(const BorealisTask&) = delete;
BorealisTask& operator=(const BorealisTask&) = delete; BorealisTask& operator=(const BorealisTask&) = delete;
virtual void Run(BorealisContext* context, virtual ~BorealisTask();
CompletionStatusCallback callback) = 0;
virtual ~BorealisTask() = default; void Run(BorealisContext* context, CompletionStatusCallback callback);
protected:
virtual void RunInternal(BorealisContext* context) = 0;
void Complete(BorealisContextManager::Status status, std::string message);
private:
CompletionStatusCallback callback_;
}; };
// Mounts the Borealis DLC. // Mounts the Borealis DLC.
...@@ -37,13 +46,11 @@ class MountDlc : public BorealisTask { ...@@ -37,13 +46,11 @@ class MountDlc : public BorealisTask {
public: public:
MountDlc(); MountDlc();
~MountDlc() override; ~MountDlc() override;
void Run(BorealisContext* context, void RunInternal(BorealisContext* context) override;
CompletionStatusCallback callback) override;
private: private:
void OnMountDlc( void OnMountDlc(
BorealisContext* context, BorealisContext* context,
CompletionStatusCallback callback,
const chromeos::DlcserviceClient::InstallResult& install_result); const chromeos::DlcserviceClient::InstallResult& install_result);
base::WeakPtrFactory<MountDlc> weak_factory_{this}; base::WeakPtrFactory<MountDlc> weak_factory_{this};
}; };
...@@ -53,13 +60,11 @@ class CreateDiskImage : public BorealisTask { ...@@ -53,13 +60,11 @@ class CreateDiskImage : public BorealisTask {
public: public:
CreateDiskImage(); CreateDiskImage();
~CreateDiskImage() override; ~CreateDiskImage() override;
void Run(BorealisContext* context, void RunInternal(BorealisContext* context) override;
CompletionStatusCallback callback) override;
private: private:
void OnCreateDiskImage( void OnCreateDiskImage(
BorealisContext* context, BorealisContext* context,
CompletionStatusCallback callback,
base::Optional<vm_tools::concierge::CreateDiskImageResponse> response); base::Optional<vm_tools::concierge::CreateDiskImageResponse> response);
base::WeakPtrFactory<CreateDiskImage> weak_factory_{this}; base::WeakPtrFactory<CreateDiskImage> weak_factory_{this};
}; };
...@@ -69,13 +74,11 @@ class StartBorealisVm : public BorealisTask { ...@@ -69,13 +74,11 @@ class StartBorealisVm : public BorealisTask {
public: public:
StartBorealisVm(); StartBorealisVm();
~StartBorealisVm() override; ~StartBorealisVm() override;
void Run(BorealisContext* context, void RunInternal(BorealisContext* context) override;
CompletionStatusCallback callback) override;
private: private:
void OnStartBorealisVm( void OnStartBorealisVm(
BorealisContext* context, BorealisContext* context,
CompletionStatusCallback callback,
base::Optional<vm_tools::concierge::StartVmResponse> response); base::Optional<vm_tools::concierge::StartVmResponse> response);
base::WeakPtrFactory<StartBorealisVm> weak_factory_{this}; base::WeakPtrFactory<StartBorealisVm> weak_factory_{this};
}; };
...@@ -85,13 +88,11 @@ class AwaitBorealisStartup : public BorealisTask { ...@@ -85,13 +88,11 @@ class AwaitBorealisStartup : public BorealisTask {
public: public:
AwaitBorealisStartup(Profile* profile, std::string vm_name); AwaitBorealisStartup(Profile* profile, std::string vm_name);
~AwaitBorealisStartup() override; ~AwaitBorealisStartup() override;
void Run(BorealisContext* context, void RunInternal(BorealisContext* context) override;
CompletionStatusCallback callback) override;
BorealisLaunchWatcher& GetWatcherForTesting(); BorealisLaunchWatcher& GetWatcherForTesting();
private: private:
void OnAwaitBorealisStartup(BorealisContext* context, void OnAwaitBorealisStartup(BorealisContext* context,
CompletionStatusCallback callback,
base::Optional<std::string> container); base::Optional<std::string> container);
BorealisLaunchWatcher watcher_; BorealisLaunchWatcher watcher_;
base::WeakPtrFactory<AwaitBorealisStartup> weak_factory_{this}; base::WeakPtrFactory<AwaitBorealisStartup> weak_factory_{this};
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment