| // 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 <stdint.h> |
| |
| #include "base/bind_helpers.h" |
| #include "base/message_loop/message_loop.h" |
| #include "base/no_destructor.h" |
| #include "base/run_loop.h" |
| #include "build/build_config.h" |
| #include "mojo/core/channel.h" |
| #include "mojo/core/connection_params.h" |
| #include "mojo/core/entrypoints.h" |
| #include "mojo/core/node_channel.h" // nogncheck |
| #include "mojo/public/cpp/platform/platform_channel.h" |
| |
| #if defined(OS_WIN) |
| #include <windows.h> |
| #endif |
| |
| using namespace mojo::core; |
| |
| // Implementation of NodeChannel::Delegate which does nothing. All of the |
| // interesting NodeChannel control message message parsing is done by |
| // NodeChannel by the time any of the delegate methods are invoked, so there's |
| // no need for this to do any work. |
| class FakeNodeChannelDelegate : public NodeChannel::Delegate { |
| public: |
| FakeNodeChannelDelegate() = default; |
| ~FakeNodeChannelDelegate() override = default; |
| |
| void OnAcceptInvitee(const ports::NodeName& from_node, |
| const ports::NodeName& inviter_name, |
| const ports::NodeName& token) override {} |
| void OnAcceptInvitation(const ports::NodeName& from_node, |
| const ports::NodeName& token, |
| const ports::NodeName& invitee_name) override {} |
| void OnAddBrokerClient(const ports::NodeName& from_node, |
| const ports::NodeName& client_name, |
| base::ProcessHandle process_handle) override {} |
| void OnBrokerClientAdded(const ports::NodeName& from_node, |
| const ports::NodeName& client_name, |
| mojo::PlatformHandle broker_channel) override {} |
| void OnAcceptBrokerClient(const ports::NodeName& from_node, |
| const ports::NodeName& broker_name, |
| mojo::PlatformHandle broker_channel) override {} |
| void OnEventMessage(const ports::NodeName& from_node, |
| Channel::MessagePtr message) override {} |
| void OnRequestPortMerge(const ports::NodeName& from_node, |
| const ports::PortName& connector_port_name, |
| const std::string& token) override {} |
| void OnRequestIntroduction(const ports::NodeName& from_node, |
| const ports::NodeName& name) override {} |
| void OnIntroduce(const ports::NodeName& from_node, |
| const ports::NodeName& name, |
| mojo::PlatformHandle channel_handle) override {} |
| void OnBroadcast(const ports::NodeName& from_node, |
| Channel::MessagePtr message) override {} |
| #if defined(OS_WIN) || (defined(OS_MACOSX) && !defined(OS_IOS)) |
| void OnRelayEventMessage(const ports::NodeName& from_node, |
| base::ProcessHandle from_process, |
| const ports::NodeName& destination, |
| Channel::MessagePtr message) override {} |
| void OnEventMessageFromRelay(const ports::NodeName& from_node, |
| const ports::NodeName& source_node, |
| Channel::MessagePtr message) override {} |
| #endif |
| void OnAcceptPeer(const ports::NodeName& from_node, |
| const ports::NodeName& token, |
| const ports::NodeName& peer_name, |
| const ports::PortName& port_name) override {} |
| void OnChannelError(const ports::NodeName& node, |
| NodeChannel* channel) override {} |
| }; |
| |
| // A fake delegate for the sending Channel endpoint. The sending Channel is not |
| // being fuzzed and won't receive any interesting messages, so this doesn't need |
| // to do anything. |
| class FakeChannelDelegate : public 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(Channel::Error error) override {} |
| }; |
| |
| // Message deserialization may register handles in the global handle table. We |
| // need to initialize Core for that to be OK. |
| struct Environment { |
| Environment() : message_loop(base::MessageLoop::TYPE_IO) { InitializeCore(); } |
| |
| base::MessageLoop message_loop; |
| }; |
| |
| extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) { |
| static base::NoDestructor<Environment> environment; |
| |
| // Platform-specific implementation of an OS IPC primitive that is normally |
| // used to carry messages between processes. |
| mojo::PlatformChannel channel; |
| |
| FakeNodeChannelDelegate receiver_delegate; |
| auto receiver = NodeChannel::Create( |
| &receiver_delegate, ConnectionParams(channel.TakeLocalEndpoint()), |
| Channel::HandlePolicy::kRejectHandles, |
| environment->message_loop.task_runner(), base::DoNothing()); |
| |
| #if defined(OS_WIN) |
| // On Windows, it's important that the receiver behaves like a broker process |
| // receiving messages from a non-broker process. This is because that case can |
| // safely handle invalid HANDLE attachments without crashing. The same is not |
| // true for messages going in the reverse direction (where the non-broker |
| // receiver has to assume that the broker has already duplicated the HANDLE |
| // into the non-broker's process), but fuzzing that direction is not |
| // interesting since a compromised broker process has much bigger problems. |
| // |
| // Note that in order for this hack to work properly, the remote process |
| // handle needs to be a "real" process handle rather than the pseudo-handle |
| // returned by GetCurrentProcessHandle(). Hence the use of OpenProcess(). |
| receiver->SetRemoteProcessHandle(mojo::core::ScopedProcessHandle( |
| ::OpenProcess(PROCESS_ALL_ACCESS, FALSE, ::GetCurrentProcessId()))); |
| #endif |
| |
| receiver->Start(); |
| |
| // We only use a Channel for the sender side, since it allows us to easily |
| // encode and transmit raw messages. For this fuzzer, we allocate a valid |
| // Channel Message with a valid header, but fill its payload contents with |
| // fuzz. Such messages will always reach the receiving NodeChannel to be |
| // parsed further. |
| FakeChannelDelegate sender_delegate; |
| auto sender = Channel::Create(&sender_delegate, |
| ConnectionParams(channel.TakeRemoteEndpoint()), |
| Channel::HandlePolicy::kRejectHandles, |
| environment->message_loop.task_runner()); |
| sender->Start(); |
| auto message = std::make_unique<Channel::Message>(size, 0 /* num_handles */); |
| std::copy(data, data + size, |
| static_cast<unsigned char*>(message->mutable_payload())); |
| sender->Write(std::move(message)); |
| |
| // Make sure |receiver| does whatever work it's gonna do in response to our |
| // message. By the time the loop goes idle, all parsing will be done. |
| base::RunLoop().RunUntilIdle(); |
| |
| // Clean up our channels so we don't leak the underlying OS primitives. |
| sender->ShutDown(); |
| sender.reset(); |
| receiver->ShutDown(); |
| receiver.reset(); |
| base::RunLoop().RunUntilIdle(); |
| |
| return 0; |
| } |