blob: 87674baec923f147b58b443e421428e7d025ec0a [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.
#include <list>
#include "base/logging.h"
#include "base/mac/mach_logging.h"
#include "base/run_loop.h"
#include "base/task/single_thread_task_executor.h"
#include "mojo/core/channel.h"
#include "mojo/core/entrypoints.h"
#include "mojo/core/test/data/channel_mac/channel_mac.pb.h"
#include "mojo/public/cpp/platform/platform_channel.h"
#include "testing/libfuzzer/fuzzers/mach/mach_message_converter.h"
#include "testing/libfuzzer/proto/lpm_interface.h"
namespace {
class ChannelMacFuzzer {
public:
ChannelMacFuzzer() {
mojo::core::InitializeCore();
logging::SetMinLogLevel(logging::LOG_FATAL);
}
scoped_refptr<base::TaskRunner> io_task_runner() {
return io_task_executor_.task_runner();
}
private:
base::SingleThreadTaskExecutor io_task_executor_{base::MessagePump::Type::IO};
};
class FakeChannelDelegate : public mojo::core::Channel::Delegate {
public:
FakeChannelDelegate() = default;
~FakeChannelDelegate() override = default;
void OnChannelMessage(const void* payload,
size_t payload_size,
std::vector<mojo::PlatformHandle> handles) override {}
void OnChannelError(mojo::core::Channel::Error error) override {}
};
} // namespace
DEFINE_BINARY_PROTO_FUZZER(mojo_fuzzer::ChannelMac proto) {
static ChannelMacFuzzer environment;
mojo::PlatformChannel platform_channel;
mojo::PlatformChannelEndpoint fuzzed_endpoint;
mojo::PlatformChannelEndpoint other_endpoint;
mach_port_t send_port = platform_channel.local_endpoint()
.platform_handle()
.GetMachSendRight()
.get();
if (proto.endpoint_type() == mojo_fuzzer::ChannelMac_EndpointType_LOCAL) {
fuzzed_endpoint = platform_channel.TakeLocalEndpoint();
other_endpoint = platform_channel.TakeRemoteEndpoint();
} else if (proto.endpoint_type() ==
mojo_fuzzer::ChannelMac_EndpointType_REMOTE) {
fuzzed_endpoint = platform_channel.TakeRemoteEndpoint();
other_endpoint = platform_channel.TakeLocalEndpoint();
}
FakeChannelDelegate delegate;
auto channel = mojo::core::Channel::Create(
&delegate, mojo::core::ConnectionParams(std::move(fuzzed_endpoint)),
mojo::core::Channel::HandlePolicy::kAcceptHandles,
environment.io_task_runner());
channel->Start();
// If the handshake is not being fuzzed, establish a peer Channel that will
// put |channel| into a good state by performing the handshake.
scoped_refptr<mojo::core::Channel> peer_channel;
if (!proto.fuzz_handshake()) {
peer_channel = mojo::core::Channel::Create(
&delegate, mojo::core::ConnectionParams(std::move(other_endpoint)),
mojo::core::Channel::HandlePolicy::kAcceptHandles,
environment.io_task_runner());
peer_channel->Start();
}
base::RunLoop().RunUntilIdle();
// Save off any ports that were sent as part of a message until after the
// channel has been shut down.
std::list<mach_fuzzer::SendablePort> ports_to_destroy;
for (auto& message : *proto.mutable_messages()) {
if (message.HasExtension(mojo_fuzzer::MojoMessage::mojo_message)) {
// Mojo message data for inline Mach messages is
// [data_length_uint64][data_bytes].
const auto& mojo_message =
message.GetExtension(mojo_fuzzer::MojoMessage::mojo_message);
// If the fuzz data do not specify an explicit length, just use the byte
// length.
uint64_t data_length = mojo_message.has_data_length()
? mojo_message.data_length()
: mojo_message.data().size();
std::string data;
data.append(reinterpret_cast<const char*>(&data_length),
sizeof(data_length));
data.append(mojo_message.data().begin(), mojo_message.data().end());
message.set_data(data);
}
mach_fuzzer::SendResult result = SendMessage(send_port, message);
std::move(result.message.ports.begin(), result.message.ports.end(),
std::back_inserter(ports_to_destroy));
}
base::RunLoop().RunUntilIdle();
channel->ShutDown();
channel.reset();
if (peer_channel) {
peer_channel->ShutDown();
peer_channel.reset();
}
base::RunLoop().RunUntilIdle();
}