15821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Copyright (c) 2012 The Chromium Authors. All rights reserved.
25821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// Use of this source code is governed by a BSD-style license that can be
35821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)// found in the LICENSE file.
45821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
55821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/browser_message_filter.h"
65821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
75821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind.h"
85821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/bind_helpers.h"
95821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/logging.h"
1058e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "base/process/kill.h"
1158e6fbe4ee35d65e14b626c557d37565bf8ad179Ben Murdoch#include "base/process/process_handle.h"
125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "base/task_runner.h"
135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/browser/user_metrics.h"
145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "content/public/common/result_codes.h"
155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#include "ipc/ipc_sync_message.h"
165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)using content::BrowserMessageFilter;
185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)namespace content {
205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserMessageFilter::BrowserMessageFilter()
227dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    : channel_(NULL),
237dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#if defined(OS_WIN)
247dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      peer_handle_(base::kNullProcessHandle),
257dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#endif
267dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch      peer_pid_(base::kNullProcessId) {
275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserMessageFilter::OnFilterAdded(IPC::Channel* channel) {
305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  channel_ = channel;
315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserMessageFilter::OnChannelClosing() {
345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  channel_ = NULL;
355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserMessageFilter::OnChannelConnected(int32 peer_pid) {
387dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  peer_pid_ = peer_pid;
395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserMessageFilter::OnMessageReceived(const IPC::Message& message) {
425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::ID thread = BrowserThread::IO;
435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  OverrideThreadForMessage(message, &thread);
445821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (thread == BrowserThread::IO) {
465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    scoped_refptr<base::TaskRunner> runner =
475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        OverrideTaskRunnerForMessage(message);
48868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)    if (runner.get()) {
49868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)      runner->PostTask(
50868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)          FROM_HERE,
515821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)          base::Bind(base::IgnoreResult(&BrowserMessageFilter::DispatchMessage),
52868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                     this,
53868fa2fe829687343ffae624259930155e16dbd8Torne (Richard Coles)                     message));
545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      return true;
555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    }
565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return DispatchMessage(message);
575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (thread == BrowserThread::UI && !CheckCanDispatchOnUI(message, this))
605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  BrowserThread::PostTask(
635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      thread, FROM_HERE,
645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      base::Bind(base::IgnoreResult(&BrowserMessageFilter::DispatchMessage),
655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                 this, message));
665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
697dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdochbase::ProcessHandle BrowserMessageFilter::PeerHandle() {
707dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#if defined(OS_WIN)
717dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::AutoLock lock(peer_handle_lock_);
727dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (peer_handle_ == base::kNullProcessHandle)
737dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::OpenPrivilegedProcessHandle(peer_pid_, &peer_handle_);
747dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
757dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return peer_handle_;
767dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#else
777dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::ProcessHandle result = base::kNullProcessHandle;
787dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::OpenPrivilegedProcessHandle(peer_pid_, &result);
797dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  return result;
807dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#endif
817dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch}
827dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch
835821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserMessageFilter::Send(IPC::Message* message) {
845821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (message->is_sync()) {
855821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // We don't support sending synchronous messages from the browser.  If we
865821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // really needed it, we can make this class derive from SyncMessageFilter
875821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // but it seems better to not allow sending synchronous messages from the
885821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // browser, since it might allow a corrupt/malicious renderer to hang us.
895821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Can't send sync message through BrowserMessageFilter!";
905821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
915821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
925821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
935821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
945821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BrowserThread::PostTask(
955821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        BrowserThread::IO,
965821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        FROM_HERE,
975821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        base::Bind(base::IgnoreResult(&BrowserMessageFilter::Send), this,
985821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                   message));
995821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return true;
1005821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1015821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1025821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (channel_)
1035821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return channel_->Send(message);
1045821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1055821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  delete message;
1065821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return false;
1075821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1085821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1095821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserMessageFilter::OverrideThreadForMessage(const IPC::Message& message,
1105821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                    BrowserThread::ID* thread) {
1115821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1125821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1135821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)base::TaskRunner* BrowserMessageFilter::OverrideTaskRunnerForMessage(
1145821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    const IPC::Message& message) {
1155821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return NULL;
1165821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1175821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1185821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserMessageFilter::CheckCanDispatchOnUI(const IPC::Message& message,
1195821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                                                IPC::Sender* sender) {
1205821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#if defined(OS_WIN)
1215821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On Windows there's a potential deadlock with sync messsages going in
1225821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // a circle from browser -> plugin -> renderer -> browser.
1235821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On Linux we can avoid this by avoiding sync messages from browser->plugin.
1245821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  // On Mac we avoid this by not supporting windowed plugins.
1255821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (message.is_sync() && !message.is_caller_pumping_messages()) {
1265821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NOTE: IF YOU HIT THIS ASSERT, THE SOLUTION IS ALMOST NEVER TO RUN A
1275821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // NESTED MESSAGE LOOP IN THE RENDERER!!!
1285821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // That introduces reentrancy which causes hard to track bugs.  You should
1295821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // find a way to either turn this into an asynchronous message, or one
1305821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    // that can be answered on the IO thread.
1315821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    NOTREACHED() << "Can't send sync messages to UI thread without pumping "
1325821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "messages in the renderer or else deadlocks can occur if the page "
1335821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)        "has windowed plugins! (message type " << message.type() << ")";
1345821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
1355821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    reply->set_reply_error();
1365821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    sender->Send(reply);
1375821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    return false;
1385821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1395821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)#endif
1405821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return true;
1415821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1425821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1435821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)void BrowserMessageFilter::BadMessageReceived() {
1447dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  base::KillProcess(PeerHandle(), content::RESULT_CODE_KILLED_BAD_MESSAGE,
1455821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)                    false);
1465821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1475821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1485821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)BrowserMessageFilter::~BrowserMessageFilter() {
1497dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#if defined(OS_WIN)
1507dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch  if (peer_handle_ != base::kNullProcessHandle)
1517dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch    base::CloseProcessHandle(peer_handle_);
1527dbb3d5cf0c15f500944d211057644d6a2f37371Ben Murdoch#endif
1535821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1545821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1555821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)bool BrowserMessageFilter::DispatchMessage(const IPC::Message& message) {
1565821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool message_was_ok = true;
1575821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  bool rv = OnMessageReceived(message, &message_was_ok);
1585821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO) || rv) <<
1595821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)      "Must handle messages that were dispatched to another thread!";
1605821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  if (!message_was_ok) {
1615821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    content::RecordAction(UserMetricsAction("BadMessageTerminate_BMF"));
1625821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)    BadMessageReceived();
1635821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  }
1645821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1655821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)  return rv;
1665821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}
1675821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)
1685821806d5e7f356e8fa4b058a389a808ea183019Torne (Richard Coles)}  // namespace content
169