1 // Copyright (c) 2012 The Chromium Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "content/public/browser/browser_message_filter.h"
6
7 #include "base/bind.h"
8 #include "base/bind_helpers.h"
9 #include "base/command_line.h"
10 #include "base/debug/dump_without_crashing.h"
11 #include "base/logging.h"
12 #include "base/macros.h"
13 #include "base/process/process_handle.h"
14 #include "base/task_runner.h"
15 #include "build/build_config.h"
16 #include "content/browser/browser_child_process_host_impl.h"
17 #include "content/browser/child_process_launcher.h"
18 #include "content/public/browser/browser_task_traits.h"
19 #include "content/public/common/content_switches.h"
20 #include "content/public/common/result_codes.h"
21 #include "ipc/ipc_sync_message.h"
22 #include "ipc/message_filter.h"
23
24 using content::BrowserMessageFilter;
25
26 namespace content {
27
28 class BrowserMessageFilter::Internal : public IPC::MessageFilter {
29 public:
Internal(BrowserMessageFilter * filter)30 explicit Internal(BrowserMessageFilter* filter) : filter_(filter) {}
31
32 private:
~Internal()33 ~Internal() override {}
34
35 // IPC::MessageFilter implementation:
OnFilterAdded(IPC::Channel * channel)36 void OnFilterAdded(IPC::Channel* channel) override {
37 filter_->sender_ = channel;
38 filter_->OnFilterAdded(channel);
39 }
40
OnFilterRemoved()41 void OnFilterRemoved() override {
42 for (auto& callback : filter_->filter_removed_callbacks_)
43 std::move(callback).Run();
44 filter_->filter_removed_callbacks_.clear();
45 filter_->OnFilterRemoved();
46 }
47
OnChannelClosing()48 void OnChannelClosing() override {
49 filter_->sender_ = nullptr;
50 filter_->OnChannelClosing();
51 }
52
OnChannelError()53 void OnChannelError() override { filter_->OnChannelError(); }
54
OnChannelConnected(int32_t peer_pid)55 void OnChannelConnected(int32_t peer_pid) override {
56 filter_->peer_process_ = base::Process::OpenWithExtraPrivileges(peer_pid);
57 filter_->OnChannelConnected(peer_pid);
58 }
59
OnMessageReceived(const IPC::Message & message)60 bool OnMessageReceived(const IPC::Message& message) override {
61 DCHECK_CURRENTLY_ON(BrowserThread::IO);
62
63 BrowserThread::ID thread = BrowserThread::IO;
64 filter_->OverrideThreadForMessage(message, &thread);
65
66 scoped_refptr<base::SequencedTaskRunner> destination;
67 if (thread == BrowserThread::UI) {
68 destination = GetUIThreadTaskRunner({});
69 } else {
70 DCHECK_EQ(thread, BrowserThread::IO);
71
72 destination = filter_->OverrideTaskRunnerForMessage(message);
73
74 // Neither override kicked in, dispatch the message immediately from the
75 // IO thread.
76 if (!destination)
77 return DispatchMessage(message);
78 }
79
80 DCHECK(destination);
81 destination->PostTask(
82 FROM_HERE,
83 base::BindOnce(base::IgnoreResult(&Internal::DispatchMessage), this,
84 message));
85 return true;
86 }
87
GetSupportedMessageClasses(std::vector<uint32_t> * supported_message_classes) const88 bool GetSupportedMessageClasses(
89 std::vector<uint32_t>* supported_message_classes) const override {
90 supported_message_classes->assign(
91 filter_->message_classes_to_filter().begin(),
92 filter_->message_classes_to_filter().end());
93 return true;
94 }
95
96 // Dispatches a message to the derived class.
DispatchMessage(const IPC::Message & message)97 bool DispatchMessage(const IPC::Message& message) {
98 bool rv = filter_->OnMessageReceived(message);
99 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO) || rv) <<
100 "Must handle messages that were dispatched to another thread!";
101 return rv;
102 }
103
104 scoped_refptr<BrowserMessageFilter> filter_;
105
106 DISALLOW_COPY_AND_ASSIGN(Internal);
107 };
108
BrowserMessageFilter(uint32_t message_class_to_filter)109 BrowserMessageFilter::BrowserMessageFilter(uint32_t message_class_to_filter)
110 : internal_(nullptr),
111 sender_(nullptr),
112 message_classes_to_filter_(1, message_class_to_filter) {}
113
BrowserMessageFilter(const uint32_t * message_classes_to_filter,size_t num_message_classes_to_filter)114 BrowserMessageFilter::BrowserMessageFilter(
115 const uint32_t* message_classes_to_filter,
116 size_t num_message_classes_to_filter)
117 : internal_(nullptr),
118 sender_(nullptr),
119 message_classes_to_filter_(
120 message_classes_to_filter,
121 message_classes_to_filter + num_message_classes_to_filter) {
122 DCHECK(num_message_classes_to_filter);
123 }
124
AddAssociatedInterface(const std::string & name,const IPC::ChannelProxy::GenericAssociatedInterfaceFactory & factory,base::OnceClosure filter_removed_callback)125 void BrowserMessageFilter::AddAssociatedInterface(
126 const std::string& name,
127 const IPC::ChannelProxy::GenericAssociatedInterfaceFactory& factory,
128 base::OnceClosure filter_removed_callback) {
129 associated_interfaces_.emplace_back(name, factory);
130 filter_removed_callbacks_.emplace_back(std::move(filter_removed_callback));
131 }
132
PeerHandle()133 base::ProcessHandle BrowserMessageFilter::PeerHandle() {
134 return peer_process_.Handle();
135 }
136
OnDestruct() const137 void BrowserMessageFilter::OnDestruct() const {
138 delete this;
139 }
140
Send(IPC::Message * message)141 bool BrowserMessageFilter::Send(IPC::Message* message) {
142 if (message->is_sync()) {
143 // We don't support sending synchronous messages from the browser. If we
144 // really needed it, we can make this class derive from SyncMessageFilter
145 // but it seems better to not allow sending synchronous messages from the
146 // browser, since it might allow a corrupt/malicious renderer to hang us.
147 NOTREACHED() << "Can't send sync message through BrowserMessageFilter!";
148 return false;
149 }
150
151 if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
152 GetIOThreadTaskRunner({})->PostTask(
153 FROM_HERE,
154 base::BindOnce(base::IgnoreResult(&BrowserMessageFilter::Send), this,
155 message));
156 return true;
157 }
158
159 if (sender_)
160 return sender_->Send(message);
161
162 delete message;
163 return false;
164 }
165
166 scoped_refptr<base::SequencedTaskRunner>
OverrideTaskRunnerForMessage(const IPC::Message & message)167 BrowserMessageFilter::OverrideTaskRunnerForMessage(
168 const IPC::Message& message) {
169 return nullptr;
170 }
171
ShutdownForBadMessage()172 void BrowserMessageFilter::ShutdownForBadMessage() {
173 base::CommandLine* command_line = base::CommandLine::ForCurrentProcess();
174 if (command_line->HasSwitch(switches::kDisableKillAfterBadIPC))
175 return;
176
177 if (base::Process::Current().Handle() == peer_process_.Handle()) {
178 // Just crash in single process. Matches RenderProcessHostImpl behavior.
179 CHECK(false);
180 }
181
182 ChildProcessLauncher::TerminateProcess(
183 peer_process_, content::RESULT_CODE_KILLED_BAD_MESSAGE);
184
185 // Report a crash, since none will be generated by the killed renderer.
186 base::debug::DumpWithoutCrashing();
187
188 // Log the renderer kill to the histogram tracking all kills.
189 BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
190 PROCESS_TYPE_RENDERER);
191 }
192
~BrowserMessageFilter()193 BrowserMessageFilter::~BrowserMessageFilter() {
194 }
195
GetFilter()196 IPC::MessageFilter* BrowserMessageFilter::GetFilter() {
197 // We create this on demand so that if a filter is used in a unit test but
198 // never attached to a channel, we don't leak Internal and this;
199 DCHECK(!internal_) << "Should only be called once.";
200 internal_ = new Internal(this);
201 return internal_;
202 }
203
RegisterAssociatedInterfaces(IPC::ChannelProxy * proxy)204 void BrowserMessageFilter::RegisterAssociatedInterfaces(
205 IPC::ChannelProxy* proxy) {
206 for (const auto& entry : associated_interfaces_)
207 proxy->AddGenericAssociatedInterfaceForIOThread(entry.first, entry.second);
208 associated_interfaces_.clear();
209 }
210
211 } // namespace content
212