Browse Source

chore: cherry-pick 5e61913985df from chromium (#25389)

Cheng Zhao 4 years ago
parent
commit
20f58fddf1
2 changed files with 550 additions and 0 deletions
  1. 1 0
      patches/chromium/.patches
  2. 549 0
      patches/chromium/backport_1081874.patch

+ 1 - 0
patches/chromium/.patches

@@ -132,3 +132,4 @@ indexeddb_fix_crash_in_webidbgetdbnamescallbacksimpl.patch
 indexeddb_reset_async_tasks_in_webidbgetdbnamescallbacksimpl.patch
 reland_fix_uaf_in_selecttype.patch
 cherry-pick-f6cb89728f04.patch
+backport_1081874.patch

+ 549 - 0
patches/chromium/backport_1081874.patch

@@ -0,0 +1,549 @@
+From 0000000000000000000000000000000000000000 Mon Sep 17 00:00:00 2001
+From: Cheng Zhao <[email protected]>
+Date: Thu, 4 Oct 2018 14:57:02 -0700
+Subject: fix: data race on NodeChannel destruction
+
+[1081874] [High] [CVE-2020-6575]: Double free on NodeChannel
+Backport https://chromium.googlesource.com/chromium/src/+/5e61913985df0cc621bf72f7fa75e76759ffde15.
+
+diff --git a/mojo/core/BUILD.gn b/mojo/core/BUILD.gn
+index e6fcb96256f6fdb867a362588547a7829f28efe8..6282eed9158c691a9ca49d1ec9a57cedc4392741 100644
+--- a/mojo/core/BUILD.gn
++++ b/mojo/core/BUILD.gn
+@@ -18,6 +18,7 @@ component("embedder_internal") {
+     ":test_sources",
+     "//mojo:*",
+     "//mojo/core/embedder",
++    "//mojo/core/test:test_support",
+   ]
+ }
+ 
+@@ -57,6 +58,7 @@ template("core_impl_source_set") {
+       "handle_table.h",
+       "invitation_dispatcher.h",
+       "message_pipe_dispatcher.h",
++      "node_channel.h",
+       "node_controller.h",
+       "options_validation.h",
+       "platform_handle_dispatcher.h",
+@@ -86,7 +88,6 @@ template("core_impl_source_set") {
+       "invitation_dispatcher.cc",
+       "message_pipe_dispatcher.cc",
+       "node_channel.cc",
+-      "node_channel.h",
+       "node_controller.cc",
+       "platform_handle_dispatcher.cc",
+       "platform_handle_in_transit.cc",
+@@ -289,6 +290,7 @@ source_set("test_sources") {
+     "handle_table_unittest.cc",
+     "message_pipe_unittest.cc",
+     "message_unittest.cc",
++    "node_channel_unittest.cc",
+     "options_validation_unittest.cc",
+     "platform_handle_dispatcher_unittest.cc",
+     "quota_unittest.cc",
+@@ -387,6 +389,7 @@ fuzzer_test("mojo_core_node_channel_fuzzer") {
+   deps = [
+     ":core_impl_for_fuzzers",
+     "//base",
++    "//mojo/core/test:test_support",
+     "//mojo/public/cpp/platform",
+   ]
+ }
+diff --git a/mojo/core/embedder/embedder.cc b/mojo/core/embedder/embedder.cc
+index ec68e37d09888f672759f79961e3e6e4d18f0c5c..f70c73be4df529cce09cb503dfce28f2a04e7e1a 100644
+--- a/mojo/core/embedder/embedder.cc
++++ b/mojo/core/embedder/embedder.cc
+@@ -35,7 +35,7 @@ void SetDefaultProcessErrorCallback(ProcessErrorCallback callback) {
+   Core::Get()->SetDefaultProcessErrorCallback(std::move(callback));
+ }
+ 
+-scoped_refptr<base::TaskRunner> GetIOTaskRunner() {
++scoped_refptr<base::SingleThreadTaskRunner> GetIOTaskRunner() {
+   return Core::Get()->GetNodeController()->io_task_runner();
+ }
+ 
+diff --git a/mojo/core/embedder/embedder.h b/mojo/core/embedder/embedder.h
+index 5d65400987728940a296ba2a84d40158f52d6d34..96dc44c0a78e0e6cb6e5aa511bd2fd4f1252cf16 100644
+--- a/mojo/core/embedder/embedder.h
++++ b/mojo/core/embedder/embedder.h
+@@ -13,7 +13,7 @@
+ #include "base/component_export.h"
+ #include "base/memory/ref_counted.h"
+ #include "base/process/process_handle.h"
+-#include "base/task_runner.h"
++#include "base/single_thread_task_runner.h"
+ #include "build/build_config.h"
+ #include "mojo/core/embedder/configuration.h"
+ 
+@@ -42,9 +42,10 @@ void SetDefaultProcessErrorCallback(ProcessErrorCallback callback);
+ 
+ // Initialialization/shutdown for interprocess communication (IPC) -------------
+ 
+-// Retrieves the TaskRunner used for IPC I/O, as set by ScopedIPCSupport.
++// Retrieves the SequencedTaskRunner used for IPC I/O, as set by
++// ScopedIPCSupport.
+ COMPONENT_EXPORT(MOJO_CORE_EMBEDDER)
+-scoped_refptr<base::TaskRunner> GetIOTaskRunner();
++scoped_refptr<base::SingleThreadTaskRunner> GetIOTaskRunner();
+ 
+ }  // namespace core
+ }  // namespace mojo
+diff --git a/mojo/core/node_channel.cc b/mojo/core/node_channel.cc
+index e898b044286e019b5e423b941502030ce3094582..061ea1026e95d1b1f80a762ce377aebdd97e1b42 100644
+--- a/mojo/core/node_channel.cc
++++ b/mojo/core/node_channel.cc
+@@ -228,7 +228,7 @@ void NodeChannel::NotifyBadMessage(const std::string& error) {
+ }
+ 
+ void NodeChannel::SetRemoteProcessHandle(ScopedProcessHandle process_handle) {
+-  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
++  DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+   {
+     base::AutoLock lock(channel_lock_);
+     if (channel_)
+@@ -253,7 +253,7 @@ ScopedProcessHandle NodeChannel::CloneRemoteProcessHandle() {
+ }
+ 
+ void NodeChannel::SetRemoteNodeName(const ports::NodeName& name) {
+-  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
++  DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+   remote_node_name_ = name;
+ }
+ 
+@@ -468,15 +468,15 @@ NodeChannel::NodeChannel(
+     Channel::HandlePolicy channel_handle_policy,
+     scoped_refptr<base::SingleThreadTaskRunner> io_task_runner,
+     const ProcessErrorCallback& process_error_callback)
+-    : delegate_(delegate),
+-      io_task_runner_(io_task_runner),
++    : base::RefCountedDeleteOnSequence<NodeChannel>(io_task_runner),
++      delegate_(delegate),
+       process_error_callback_(process_error_callback)
+ #if !defined(OS_NACL_SFI)
+       ,
+       channel_(Channel::Create(this,
+                                std::move(connection_params),
+                                channel_handle_policy,
+-                               io_task_runner_))
++                               std::move(io_task_runner)))
+ #endif
+ {
+ }
+@@ -499,15 +499,10 @@ void NodeChannel::CreateAndBindLocalBrokerHost(
+ void NodeChannel::OnChannelMessage(const void* payload,
+                                    size_t payload_size,
+                                    std::vector<PlatformHandle> handles) {
+-  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
++  DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+ 
+   RequestContext request_context(RequestContext::Source::SYSTEM);
+ 
+-  // Ensure this NodeChannel stays alive through the extent of this method. The
+-  // delegate may have the only other reference to this object and it may choose
+-  // to drop it here in response to, e.g., a malformed message.
+-  scoped_refptr<NodeChannel> keepalive = this;
+-
+   if (payload_size <= sizeof(Header)) {
+     delegate_->OnChannelError(remote_node_name_, this);
+     return;
+@@ -739,7 +734,7 @@ void NodeChannel::OnChannelMessage(const void* payload,
+ }
+ 
+ void NodeChannel::OnChannelError(Channel::Error error) {
+-  DCHECK(io_task_runner_->RunsTasksInCurrentSequence());
++  DCHECK(owning_task_runner()->RunsTasksInCurrentSequence());
+ 
+   RequestContext request_context(RequestContext::Source::SYSTEM);
+ 
+diff --git a/mojo/core/node_channel.h b/mojo/core/node_channel.h
+index ea91f927049befa258884b13e7f7966c09518687..04501da0fb6cd36df1b332135282104dd442b41e 100644
+--- a/mojo/core/node_channel.h
++++ b/mojo/core/node_channel.h
+@@ -11,7 +11,7 @@
+ #include "base/callback.h"
+ #include "base/containers/queue.h"
+ #include "base/macros.h"
+-#include "base/memory/ref_counted.h"
++#include "base/memory/ref_counted_delete_on_sequence.h"
+ #include "base/process/process_handle.h"
+ #include "base/single_thread_task_runner.h"
+ #include "base/synchronization/lock.h"
+@@ -21,13 +21,15 @@
+ #include "mojo/core/embedder/process_error_callback.h"
+ #include "mojo/core/ports/name.h"
+ #include "mojo/core/scoped_process_handle.h"
++#include "mojo/core/system_impl_export.h"
+ 
+ namespace mojo {
+ namespace core {
+ 
+ // Wraps a Channel to send and receive Node control messages.
+-class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
+-                    public Channel::Delegate {
++class MOJO_SYSTEM_IMPL_EXPORT NodeChannel
++    : public base::RefCountedDeleteOnSequence<NodeChannel>,
++      public Channel::Delegate {
+  public:
+   class Delegate {
+    public:
+@@ -92,8 +94,6 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
+                                   void** data,
+                                   size_t* num_data_bytes);
+ 
+-  Channel* channel() const { return channel_.get(); }
+-
+   // Start receiving messages.
+   void Start();
+ 
+@@ -155,7 +155,8 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
+ #endif
+ 
+  private:
+-  friend class base::RefCountedThreadSafe<NodeChannel>;
++  friend class base::RefCountedDeleteOnSequence<NodeChannel>;
++  friend class base::DeleteHelper<NodeChannel>;
+ 
+   using PendingMessageQueue = base::queue<Channel::MessagePtr>;
+   using PendingRelayMessageQueue =
+@@ -181,13 +182,12 @@ class NodeChannel : public base::RefCountedThreadSafe<NodeChannel>,
+   void WriteChannelMessage(Channel::MessagePtr message);
+ 
+   Delegate* const delegate_;
+-  const scoped_refptr<base::SingleThreadTaskRunner> io_task_runner_;
+   const ProcessErrorCallback process_error_callback_;
+ 
+   base::Lock channel_lock_;
+-  scoped_refptr<Channel> channel_;
++  scoped_refptr<Channel> channel_ GUARDED_BY(channel_lock_);
+ 
+-  // Must only be accessed from |io_task_runner_|'s thread.
++  // Must only be accessed from the owning task runner's thread.
+   ports::NodeName remote_node_name_;
+ 
+   base::Lock remote_process_handle_lock_;
+diff --git a/mojo/core/node_channel_fuzzer.cc b/mojo/core/node_channel_fuzzer.cc
+index 99047c000dbe6be90f1d28b4b6817e608f9853a6..54fe757e0dec8aa138af96aa1a0afe596563c26c 100644
+--- a/mojo/core/node_channel_fuzzer.cc
++++ b/mojo/core/node_channel_fuzzer.cc
+@@ -14,6 +14,7 @@
+ #include "mojo/core/connection_params.h"
+ #include "mojo/core/entrypoints.h"
+ #include "mojo/core/node_channel.h"  // nogncheck
++#include "mojo/core/test/mock_node_channel_delegate.h"
+ #include "mojo/public/cpp/platform/platform_channel.h"
+ 
+ #if defined(OS_WIN)
+@@ -24,60 +25,6 @@ using mojo::core::Channel;
+ using mojo::core::ConnectionParams;
+ using mojo::core::ports::NodeName;
+ 
+-// 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 mojo::core::NodeChannel::Delegate {
+- public:
+-  FakeNodeChannelDelegate() = default;
+-  ~FakeNodeChannelDelegate() override = default;
+-
+-  void OnAcceptInvitee(const NodeName& from_node,
+-                       const NodeName& inviter_name,
+-                       const NodeName& token) override {}
+-  void OnAcceptInvitation(const NodeName& from_node,
+-                          const NodeName& token,
+-                          const NodeName& invitee_name) override {}
+-  void OnAddBrokerClient(const NodeName& from_node,
+-                         const NodeName& client_name,
+-                         base::ProcessHandle process_handle) override {}
+-  void OnBrokerClientAdded(const NodeName& from_node,
+-                           const NodeName& client_name,
+-                           mojo::PlatformHandle broker_channel) override {}
+-  void OnAcceptBrokerClient(const NodeName& from_node,
+-                            const NodeName& broker_name,
+-                            mojo::PlatformHandle broker_channel) override {}
+-  void OnEventMessage(const NodeName& from_node,
+-                      Channel::MessagePtr message) override {}
+-  void OnRequestPortMerge(
+-      const NodeName& from_node,
+-      const mojo::core::ports::PortName& connector_port_name,
+-      const std::string& token) override {}
+-  void OnRequestIntroduction(const NodeName& from_node,
+-                             const NodeName& name) override {}
+-  void OnIntroduce(const NodeName& from_node,
+-                   const NodeName& name,
+-                   mojo::PlatformHandle channel_handle) override {}
+-  void OnBroadcast(const NodeName& from_node,
+-                   Channel::MessagePtr message) override {}
+-#if defined(OS_WIN)
+-  void OnRelayEventMessage(const NodeName& from_node,
+-                           base::ProcessHandle from_process,
+-                           const NodeName& destination,
+-                           Channel::MessagePtr message) override {}
+-  void OnEventMessageFromRelay(const NodeName& from_node,
+-                               const NodeName& source_node,
+-                               Channel::MessagePtr message) override {}
+-#endif
+-  void OnAcceptPeer(const NodeName& from_node,
+-                    const NodeName& token,
+-                    const NodeName& peer_name,
+-                    const mojo::core::ports::PortName& port_name) override {}
+-  void OnChannelError(const NodeName& node,
+-                      mojo::core::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.
+@@ -109,7 +56,7 @@ extern "C" int LLVMFuzzerTestOneInput(const unsigned char* data, size_t size) {
+   // used to carry messages between processes.
+   mojo::PlatformChannel channel;
+ 
+-  FakeNodeChannelDelegate receiver_delegate;
++  mojo::core::MockNodeChannelDelegate receiver_delegate;
+   auto receiver = mojo::core::NodeChannel::Create(
+       &receiver_delegate, ConnectionParams(channel.TakeLocalEndpoint()),
+       Channel::HandlePolicy::kRejectHandles,
+diff --git a/mojo/core/node_channel_unittest.cc b/mojo/core/node_channel_unittest.cc
+new file mode 100644
+index 0000000000000000000000000000000000000000..13c46f13fea6342316534a7a843debbf7586108d
+--- /dev/null
++++ b/mojo/core/node_channel_unittest.cc
+@@ -0,0 +1,72 @@
++// Copyright 2020 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 "mojo/core/node_channel.h"
++
++#include "base/bind_helpers.h"
++#include "base/memory/scoped_refptr.h"
++#include "base/message_loop/message_pump_type.h"
++#include "base/test/task_environment.h"
++#include "base/threading/thread.h"
++#include "mojo/core/embedder/embedder.h"
++#include "mojo/core/test/mock_node_channel_delegate.h"
++#include "mojo/public/cpp/platform/platform_channel.h"
++#include "mojo/public/cpp/platform/platform_channel_endpoint.h"
++#include "testing/gtest/include/gtest/gtest.h"
++
++namespace mojo {
++namespace core {
++namespace {
++
++using NodeChannelTest = testing::Test;
++using ports::NodeName;
++
++scoped_refptr<NodeChannel> CreateNodeChannel(NodeChannel::Delegate* delegate,
++                                             PlatformChannelEndpoint endpoint) {
++  return NodeChannel::Create(delegate, ConnectionParams(std::move(endpoint)),
++                             Channel::HandlePolicy::kAcceptHandles,
++                             GetIOTaskRunner(), base::NullCallback());
++}
++
++TEST_F(NodeChannelTest, DestructionIsSafe) {
++  // Regression test for https://crbug.com/1081874.
++  base::test::TaskEnvironment task_environment;
++
++  PlatformChannel channel;
++  MockNodeChannelDelegate local_delegate;
++  auto local_channel =
++      CreateNodeChannel(&local_delegate, channel.TakeLocalEndpoint());
++  local_channel->Start();
++  MockNodeChannelDelegate remote_delegate;
++  auto remote_channel =
++      CreateNodeChannel(&remote_delegate, channel.TakeRemoteEndpoint());
++  remote_channel->Start();
++
++  // Verify end-to-end operation
++  const NodeName kRemoteNodeName{123, 456};
++  const NodeName kToken{987, 654};
++  base::RunLoop loop;
++  EXPECT_CALL(local_delegate,
++              OnAcceptInvitee(ports::kInvalidNodeName, kRemoteNodeName, kToken))
++      .WillRepeatedly([&] { loop.Quit(); });
++  remote_channel->AcceptInvitee(kRemoteNodeName, kToken);
++  loop.Run();
++
++  // Now send another message to the local endpoint but tear it down
++  // immediately. This will race with the message being received on the IO
++  // thread, and although the corresponding delegate call may or may not
++  // dispatch as a result, the race should still be memory-safe.
++  remote_channel->AcceptInvitee(kRemoteNodeName, kToken);
++
++  base::RunLoop error_loop;
++  EXPECT_CALL(remote_delegate, OnChannelError).WillOnce([&] {
++    error_loop.Quit();
++  });
++  local_channel.reset();
++  error_loop.Run();
++}
++
++}  // namespace
++}  // namespace core
++}  // namespace mojo
+diff --git a/mojo/core/test/BUILD.gn b/mojo/core/test/BUILD.gn
+index 1abadfc503d5176d2af1dcecfde153f17488546d..9429c61853059e10ca2430ad79ec8d9a39d90906 100644
+--- a/mojo/core/test/BUILD.gn
++++ b/mojo/core/test/BUILD.gn
+@@ -7,6 +7,8 @@ import("//third_party/protobuf/proto_library.gni")
+ static_library("test_support") {
+   testonly = true
+   sources = [
++    "mock_node_channel_delegate.cc",
++    "mock_node_channel_delegate.h",
+     "mojo_test_base.cc",
+     "mojo_test_base.h",
+     "test_utils.h",
+@@ -27,8 +29,10 @@ static_library("test_support") {
+   public_deps = [
+     "//base",
+     "//base/test:test_support",
++    "//mojo/core:embedder_internal",
+     "//mojo/core/embedder",
+     "//mojo/public/cpp/system",
++    "//testing/gmock",
+     "//testing/gtest",
+   ]
+ }
+diff --git a/mojo/core/test/mock_node_channel_delegate.cc b/mojo/core/test/mock_node_channel_delegate.cc
+new file mode 100644
+index 0000000000000000000000000000000000000000..d257c3e1dc03857f91e94807328a0dc176f332f4
+--- /dev/null
++++ b/mojo/core/test/mock_node_channel_delegate.cc
+@@ -0,0 +1,15 @@
++// Copyright 2020 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 "mojo/core/test/mock_node_channel_delegate.h"
++
++namespace mojo {
++namespace core {
++
++MockNodeChannelDelegate::MockNodeChannelDelegate() = default;
++
++MockNodeChannelDelegate::~MockNodeChannelDelegate() = default;
++
++}  // namespace core
++}  // namespace mojo
+diff --git a/mojo/core/test/mock_node_channel_delegate.h b/mojo/core/test/mock_node_channel_delegate.h
+new file mode 100644
+index 0000000000000000000000000000000000000000..06ca96857b9472682d577a802c68a56a7af0aacd
+--- /dev/null
++++ b/mojo/core/test/mock_node_channel_delegate.h
+@@ -0,0 +1,114 @@
++// Copyright 2020 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 MOJO_CORE_TEST_MOCK_NODE_CHANNEL_DELEGATE_H_
++#define MOJO_CORE_TEST_MOCK_NODE_CHANNEL_DELEGATE_H_
++
++#include "build/build_config.h"
++#include "mojo/core/node_channel.h"
++#include "testing/gmock/include/gmock/gmock.h"
++
++namespace mojo {
++namespace core {
++
++// A NodeChannel Delegate implementation which can be used by NodeChannel unit
++// tests and fuzzers.
++class MockNodeChannelDelegate
++    : public testing::NiceMock<NodeChannel::Delegate> {
++ public:
++  using NodeName = ports::NodeName;
++  using PortName = ports::PortName;
++
++  MockNodeChannelDelegate();
++  MockNodeChannelDelegate(const MockNodeChannelDelegate&) = delete;
++  MockNodeChannelDelegate& operator=(const MockNodeChannelDelegate&) = delete;
++  ~MockNodeChannelDelegate() override;
++
++  // testing::NiceMock<NodeChannel::Delegate> implementation:
++  MOCK_METHOD(void,
++              OnAcceptInvitee,
++              (const NodeName& from_node,
++               const NodeName& inviter_name,
++               const NodeName& token),
++              (override));
++  MOCK_METHOD(void,
++              OnAcceptInvitation,
++              (const NodeName& from_node,
++               const NodeName& token,
++               const NodeName& invitee_name),
++              (override));
++  MOCK_METHOD(void,
++              OnAddBrokerClient,
++              (const NodeName& from_node,
++               const NodeName& client_name,
++               base::ProcessHandle process_handle),
++              (override));
++  MOCK_METHOD(void,
++              OnBrokerClientAdded,
++              (const NodeName& from_node,
++               const NodeName& client_name,
++               PlatformHandle broker_channel),
++              (override));
++  MOCK_METHOD(void,
++              OnAcceptBrokerClient,
++              (const NodeName& from_node,
++               const NodeName& broker_name,
++               PlatformHandle broker_channel),
++              (override));
++  MOCK_METHOD(void,
++              OnEventMessage,
++              (const NodeName& from_node, Channel::MessagePtr message),
++              (override));
++  MOCK_METHOD(void,
++              OnRequestPortMerge,
++              (const NodeName& from_node,
++               const PortName& connector_port_name,
++               const std::string& token),
++              (override));
++  MOCK_METHOD(void,
++              OnRequestIntroduction,
++              (const NodeName& from_node, const NodeName& name),
++              (override));
++  MOCK_METHOD(void,
++              OnIntroduce,
++              (const NodeName& from_node,
++               const NodeName& name,
++               PlatformHandle channel_handle),
++              (override));
++  MOCK_METHOD(void,
++              OnBroadcast,
++              (const NodeName& from_node, Channel::MessagePtr message),
++              (override));
++#if defined(OS_WIN)
++  MOCK_METHOD(void,
++              OnRelayEventMessage,
++              (const NodeName& from_node,
++               base::ProcessHandle from_process,
++               const NodeName& destination,
++               Channel::MessagePtr message),
++              (override));
++  MOCK_METHOD(void,
++              OnEventMessageFromRelay,
++              (const NodeName& from_node,
++               const NodeName& source_node,
++               Channel::MessagePtr message),
++              (override));
++#endif
++  MOCK_METHOD(void,
++              OnAcceptPeer,
++              (const NodeName& from_node,
++               const NodeName& token,
++               const NodeName& peer_name,
++               const PortName& port_name),
++              (override));
++  MOCK_METHOD(void,
++              OnChannelError,
++              (const NodeName& node, NodeChannel* channel),
++              (override));
++};
++
++}  // namespace core
++}  // namespace mojo
++
++#endif  // MOJO_CORE_TEST_MOCK_NODE_CHANNEL_DELEGATE_H_