blob: 6e3776f8bb16d5c03d481ac7b7a41a6840f38008 [file] [log] [blame]
// Copyright 2019 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_PROMPT_CHANNEL_WIN_H_
#define CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_PROMPT_CHANNEL_WIN_H_
#include <memory>
#include "base/callback_forward.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/process/launch.h"
#include "base/process/process.h"
#include "base/sequence_checker.h"
#include "base/sequenced_task_runner.h"
#include "base/win/scoped_handle.h"
#include "chrome/browser/safe_browsing/chrome_cleaner/chrome_prompt_actions_win.h"
#include "components/chrome_cleaner/public/interfaces/chrome_prompt.mojom.h"
#include "components/chrome_cleaner/public/proto/chrome_prompt.pb.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "mojo/public/cpp/system/invitation.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "third_party/protobuf/src/google/protobuf/message_lite.h"
namespace base {
class CommandLine;
} // namespace base
namespace safe_browsing {
namespace internal {
class ChromePromptImpl;
} // namespace internal
class ChromePromptActions;
// Handles IPC to the Chrome Cleaner process. The Chrome Cleaner process will
// send requests and ChromePromptChannel will handle the request, often by
// using ChromePromptActions, and write the response.
class ChromePromptChannel {
public:
// Gives access to the Chrome Cleaner process that the channel communicates
// with.
class CleanerProcessDelegate {
public:
virtual ~CleanerProcessDelegate() = default;
virtual base::ProcessHandle Handle() const = 0;
virtual void TerminateOnError() const = 0;
};
// Returns a CleanerProcessDelegate that wraps |process|.
static std::unique_ptr<CleanerProcessDelegate> CreateDelegateForProcess(
const base::Process& process);
// Creates a ChromePromptChannel that calls |on_connection_closed| when the
// IPC channel closes (either normally or on error) and uses |actions| to
// fulfill requests. |task_runner| can be used to run any tasks that must be
// seqeuenced with destruction of the ChromePromptChannel.
ChromePromptChannel(base::OnceClosure on_connection_closed,
std::unique_ptr<ChromePromptActions> actions,
scoped_refptr<base::SequencedTaskRunner> task_runner);
virtual ~ChromePromptChannel();
// Prepares an IPC channel to be used by the cleaner process that is about to
// be launched. Adds all handles used by the channel to |handles_to_inherit|
// so that the cleaner process can access them, and adds switches to
// |command_line| that the cleaner process can use to connect to the channel.
virtual bool PrepareForCleaner(
base::CommandLine* command_line,
base::HandlesToInheritVector* handles_to_inherit) = 0;
// Does any cleanup required if the cleaner process fails to launch after
// PrepareForCleaner was called.
virtual void CleanupAfterCleanerLaunchFailed() = 0;
// Kicks off communication between the IPC channel prepared by
// PrepareForCleaner and the process in |cleaner_process|. If the connection
// fails, |connection_closed_callback_| should be called.
virtual void ConnectToCleaner(
std::unique_ptr<CleanerProcessDelegate> cleaner_process) = 0;
scoped_refptr<base::SequencedTaskRunner> task_runner() const {
return task_runner_;
}
protected:
base::OnceClosure on_connection_closed_;
std::unique_ptr<ChromePromptActions> actions_;
scoped_refptr<base::SequencedTaskRunner> task_runner_;
private:
ChromePromptChannel(const ChromePromptChannel& other) = delete;
ChromePromptChannel& operator=(const ChromePromptChannel& other) = delete;
};
// Handles IPC to the Chrome Cleaner process using Mojo.
class ChromePromptChannelMojo : public ChromePromptChannel {
public:
ChromePromptChannelMojo(base::OnceClosure on_connection_closed,
std::unique_ptr<ChromePromptActions> actions,
scoped_refptr<base::SequencedTaskRunner> task_runner);
~ChromePromptChannelMojo() override;
bool PrepareForCleaner(
base::CommandLine* command_line,
base::HandlesToInheritVector* handles_to_inherit) override;
void CleanupAfterCleanerLaunchFailed() override;
void ConnectToCleaner(
std::unique_ptr<CleanerProcessDelegate> cleaner_process) override;
private:
ChromePromptChannelMojo(const ChromePromptChannelMojo& other) = delete;
ChromePromptChannelMojo& operator=(const ChromePromptChannelMojo& other) =
delete;
void CreateChromePromptImpl(
chrome_cleaner::mojom::ChromePromptRequest chrome_prompt_request);
mojo::OutgoingInvitation invitation_;
mojo::PlatformChannel mojo_channel_;
mojo::ScopedMessagePipeHandle request_pipe_;
std::unique_ptr<internal::ChromePromptImpl> chrome_prompt_impl_;
base::WeakPtrFactory<ChromePromptChannelMojo> weak_factory_;
};
// Handles IPC to the Chrome Cleaner process by serializing protobufs over
// a pipe.
class ChromePromptChannelProtobuf : public ChromePromptChannel {
public:
static const char kErrorHistogramName[];
static constexpr uint32_t kMaxMessageLength = 1 * 1024 * 1024; // 1M bytes
// Values from this enum will serve as the high bits of the histogram values.
// We will be able to use them to separate the errors by category if we ever
// need to analyze them.
enum class ErrorCategory : uint16_t {
kCustomError = 1,
kReadVersionWinError = 2,
kReadRequestLengthWinError = 3,
kReadRequestWinError = 4,
kWriteResponseWinError = 5,
kWriteResponseLengthWinError = 6,
};
// Code that describes the error precisely.
enum class CustomErrors : uint16_t {
kWrongHandshakeVersion = 1,
kRequestLengthShortRead = 2,
kRequestShortRead = 3,
kRequestInvalidSize = 4,
kRequestContentInvalid = 5,
kRequestUnknown = 6,
kRequestUnknownField = 7,
kUndisplayableFilePath = 8,
kUndisplayableRegistryKey = 9,
kUndisplayableExtension = 9,
};
static int32_t GetErrorCodeInt(ErrorCategory category,
CustomErrors error_code) {
return GetErrorCodeInt(category, static_cast<uint16_t>(error_code));
}
static int32_t GetErrorCodeInt(ErrorCategory category, uint16_t error_code) {
// We are storing the bits of the category and error_code in the return type
// without caring about the numerical values. Make sure everything fits.
using CategoryNumType = std::underlying_type<ErrorCategory>::type;
using ErrorCodeType = decltype(error_code);
static_assert(std::is_same<CategoryNumType, ErrorCodeType>::value,
"Category and error code types need to be the same.");
static_assert(
sizeof(int32_t) == sizeof(CategoryNumType) + sizeof(ErrorCodeType),
"Values won't fit in return type.");
int32_t category_and_code = static_cast<CategoryNumType>(category);
category_and_code <<= sizeof(category) * CHAR_BIT;
category_and_code |= error_code;
return category_and_code;
}
ChromePromptChannelProtobuf(
base::OnceClosure on_connection_closed,
std::unique_ptr<ChromePromptActions> actions,
scoped_refptr<base::SequencedTaskRunner> task_runner);
~ChromePromptChannelProtobuf() override;
bool PrepareForCleaner(
base::CommandLine* command_line,
base::HandlesToInheritVector* handles_to_inherit) override;
void CleanupAfterCleanerLaunchFailed() override;
void ConnectToCleaner(
std::unique_ptr<CleanerProcessDelegate> cleaner_process) override;
// Handles |request| and sends a QueryCapabilityResponse in reply.
void HandleQueryCapabilityRequest(
const chrome_cleaner::QueryCapabilityRequest& request);
// Handles |request| and sends a PromptUserResponse in reply.
void HandlePromptUserRequest(
const chrome_cleaner::PromptUserRequest& request);
// Handles |request| and sends a RemoveExtensionsResponse in reply.
void HandleRemoveExtensionsRequest(
const chrome_cleaner::RemoveExtensionsRequest& request);
// Closes request_read_handle_ and request_write_handle_, which will trigger
// an error handler in ServiceChromePromptRequests.
void CloseHandles();
private:
ChromePromptChannelProtobuf(const ChromePromptChannelProtobuf& other) =
delete;
ChromePromptChannelProtobuf& operator=(
const ChromePromptChannelProtobuf& other) = delete;
// Serializes |message| to response_write_handle_. Calls CloseHandles on
// error.
void WriteResponseMessage(const google::protobuf::MessageLite& message);
// Sends a PromptUserResponse with the given |acceptance| value.
void SendPromptUserResponse(ChromePromptActions::PromptAcceptance acceptance);
SEQUENCE_CHECKER(sequence_checker_);
// Requests always flow from the Chrome Cleanup tool to Chrome.
// This class owns request_read_handle_ but request_write_handle_ will be
// closed once it is passed to the child process.
base::win::ScopedHandle request_read_handle_;
base::win::ScopedHandle request_write_handle_;
// Responses flow from Chrome to the Chrome Cleanup tool.
// This class owns response_write_handle_ but response_read_handle_ will be
// closed once it is passed to the child process.
base::win::ScopedHandle response_read_handle_;
base::win::ScopedHandle response_write_handle_;
base::WeakPtrFactory<ChromePromptChannelProtobuf> weak_factory_;
};
} // namespace safe_browsing
#endif // CHROME_BROWSER_SAFE_BROWSING_CHROME_CLEANER_CHROME_PROMPT_CHANNEL_WIN_H_