• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/logging.h"
11 #include "base/process/kill.h"
12 #include "base/process/process_handle.h"
13 #include "base/task_runner.h"
14 #include "content/browser/browser_child_process_host_impl.h"
15 #include "content/public/browser/user_metrics.h"
16 #include "content/public/common/content_switches.h"
17 #include "content/public/common/result_codes.h"
18 #include "ipc/ipc_sync_message.h"
19 #include "ipc/message_filter.h"
20 
21 using content::BrowserMessageFilter;
22 
23 namespace content {
24 
25 class BrowserMessageFilter::Internal : public IPC::MessageFilter {
26  public:
Internal(BrowserMessageFilter * filter)27   explicit Internal(BrowserMessageFilter* filter) : filter_(filter) {}
28 
29  private:
~Internal()30   virtual ~Internal() {}
31 
32   // IPC::MessageFilter implementation:
OnFilterAdded(IPC::Sender * sender)33   virtual void OnFilterAdded(IPC::Sender* sender) OVERRIDE {
34     filter_->sender_ = sender;
35     filter_->OnFilterAdded(sender);
36   }
37 
OnFilterRemoved()38   virtual void OnFilterRemoved() OVERRIDE {
39     filter_->OnFilterRemoved();
40   }
41 
OnChannelClosing()42   virtual void OnChannelClosing() OVERRIDE {
43     filter_->sender_ = NULL;
44     filter_->OnChannelClosing();
45   }
46 
OnChannelConnected(int32 peer_pid)47   virtual void OnChannelConnected(int32 peer_pid) OVERRIDE {
48     filter_->peer_pid_ = peer_pid;
49     filter_->OnChannelConnected(peer_pid);
50   }
51 
OnMessageReceived(const IPC::Message & message)52   virtual bool OnMessageReceived(const IPC::Message& message) OVERRIDE {
53     BrowserThread::ID thread = BrowserThread::IO;
54     filter_->OverrideThreadForMessage(message, &thread);
55 
56     if (thread == BrowserThread::IO) {
57       scoped_refptr<base::TaskRunner> runner =
58           filter_->OverrideTaskRunnerForMessage(message);
59       if (runner.get()) {
60         runner->PostTask(
61             FROM_HERE,
62             base::Bind(
63                 base::IgnoreResult(&Internal::DispatchMessage), this, message));
64         return true;
65       }
66       return DispatchMessage(message);
67     }
68 
69     if (thread == BrowserThread::UI &&
70         !BrowserMessageFilter::CheckCanDispatchOnUI(message, filter_)) {
71       return true;
72     }
73 
74     BrowserThread::PostTask(
75         thread, FROM_HERE,
76         base::Bind(
77             base::IgnoreResult(&Internal::DispatchMessage), this, message));
78     return true;
79   }
80 
GetSupportedMessageClasses(std::vector<uint32> * supported_message_classes) const81   virtual bool GetSupportedMessageClasses(
82       std::vector<uint32>* supported_message_classes) const OVERRIDE {
83     supported_message_classes->assign(
84         filter_->message_classes_to_filter().begin(),
85         filter_->message_classes_to_filter().end());
86     return true;
87   }
88 
89   // Dispatches a message to the derived class.
DispatchMessage(const IPC::Message & message)90   bool DispatchMessage(const IPC::Message& message) {
91     bool rv = filter_->OnMessageReceived(message);
92     DCHECK(BrowserThread::CurrentlyOn(BrowserThread::IO) || rv) <<
93         "Must handle messages that were dispatched to another thread!";
94     return rv;
95   }
96 
97   scoped_refptr<BrowserMessageFilter> filter_;
98 
99   DISALLOW_COPY_AND_ASSIGN(Internal);
100 };
101 
BrowserMessageFilter(uint32 message_class_to_filter)102 BrowserMessageFilter::BrowserMessageFilter(uint32 message_class_to_filter)
103     : internal_(NULL),
104       sender_(NULL),
105 #if defined(OS_WIN)
106       peer_handle_(base::kNullProcessHandle),
107 #endif
108       peer_pid_(base::kNullProcessId),
109       message_classes_to_filter_(1, message_class_to_filter) {}
110 
BrowserMessageFilter(const uint32 * message_classes_to_filter,size_t num_message_classes_to_filter)111 BrowserMessageFilter::BrowserMessageFilter(
112     const uint32* message_classes_to_filter,
113     size_t num_message_classes_to_filter)
114     : internal_(NULL),
115       sender_(NULL),
116 #if defined(OS_WIN)
117       peer_handle_(base::kNullProcessHandle),
118 #endif
119       peer_pid_(base::kNullProcessId),
120       message_classes_to_filter_(
121           message_classes_to_filter,
122           message_classes_to_filter + num_message_classes_to_filter) {
123   DCHECK(num_message_classes_to_filter);
124 }
125 
PeerHandle()126 base::ProcessHandle BrowserMessageFilter::PeerHandle() {
127 #if defined(OS_WIN)
128   base::AutoLock lock(peer_handle_lock_);
129   if (peer_handle_ == base::kNullProcessHandle)
130     base::OpenPrivilegedProcessHandle(peer_pid_, &peer_handle_);
131 
132   return peer_handle_;
133 #else
134   base::ProcessHandle result = base::kNullProcessHandle;
135   base::OpenPrivilegedProcessHandle(peer_pid_, &result);
136   return result;
137 #endif
138 }
139 
140 
OnDestruct() const141 void BrowserMessageFilter::OnDestruct() const {
142   delete this;
143 }
144 
Send(IPC::Message * message)145 bool BrowserMessageFilter::Send(IPC::Message* message) {
146   if (message->is_sync()) {
147     // We don't support sending synchronous messages from the browser.  If we
148     // really needed it, we can make this class derive from SyncMessageFilter
149     // but it seems better to not allow sending synchronous messages from the
150     // browser, since it might allow a corrupt/malicious renderer to hang us.
151     NOTREACHED() << "Can't send sync message through BrowserMessageFilter!";
152     return false;
153   }
154 
155   if (!BrowserThread::CurrentlyOn(BrowserThread::IO)) {
156     BrowserThread::PostTask(
157         BrowserThread::IO,
158         FROM_HERE,
159         base::Bind(base::IgnoreResult(&BrowserMessageFilter::Send), this,
160                    message));
161     return true;
162   }
163 
164   if (sender_)
165     return sender_->Send(message);
166 
167   delete message;
168   return false;
169 }
170 
OverrideTaskRunnerForMessage(const IPC::Message & message)171 base::TaskRunner* BrowserMessageFilter::OverrideTaskRunnerForMessage(
172     const IPC::Message& message) {
173   return NULL;
174 }
175 
CheckCanDispatchOnUI(const IPC::Message & message,IPC::Sender * sender)176 bool BrowserMessageFilter::CheckCanDispatchOnUI(const IPC::Message& message,
177                                                 IPC::Sender* sender) {
178 #if defined(OS_WIN)
179   // On Windows there's a potential deadlock with sync messsages going in
180   // a circle from browser -> plugin -> renderer -> browser.
181   // On Linux we can avoid this by avoiding sync messages from browser->plugin.
182   // On Mac we avoid this by not supporting windowed plugins.
183   if (message.is_sync() && !message.is_caller_pumping_messages()) {
184     // NOTE: IF YOU HIT THIS ASSERT, THE SOLUTION IS ALMOST NEVER TO RUN A
185     // NESTED MESSAGE LOOP IN THE RENDERER!!!
186     // That introduces reentrancy which causes hard to track bugs.  You should
187     // find a way to either turn this into an asynchronous message, or one
188     // that can be answered on the IO thread.
189     NOTREACHED() << "Can't send sync messages to UI thread without pumping "
190         "messages in the renderer or else deadlocks can occur if the page "
191         "has windowed plugins! (message type " << message.type() << ")";
192     IPC::Message* reply = IPC::SyncMessage::GenerateReply(&message);
193     reply->set_reply_error();
194     sender->Send(reply);
195     return false;
196   }
197 #endif
198   return true;
199 }
200 
BadMessageReceived()201 void BrowserMessageFilter::BadMessageReceived() {
202   CommandLine* command_line = CommandLine::ForCurrentProcess();
203   if (command_line->HasSwitch(switches::kDisableKillAfterBadIPC))
204     return;
205 
206   BrowserChildProcessHostImpl::HistogramBadMessageTerminated(
207       PROCESS_TYPE_RENDERER);
208   base::KillProcess(PeerHandle(), content::RESULT_CODE_KILLED_BAD_MESSAGE,
209                     false);
210 }
211 
~BrowserMessageFilter()212 BrowserMessageFilter::~BrowserMessageFilter() {
213 #if defined(OS_WIN)
214   if (peer_handle_ != base::kNullProcessHandle)
215     base::CloseProcessHandle(peer_handle_);
216 #endif
217 }
218 
GetFilter()219 IPC::MessageFilter* BrowserMessageFilter::GetFilter() {
220   // We create this on demand so that if a filter is used in a unit test but
221   // never attached to a channel, we don't leak Internal and this;
222   DCHECK(!internal_) << "Should only be called once.";
223   internal_ = new Internal(this);
224   return internal_;
225 }
226 
227 }  // namespace content
228