Commit 86ba94de authored by Joe Mason's avatar Joe Mason Committed by Commit Bot

Add chrome_cleaner/json_parser

This does not use services/data_decoder because it's closely tied to
the service manager, which chrome_cleaner does not support.

R=csharp

Bug: 830892
Change-Id: Ia3138624c9d723916fdf1ba174c89cbcc6e71401
Reviewed-on: https://chromium-review.googlesource.com/1180349Reviewed-by: default avatarJoe Mason <joenotcharles@chromium.org>
Reviewed-by: default avatarChris Sharp <csharp@chromium.org>
Reviewed-by: default avatarTom Sepez <tsepez@chromium.org>
Commit-Queue: Joe Mason <joenotcharles@chromium.org>
Cr-Commit-Position: refs/heads/master@{#585408}
parent b08a5594
......@@ -33,6 +33,7 @@ test("chrome_cleaner_unittests") {
"//chrome/chrome_cleaner/chrome_utils:unittest_sources",
"//chrome/chrome_cleaner/http:unittest_sources",
"//chrome/chrome_cleaner/ipc:unittest_sources",
"//chrome/chrome_cleaner/json_parser:unittest_sources",
"//chrome/chrome_cleaner/logging:unittest_sources",
"//chrome/chrome_cleaner/os:unittest_sources",
"//chrome/chrome_cleaner/pup_data:unittest_sources",
......
......@@ -19,3 +19,20 @@ mojom("engine_sandbox_interface") {
"//mojo/public/mojom/base",
]
}
mojom("json_parser_interface") {
sources = [
"json_parser.mojom",
]
deps = [
"//mojo/public/mojom/base",
]
}
mojom("mojo_sandbox_hooks_test_interface") {
testonly = true
sources = [
"test_mojo_sandbox_hooks.mojom",
]
}
// Copyright 2018 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.
module chrome_cleaner.mojom;
import "mojo/public/mojom/base/values.mojom";
// Interface copied from services/data_decoder/public/mojom/json_parser.mojom,
// which can't be used directly because it's closely tied to the service
// manager which chrome_cleaner does not support.
//
// Sends a JSON string to parse from the high-privilege sandbox broker process
// to a locked down sandbox target process where the parsing takes place.
interface JsonParser {
// Parses |json| into a structured Value object. Returns the value in
// |result| if the parse was successful, or an error message in |error| if
// not.
Parse(string json) => (mojo_base.mojom.Value? result, string? error);
};
// Copyright 2018 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.
module chrome_cleaner.mojom;
// Simple interface that echoes a string for mojo setup testing.
interface TestMojoSandboxHooks {
EchoString(string input) => (string output);
};
......@@ -32,6 +32,8 @@ source_set("chrome_prompt_ipc") {
source_set("sandbox") {
sources = [
"mojo_sandbox_hooks.cc",
"mojo_sandbox_hooks.h",
"sandbox.cc",
"sandbox.h",
]
......@@ -74,6 +76,7 @@ source_set("unittest_sources") {
sources = [
"chrome_prompt_ipc_unittest.cc",
"mojo_sandbox_hooks_unittest.cc",
"mojo_task_runner_unittest.cc",
"sandbox_unittest.cc",
]
......@@ -85,6 +88,7 @@ source_set("unittest_sources") {
":sandbox",
"//base",
"//base/test:test_support",
"//chrome/chrome_cleaner/interfaces:mojo_sandbox_hooks_test_interface",
"//chrome/chrome_cleaner/logging:common",
"//chrome/chrome_cleaner/os:common_os",
"//chrome/chrome_cleaner/test:test_util",
......
// Copyright 2018 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.
#include "chrome/chrome_cleaner/ipc/mojo_sandbox_hooks.h"
#include <string>
#include <utility>
#include "base/logging.h"
#include "base/rand_util.h"
#include "base/strings/string_number_conversions.h"
#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
namespace chrome_cleaner {
MojoSandboxSetupHooks::MojoSandboxSetupHooks() = default;
MojoSandboxSetupHooks::~MojoSandboxSetupHooks() = default;
mojo::ScopedMessagePipeHandle MojoSandboxSetupHooks::SetupSandboxMessagePipe(
sandbox::TargetPolicy* policy,
base::CommandLine* command_line) {
DCHECK(policy);
DCHECK(command_line);
std::string pipe_token = base::NumberToString(base::RandUint64());
mojo::ScopedMessagePipeHandle mojo_pipe =
outgoing_invitation_.AttachMessagePipe(pipe_token);
command_line->AppendSwitchASCII(kSandboxMojoPipeTokenSwitch, pipe_token);
base::HandlesToInheritVector handles_to_inherit;
mojo_channel_.PrepareToPassRemoteEndpoint(&handles_to_inherit, command_line);
for (HANDLE handle : handles_to_inherit)
policy->AddHandleToShare(handle);
message_pipe_was_created_ = true;
return mojo_pipe;
}
ResultCode MojoSandboxSetupHooks::TargetSpawned(
const base::Process& target_process,
const base::win::ScopedHandle& target_thread) {
DCHECK(message_pipe_was_created_);
// TODO(joenotcharles): Hook up the |error_callback| parameter of Send to a
// function that logs a security warning and exits. This callback will be
// called when an invalid message is written to the pipe.
mojo::OutgoingInvitation::Send(std::move(outgoing_invitation_),
target_process.Handle(),
mojo_channel_.TakeLocalEndpoint());
return RESULT_CODE_SUCCESS;
}
MojoSandboxTargetHooks::MojoSandboxTargetHooks() = default;
MojoSandboxTargetHooks::~MojoSandboxTargetHooks() = default;
mojo::ScopedMessagePipeHandle MojoSandboxTargetHooks::ExtractSandboxMessagePipe(
const base::CommandLine& command_line) {
auto channel_endpoint =
mojo::PlatformChannel::RecoverPassedEndpointFromCommandLine(command_line);
auto incoming_invitation =
mojo::IncomingInvitation::Accept(std::move(channel_endpoint));
return incoming_invitation.ExtractMessagePipe(
command_line.GetSwitchValueASCII(kSandboxMojoPipeTokenSwitch));
}
} // namespace chrome_cleaner
// Copyright 2018 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_CHROME_CLEANER_IPC_MOJO_SANDBOX_HOOKS_H_
#define CHROME_CHROME_CLEANER_IPC_MOJO_SANDBOX_HOOKS_H_
#include "base/command_line.h"
#include "base/macros.h"
#include "base/process/process.h"
#include "base/win/scoped_handle.h"
#include "chrome/chrome_cleaner/ipc/sandbox.h"
#include "components/chrome_cleaner/public/constants/result_codes.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 "sandbox/win/src/sandbox_policy.h"
namespace chrome_cleaner {
class MojoSandboxSetupHooks : public SandboxSetupHooks {
public:
MojoSandboxSetupHooks();
~MojoSandboxSetupHooks() override;
protected:
mojo::ScopedMessagePipeHandle SetupSandboxMessagePipe(
sandbox::TargetPolicy* policy,
base::CommandLine* command_line);
// SandboxSetupHooks
ResultCode TargetSpawned(
const base::Process& target_process,
const base::win::ScopedHandle& target_thread) override;
private:
bool message_pipe_was_created_ = false;
mojo::OutgoingInvitation outgoing_invitation_;
mojo::PlatformChannel mojo_channel_;
DISALLOW_COPY_AND_ASSIGN(MojoSandboxSetupHooks);
};
class MojoSandboxTargetHooks : public SandboxTargetHooks {
public:
MojoSandboxTargetHooks();
~MojoSandboxTargetHooks() override;
protected:
mojo::ScopedMessagePipeHandle ExtractSandboxMessagePipe(
const base::CommandLine& command_line);
private:
DISALLOW_COPY_AND_ASSIGN(MojoSandboxTargetHooks);
};
} // namespace chrome_cleaner
#endif // CHROME_CHROME_CLEANER_IPC_MOJO_SANDBOX_HOOKS_H_
// Copyright 2018 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.
#include <memory>
#include <string>
#include <utility>
#include "base/bind.h"
#include "base/bind_helpers.h"
#include "base/memory/ref_counted.h"
#include "base/sequenced_task_runner.h"
#include "base/test/multiprocess_test.h"
#include "base/test/scoped_task_environment.h"
#include "chrome/chrome_cleaner/interfaces/test_mojo_sandbox_hooks.mojom.h"
#include "chrome/chrome_cleaner/ipc/mojo_sandbox_hooks.h"
#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
#include "chrome/chrome_cleaner/os/early_exit.h"
#include "mojo/public/cpp/bindings/binding.h"
#include "mojo/public/cpp/system/message_pipe.h"
#include "sandbox/win/src/sandbox_factory.h"
#include "testing/multiprocess_func_list.h"
namespace chrome_cleaner {
namespace {
constexpr char kTestString[] = "Hello World";
using UniqueTestMojoSandboxHooksPtr =
std::unique_ptr<mojom::TestMojoSandboxHooksPtr, base::OnTaskRunnerDeleter>;
class MojoSandboxHooksTest : public base::MultiProcessTest {
public:
MojoSandboxHooksTest() : mojo_task_runner_(MojoTaskRunner::Create()) {}
protected:
scoped_refptr<MojoTaskRunner> mojo_task_runner_;
private:
base::test::ScopedTaskEnvironment scoped_task_environment_;
};
// |TestMojoSandboxHooksImpl| runs and handles mojo requests in the sandbox
// child process.
class TestMojoSandboxHooksImpl : mojom::TestMojoSandboxHooks {
public:
explicit TestMojoSandboxHooksImpl(mojom::TestMojoSandboxHooksRequest request)
: binding_(this, std::move(request)) {
binding_.set_connection_error_handler(base::BindOnce(&EarlyExit, 1));
}
void EchoString(const std::string& input,
EchoStringCallback callback) override {
std::move(callback).Run(input);
}
private:
mojo::Binding<mojom::TestMojoSandboxHooks> binding_;
};
class TestSandboxSetupHooks : public MojoSandboxSetupHooks {
public:
explicit TestSandboxSetupHooks(scoped_refptr<MojoTaskRunner> mojo_task_runner)
: mojo_task_runner_(mojo_task_runner),
// Manually use |new| here because |make_unique| doesn't work with
// custom deleter.
test_mojo_ptr_(new mojom::TestMojoSandboxHooksPtr,
base::OnTaskRunnerDeleter(mojo_task_runner_)) {}
ResultCode UpdateSandboxPolicy(sandbox::TargetPolicy* policy,
base::CommandLine* command_line) override {
mojo::ScopedMessagePipeHandle pipe_handle =
SetupSandboxMessagePipe(policy, command_line);
// Unretained pointer of |test_mojo_ptr_| is safe because its deleter is
// run on the same task runner. So it won't be deleted before this task.
mojo_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(TestSandboxSetupHooks::BindTestMojoSandboxHooksPtr,
base::Unretained(test_mojo_ptr_.get()),
std::move(pipe_handle)));
return RESULT_CODE_SUCCESS;
}
UniqueTestMojoSandboxHooksPtr TakeTestMojoSandboxHooksPtr() {
return std::move(test_mojo_ptr_);
}
private:
static void BindTestMojoSandboxHooksPtr(
mojom::TestMojoSandboxHooksPtr* test_mojo_ptr,
mojo::ScopedMessagePipeHandle pipe_handle) {
test_mojo_ptr->Bind(
mojom::TestMojoSandboxHooksPtrInfo(std::move(pipe_handle), 0));
test_mojo_ptr->set_connection_error_handler(base::BindOnce(
[] { FAIL() << "Mojo sandbox setup connection error"; }));
}
scoped_refptr<MojoTaskRunner> mojo_task_runner_;
UniqueTestMojoSandboxHooksPtr test_mojo_ptr_;
};
class TestSandboxTargetHooks : public MojoSandboxTargetHooks {
public:
ResultCode TargetDroppedPrivileges(
const base::CommandLine& command_line) override {
scoped_refptr<MojoTaskRunner> mojo_task_runner = MojoTaskRunner::Create();
mojom::TestMojoSandboxHooksRequest request(
ExtractSandboxMessagePipe(command_line));
std::unique_ptr<TestMojoSandboxHooksImpl, base::OnTaskRunnerDeleter>
impl_ptr(nullptr, base::OnTaskRunnerDeleter(mojo_task_runner));
// This loop will run forever. Once the communication channel with the
// broker process is broken, mojo error handler will abort this process.
base::RunLoop loop;
mojo_task_runner->PostTask(
FROM_HERE,
base::BindOnce(CreateTestMojoSandboxHooksImpl,
base::Unretained(&impl_ptr), std::move(request)));
loop.Run();
return RESULT_CODE_SUCCESS;
}
private:
static void CreateTestMojoSandboxHooksImpl(
std::unique_ptr<TestMojoSandboxHooksImpl, base::OnTaskRunnerDeleter>*
impl_ptr,
mojom::TestMojoSandboxHooksRequest request) {
(*impl_ptr).reset(new TestMojoSandboxHooksImpl(std::move(request)));
}
base::test::ScopedTaskEnvironment scoped_task_environment_;
};
void RunEchoString(mojom::TestMojoSandboxHooksPtr* test_mojo_ptr,
const std::string& input,
mojom::TestMojoSandboxHooks::EchoStringCallback callback) {
DCHECK(test_mojo_ptr);
(*test_mojo_ptr)->EchoString(input, std::move(callback));
}
void OnEchoStringDone(std::string* result_string,
base::OnceClosure done_callback,
const std::string& output) {
*result_string = output;
std::move(done_callback).Run();
}
} // namespace
MULTIPROCESS_TEST_MAIN(MojoSandboxHooksTargetMain) {
sandbox::TargetServices* sandbox_target_services =
sandbox::SandboxFactory::GetTargetServices();
CHECK(sandbox_target_services);
TestSandboxTargetHooks target_hooks;
RunSandboxTarget(*base::CommandLine::ForCurrentProcess(),
sandbox_target_services, &target_hooks);
return 0;
}
TEST_F(MojoSandboxHooksTest, SpawnSandboxTarget) {
TestSandboxSetupHooks setup_hooks(mojo_task_runner_.get());
ASSERT_EQ(RESULT_CODE_SUCCESS,
StartSandboxTarget(MakeCmdLine("MojoSandboxHooksTargetMain"),
&setup_hooks, SandboxType::kTest));
UniqueTestMojoSandboxHooksPtr test_mojo_ptr =
setup_hooks.TakeTestMojoSandboxHooksPtr();
std::string test_result_string;
base::RunLoop loop;
// Unretained pointers are safe because the test will wait until the task
// ends.
mojo_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(RunEchoString, base::Unretained(test_mojo_ptr.get()),
kTestString,
base::BindOnce(OnEchoStringDone,
base::Unretained(&test_result_string),
loop.QuitClosure())));
loop.Run();
EXPECT_EQ(test_result_string, kTestString);
}
} // namespace chrome_cleaner
# Copyright 2018 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.
static_library("json_parser") {
sources = [
"json_parser_api.h",
"json_parser_impl.cc",
"json_parser_impl.h",
"sandbox_setup_hooks.cc",
"sandbox_setup_hooks.h",
"sandbox_target_hooks.cc",
"sandbox_target_hooks.h",
"sandboxed_json_parser.cc",
"sandboxed_json_parser.h",
"test_json_parser.cc",
"test_json_parser.h",
]
deps = [
"//base:base",
"//chrome/chrome_cleaner/constants:common_strings",
"//chrome/chrome_cleaner/interfaces:json_parser_interface",
"//chrome/chrome_cleaner/ipc:mojo_task_runner",
"//chrome/chrome_cleaner/ipc:sandbox",
"//chrome/chrome_cleaner/os:common_os",
"//components/chrome_cleaner/public/constants",
"//mojo/public/cpp/bindings",
]
}
source_set("unittest_sources") {
testonly = true
sources = [
"json_parser_impl_unittest.cc",
"sandbox_setup_unittest.cc",
]
deps = [
":json_parser",
"//base:base",
"//base/test:test_support",
"//chrome/chrome_cleaner/interfaces:json_parser_interface",
"//chrome/chrome_cleaner/ipc:mojo_task_runner",
"//mojo/public/cpp/bindings",
"//sandbox/win:sandbox",
"//testing/gtest",
]
}
// Copyright 2018 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_CHROME_CLEANER_JSON_PARSER_JSON_PARSER_API_H_
#define CHROME_CHROME_CLEANER_JSON_PARSER_JSON_PARSER_API_H_
#include "base/callback.h"
#include "base/optional.h"
#include "base/values.h"
namespace chrome_cleaner {
using ParseDoneCallback =
base::OnceCallback<void(base::Optional<base::Value>,
const base::Optional<std::string>&)>;
class JsonParserAPI {
public:
virtual ~JsonParserAPI() = default;
virtual void Parse(const std::string& json, ParseDoneCallback callback) = 0;
};
} // namespace chrome_cleaner
#endif // CHROME_CHROME_CLEANER_JSON_PARSER_JSON_PARSER_API_H_
// Copyright 2018 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.
#include "chrome/chrome_cleaner/json_parser/json_parser_impl.h"
#include "base/json/json_reader.h"
#include "base/values.h"
namespace chrome_cleaner {
JsonParserImpl::JsonParserImpl(mojom::JsonParserRequest request,
base::OnceClosure connection_error_handler)
: binding_(this, std::move(request)) {
binding_.set_connection_error_handler(std::move(connection_error_handler));
}
JsonParserImpl::~JsonParserImpl() = default;
void JsonParserImpl::Parse(const std::string& json, ParseCallback callback) {
int error_code;
std::string error;
std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
json,
base::JSON_ALLOW_TRAILING_COMMAS | base::JSON_REPLACE_INVALID_CHARACTERS,
&error_code, &error);
if (value) {
std::move(callback).Run(base::make_optional(std::move(*value)),
base::nullopt);
} else {
std::move(callback).Run(base::nullopt,
base::make_optional(std::move(error)));
}
}
} // namespace chrome_cleaner
// Copyright 2018 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_CHROME_CLEANER_JSON_PARSER_JSON_PARSER_IMPL_H_
#define CHROME_CHROME_CLEANER_JSON_PARSER_JSON_PARSER_IMPL_H_
#include "chrome/chrome_cleaner/interfaces/json_parser.mojom.h"
#include "mojo/public/cpp/bindings/binding.h"
namespace chrome_cleaner {
class JsonParserImpl : public mojom::JsonParser {
public:
explicit JsonParserImpl(mojom::JsonParserRequest request,
base::OnceClosure connection_error_handler);
~JsonParserImpl() override;
// mojom::JsonParser
void Parse(const std::string& json, ParseCallback callback) override;
private:
mojo::Binding<mojom::JsonParser> binding_;
};
} // namespace chrome_cleaner
#endif // CHROME_CHROME_CLEANER_JSON_PARSER_JSON_PARSER_IMPL_H_
// Copyright 2018 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.
#include "chrome/chrome_cleaner/json_parser/json_parser_impl.h"
#include "base/bind.h"
#include "base/synchronization/waitable_event.h"
#include "base/test/test_timeouts.h"
#include "base/values.h"
#include "chrome/chrome_cleaner/interfaces/json_parser.mojom.h"
#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
#include "chrome/chrome_cleaner/json_parser/sandboxed_json_parser.h"
#include "mojo/public/cpp/bindings/interface_request.h"
#include "testing/gtest/include/gtest/gtest.h"
using base::WaitableEvent;
namespace chrome_cleaner {
namespace {
const char kTestJsonKey[] = "name";
const char kTestJsonValue[] = "Jason";
const char kTestJsonText[] = "{ \"name\": \"Jason\" }";
const char kInvalidJsonText[] = "{ name: jason }";
class JsonParserImplTest : public testing::Test {
public:
JsonParserImplTest()
: task_runner_(MojoTaskRunner::Create()),
json_parser_ptr_(new mojom::JsonParserPtr(),
base::OnTaskRunnerDeleter(task_runner_)),
json_parser_impl_(nullptr, base::OnTaskRunnerDeleter(task_runner_)),
sandboxed_json_parser_(task_runner_.get(), json_parser_ptr_.get()) {
BindParser();
}
protected:
void BindParser() {
task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
[](mojom::JsonParserPtr* json_parser,
std::unique_ptr<JsonParserImpl, base::OnTaskRunnerDeleter>*
json_parser_impl) {
json_parser_impl->reset(new JsonParserImpl(
mojo::MakeRequest(json_parser), base::DoNothing()));
},
json_parser_ptr_.get(), &json_parser_impl_));
}
scoped_refptr<MojoTaskRunner> task_runner_;
std::unique_ptr<mojom::JsonParserPtr, base::OnTaskRunnerDeleter>
json_parser_ptr_;
std::unique_ptr<JsonParserImpl, base::OnTaskRunnerDeleter> json_parser_impl_;
SandboxedJsonParser sandboxed_json_parser_;
};
} // namespace
TEST_F(JsonParserImplTest, ParseJson) {
WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL,
WaitableEvent::InitialState::NOT_SIGNALED);
sandboxed_json_parser_.Parse(
kTestJsonText,
base::BindOnce(
[](WaitableEvent* done, base::Optional<base::Value> value,
const base::Optional<std::string>& error) {
ASSERT_FALSE(error.has_value());
ASSERT_TRUE(value.has_value());
ASSERT_TRUE(value->is_dict());
const base::DictionaryValue* dict;
ASSERT_TRUE(value->GetAsDictionary(&dict));
std::string string_value;
ASSERT_TRUE(dict->GetString(kTestJsonKey, &string_value));
EXPECT_EQ(kTestJsonValue, string_value);
done->Signal();
},
&done));
EXPECT_TRUE(done.TimedWait(TestTimeouts::action_timeout()));
}
TEST_F(JsonParserImplTest, ParseJsonError) {
WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL,
WaitableEvent::InitialState::NOT_SIGNALED);
sandboxed_json_parser_.Parse(
kInvalidJsonText,
base::BindOnce(
[](WaitableEvent* done, base::Optional<base::Value> value,
const base::Optional<std::string>& error) {
ASSERT_TRUE(error.has_value());
EXPECT_FALSE(error->empty());
done->Signal();
},
&done));
EXPECT_TRUE(done.TimedWait(TestTimeouts::action_timeout()));
}
} // namespace chrome_cleaner
// Copyright 2018 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.
#include "chrome/chrome_cleaner/json_parser/sandbox_setup_hooks.h"
#include <utility>
#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
namespace chrome_cleaner {
JsonParserSandboxSetupHooks::JsonParserSandboxSetupHooks(
scoped_refptr<MojoTaskRunner> mojo_task_runner,
base::OnceClosure connection_error_handler)
: mojo_task_runner_(mojo_task_runner),
connection_error_handler_(std::move(connection_error_handler)),
json_parser_ptr_(new mojom::JsonParserPtr(),
base::OnTaskRunnerDeleter(mojo_task_runner_)) {}
JsonParserSandboxSetupHooks::~JsonParserSandboxSetupHooks() = default;
ResultCode JsonParserSandboxSetupHooks::UpdateSandboxPolicy(
sandbox::TargetPolicy* policy,
base::CommandLine* command_line) {
// Unretained reference is safe because the json_parser_ptr is taken by the
// caller and is expected to retain it for the life of the sandboxed process.
mojo_task_runner_->PostTask(
FROM_HERE, base::BindOnce(&JsonParserSandboxSetupHooks::BindJsonParserPtr,
base::Unretained(this),
SetupSandboxMessagePipe(policy, command_line),
base::Unretained(json_parser_ptr_.get())));
return RESULT_CODE_SUCCESS;
}
void JsonParserSandboxSetupHooks::BindJsonParserPtr(
mojo::ScopedMessagePipeHandle pipe_handle,
mojom::JsonParserPtr* json_parser_ptr) {
json_parser_ptr->Bind(mojom::JsonParserPtrInfo(std::move(pipe_handle), 0));
json_parser_ptr->set_connection_error_handler(
std::move(connection_error_handler_));
}
UniqueJsonParserPtr JsonParserSandboxSetupHooks::TakeJsonParserPtr() {
return std::move(json_parser_ptr_);
}
ResultCode SpawnJsonParserSandbox(
scoped_refptr<MojoTaskRunner> mojo_task_runner,
base::OnceClosure connection_error_handler,
UniqueJsonParserPtr* json_parser_ptr) {
JsonParserSandboxSetupHooks setup_hooks(mojo_task_runner,
std::move(connection_error_handler));
ResultCode result_code = SpawnSandbox(&setup_hooks, SandboxType::kJsonParser);
*json_parser_ptr = setup_hooks.TakeJsonParserPtr();
return result_code;
}
} // namespace chrome_cleaner
// Copyright 2018 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_CHROME_CLEANER_JSON_PARSER_SANDBOX_SETUP_HOOKS_H_
#define CHROME_CHROME_CLEANER_JSON_PARSER_SANDBOX_SETUP_HOOKS_H_
#include <memory>
#include "base/command_line.h"
#include "chrome/chrome_cleaner/interfaces/json_parser.mojom.h"
#include "chrome/chrome_cleaner/ipc/mojo_sandbox_hooks.h"
#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
#include "components/chrome_cleaner/public/constants/result_codes.h"
#include "mojo/public/cpp/system/message_pipe.h"
namespace chrome_cleaner {
using UniqueJsonParserPtr =
std::unique_ptr<mojom::JsonParserPtr, base::OnTaskRunnerDeleter>;
// Hooks to spawn a new sandboxed JSON parser process and bind a Mojo interface
// pointer to the sandboxed implementation.
class JsonParserSandboxSetupHooks : public MojoSandboxSetupHooks {
public:
JsonParserSandboxSetupHooks(scoped_refptr<MojoTaskRunner> mojo_task_runner,
base::OnceClosure connection_error_handler);
~JsonParserSandboxSetupHooks() override;
// Transfers ownership of |json_parser_ptr_| to the caller.
UniqueJsonParserPtr TakeJsonParserPtr();
// SandboxSetupHooks
ResultCode UpdateSandboxPolicy(sandbox::TargetPolicy* policy,
base::CommandLine* command_line) override;
private:
void BindJsonParserPtr(mojo::ScopedMessagePipeHandle pipe_handle,
mojom::JsonParserPtr* json_parser_ptr);
scoped_refptr<MojoTaskRunner> mojo_task_runner_;
base::OnceClosure connection_error_handler_;
UniqueJsonParserPtr json_parser_ptr_;
DISALLOW_COPY_AND_ASSIGN(JsonParserSandboxSetupHooks);
};
// Spawn a sandboxed process with type kJsonParser, and return the bound
// |json_parser_ptr|.
ResultCode SpawnJsonParserSandbox(
scoped_refptr<MojoTaskRunner> mojo_task_runner,
base::OnceClosure connection_error_handler,
UniqueJsonParserPtr* json_parser_ptr);
} // namespace chrome_cleaner
#endif // CHROME_CHROME_CLEANER_JSON_PARSER_SANDBOX_SETUP_HOOKS_H_
// Copyright 2018 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.
#include "base/synchronization/waitable_event.h"
#include "base/test/multiprocess_test.h"
#include "base/test/test_timeouts.h"
#include "base/time/time.h"
#include "chrome/chrome_cleaner/interfaces/json_parser.mojom.h"
#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
#include "chrome/chrome_cleaner/json_parser/sandbox_setup_hooks.h"
#include "chrome/chrome_cleaner/json_parser/sandbox_target_hooks.h"
#include "sandbox/win/src/sandbox_factory.h"
#include "testing/multiprocess_func_list.h"
using base::WaitableEvent;
namespace chrome_cleaner {
namespace {
const char kTestJsonKey[] = "name";
const char kTestJsonValue[] = "Jason";
const char kTestJsonText[] = "{ \"name\": \"Jason\" }";
const char kInvalidJsonText[] = "{ name: jason }";
class JsonParserSandboxSetupTest : public base::MultiProcessTest {
public:
JsonParserSandboxSetupTest()
: json_parser_ptr_(nullptr, base::OnTaskRunnerDeleter(nullptr)) {}
void SetUp() override {
mojo_task_runner_ = MojoTaskRunner::Create();
JsonParserSandboxSetupHooks setup_hooks(
mojo_task_runner_.get(), base::BindOnce([] {
FAIL() << "JsonParser sandbox connection error";
}));
ASSERT_EQ(RESULT_CODE_SUCCESS,
StartSandboxTarget(MakeCmdLine("JsonParserSandboxTargetMain"),
&setup_hooks, SandboxType::kTest));
json_parser_ptr_ = setup_hooks.TakeJsonParserPtr();
}
protected:
scoped_refptr<MojoTaskRunner> mojo_task_runner_;
UniqueJsonParserPtr json_parser_ptr_;
};
void ParseCallbackExpectedKeyValue(const std::string& expected_key,
const std::string& expected_value,
WaitableEvent* done,
base::Optional<base::Value> value,
const base::Optional<std::string>& error) {
ASSERT_FALSE(error.has_value());
ASSERT_TRUE(value.has_value());
ASSERT_TRUE(value->is_dict());
const base::DictionaryValue* dict;
ASSERT_TRUE(value->GetAsDictionary(&dict));
std::string string_value;
ASSERT_TRUE(dict->GetString(expected_key, &string_value));
EXPECT_EQ(expected_value, string_value);
done->Signal();
}
void ParseCallbackExpectedError(WaitableEvent* done,
base::Optional<base::Value> value,
const base::Optional<std::string>& error) {
ASSERT_TRUE(error.has_value());
EXPECT_FALSE(error->empty());
done->Signal();
}
} // namespace
MULTIPROCESS_TEST_MAIN(JsonParserSandboxTargetMain) {
sandbox::TargetServices* sandbox_target_services =
sandbox::SandboxFactory::GetTargetServices();
CHECK(sandbox_target_services);
EXPECT_EQ(RESULT_CODE_SUCCESS,
RunJsonParserSandbox(*base::CommandLine::ForCurrentProcess(),
sandbox_target_services));
return ::testing::Test::HasNonfatalFailure();
}
TEST_F(JsonParserSandboxSetupTest, ParseJsonSandboxed) {
WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL,
WaitableEvent::InitialState::NOT_SIGNALED);
mojo_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
[](mojom::JsonParserPtr* json_parser_ptr, WaitableEvent* done) {
(*json_parser_ptr)
->Parse(kTestJsonText,
base::BindOnce(&ParseCallbackExpectedKeyValue,
kTestJsonKey, kTestJsonValue, done));
},
json_parser_ptr_.get(), &done));
EXPECT_TRUE(done.TimedWait(TestTimeouts::action_timeout()));
}
TEST_F(JsonParserSandboxSetupTest, ParseInvalidJsonSandboxed) {
WaitableEvent done(WaitableEvent::ResetPolicy::MANUAL,
WaitableEvent::InitialState::NOT_SIGNALED);
mojo_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(
[](mojom::JsonParserPtr* json_parser_ptr, WaitableEvent* done) {
(*json_parser_ptr)
->Parse(kInvalidJsonText,
base::BindOnce(&ParseCallbackExpectedError, done));
},
json_parser_ptr_.get(), &done));
EXPECT_TRUE(done.TimedWait(TestTimeouts::action_timeout()));
}
} // namespace chrome_cleaner
// Copyright 2018 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.
#include "chrome/chrome_cleaner/json_parser/sandbox_target_hooks.h"
#include <utility>
#include "chrome/chrome_cleaner/constants/chrome_cleaner_switches.h"
#include "chrome/chrome_cleaner/os/early_exit.h"
namespace chrome_cleaner {
JsonParserSandboxTargetHooks::JsonParserSandboxTargetHooks(
MojoTaskRunner* mojo_task_runner)
: mojo_task_runner_(mojo_task_runner) {}
JsonParserSandboxTargetHooks::~JsonParserSandboxTargetHooks() {
// Ensure Mojo objects are deleted on the IPC thread.
mojo_task_runner_->PostTask(
FROM_HERE, base::BindOnce(
[](std::unique_ptr<JsonParserImpl> json_parser_impl) {
json_parser_impl.reset();
},
base::Passed(&json_parser_impl_)));
}
ResultCode JsonParserSandboxTargetHooks::TargetDroppedPrivileges(
const base::CommandLine& command_line) {
mojom::JsonParserRequest request(ExtractSandboxMessagePipe(command_line));
// This loop will run forever. Once the communication channel with the broker
// process is broken, mojo error handler will abort this process.
base::RunLoop run_loop;
mojo_task_runner_->PostTask(
FROM_HERE,
base::BindOnce(&JsonParserSandboxTargetHooks::CreateJsonParserImpl,
base::Unretained(this), base::Passed(&request)));
run_loop.Run();
return RESULT_CODE_SUCCESS;
}
void JsonParserSandboxTargetHooks::CreateJsonParserImpl(
mojom::JsonParserRequest request) {
json_parser_impl_ = std::make_unique<JsonParserImpl>(
std::move(request), base::BindOnce(&EarlyExit, 1));
}
ResultCode RunJsonParserSandbox(const base::CommandLine& command_line,
sandbox::TargetServices* target_services) {
scoped_refptr<MojoTaskRunner> mojo_task_runner = MojoTaskRunner::Create();
JsonParserSandboxTargetHooks target_hooks(mojo_task_runner.get());
return RunSandboxTarget(command_line, target_services, &target_hooks);
}
} // namespace chrome_cleaner
// Copyright 2018 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_CHROME_CLEANER_JSON_PARSER_SANDBOX_TARGET_HOOKS_H_
#define CHROME_CHROME_CLEANER_JSON_PARSER_SANDBOX_TARGET_HOOKS_H_
#include <memory>
#include "base/command_line.h"
#include "chrome/chrome_cleaner/interfaces/json_parser.mojom.h"
#include "chrome/chrome_cleaner/ipc/mojo_sandbox_hooks.h"
#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
#include "chrome/chrome_cleaner/json_parser/json_parser_impl.h"
#include "components/chrome_cleaner/public/constants/result_codes.h"
namespace chrome_cleaner {
// Hooks to initialize the sandboxed JSON parser process by creating a
// JsonParserImpl instance and binding it to the mojo pipe.
class JsonParserSandboxTargetHooks : public MojoSandboxTargetHooks {
public:
explicit JsonParserSandboxTargetHooks(MojoTaskRunner* mojo_task_runner);
~JsonParserSandboxTargetHooks() override;
// SandboxTargetHooks
ResultCode TargetDroppedPrivileges(
const base::CommandLine& command_line) override;
private:
void CreateJsonParserImpl(mojom::JsonParserRequest request);
MojoTaskRunner* mojo_task_runner_;
base::MessageLoop message_loop_;
std::unique_ptr<JsonParserImpl> json_parser_impl_;
DISALLOW_COPY_AND_ASSIGN(JsonParserSandboxTargetHooks);
};
// Run the JSON parser, to be called in a newly spawned process.
ResultCode RunJsonParserSandbox(const base::CommandLine& command_line,
sandbox::TargetServices* target_services);
} // namespace chrome_cleaner
#endif // CHROME_CHROME_CLEANER_JSON_PARSER_SANDBOX_TARGET_HOOKS_H_
// Copyright 2018 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.
#include "chrome/chrome_cleaner/json_parser/sandboxed_json_parser.h"
namespace chrome_cleaner {
SandboxedJsonParser::SandboxedJsonParser(MojoTaskRunner* mojo_task_runner,
mojom::JsonParserPtr* json_parser_ptr)
: mojo_task_runner_(mojo_task_runner), json_parser_ptr_(json_parser_ptr) {}
void SandboxedJsonParser::Parse(const std::string& json,
ParseDoneCallback callback) {
mojo_task_runner_->PostTask(
FROM_HERE, base::BindOnce(
[](mojom::JsonParserPtr* json_parser_ptr,
const std::string& json, ParseDoneCallback callback) {
(*json_parser_ptr)->Parse(json, std::move(callback));
},
json_parser_ptr_, json, std::move(callback)));
}
} // namespace chrome_cleaner
// Copyright 2018 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_CHROME_CLEANER_JSON_PARSER_SANDBOXED_JSON_PARSER_H_
#define CHROME_CHROME_CLEANER_JSON_PARSER_SANDBOXED_JSON_PARSER_H_
#include "chrome/chrome_cleaner/interfaces/json_parser.mojom.h"
#include "chrome/chrome_cleaner/ipc/mojo_task_runner.h"
#include "chrome/chrome_cleaner/json_parser/json_parser_api.h"
namespace chrome_cleaner {
// An implementation of JsonParserAPI to wrap a MojoTaskRunner and
// JsonParserPtr. Parses via |json_parser_ptr_| on the |mojo_task_runner_|.
class SandboxedJsonParser : public JsonParserAPI {
public:
SandboxedJsonParser(MojoTaskRunner* mojo_task_runner,
mojom::JsonParserPtr* json_parser_ptr);
void Parse(const std::string& json, ParseDoneCallback callback) override;
private:
MojoTaskRunner* mojo_task_runner_;
mojom::JsonParserPtr* json_parser_ptr_;
};
} // namespace chrome_cleaner
#endif // CHROME_CHROME_CLEANER_JSON_PARSER_SANDBOXED_JSON_PARSER_H_
// Copyright 2018 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.
#include "chrome/chrome_cleaner/json_parser/test_json_parser.h"
#include "base/json/json_reader.h"
#include "base/values.h"
#include "chrome/chrome_cleaner/json_parser/json_parser_impl.h"
namespace chrome_cleaner {
void TestJsonParser::Parse(const std::string& json,
ParseDoneCallback callback) {
int error_code;
std::string error;
std::unique_ptr<base::Value> value = base::JSONReader::ReadAndReturnError(
json,
base::JSON_ALLOW_TRAILING_COMMAS | base::JSON_REPLACE_INVALID_CHARACTERS,
&error_code, &error);
if (value) {
std::move(callback).Run(base::make_optional(std::move(*value)),
base::nullopt);
} else {
std::move(callback).Run(base::nullopt,
base::make_optional(std::move(error)));
}
}
} // namespace chrome_cleaner
// Copyright 2018 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_CHROME_CLEANER_JSON_PARSER_TEST_JSON_PARSER_H_
#define CHROME_CHROME_CLEANER_JSON_PARSER_TEST_JSON_PARSER_H_
#include "chrome/chrome_cleaner/json_parser/json_parser_api.h"
namespace chrome_cleaner {
// An implementation of JsonParserAPI for testing that directly calls
// base::JSONReader and runs the callback with the result. This should only be
// used for tests where a JsonParserAPI is needed.
class TestJsonParser : public JsonParserAPI {
public:
void Parse(const std::string& json, ParseDoneCallback callback) override;
};
} // namespace chrome_cleaner
#endif // CHROME_CHROME_CLEANER_JSON_PARSER_TEST_JSON_PARSER_H_
......@@ -14,6 +14,7 @@ enum class SandboxType {
kNonSandboxed = 0,
kTest,
kEset,
kJsonParser,
kNumValues,
};
......
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