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/browser/renderer_host/pepper/browser_ppapi_host_impl.h"
6 
7 #include "base/metrics/histogram_functions.h"
8 #include "content/browser/renderer_host/pepper/pepper_message_filter.h"
9 #include "content/common/pepper_renderer_instance_data.h"
10 #include "content/public/common/process_type.h"
11 #include "ipc/ipc_message_macros.h"
12 #include "ppapi/proxy/ppapi_messages.h"
13 
14 namespace content {
15 
16 // static
CreateExternalPluginProcess(IPC::Sender * sender,ppapi::PpapiPermissions permissions,base::ProcessHandle plugin_child_process,IPC::ChannelProxy * channel,int render_process_id,int render_view_id,const base::FilePath & profile_directory)17 BrowserPpapiHost* BrowserPpapiHost::CreateExternalPluginProcess(
18     IPC::Sender* sender,
19     ppapi::PpapiPermissions permissions,
20     base::ProcessHandle plugin_child_process,
21     IPC::ChannelProxy* channel,
22     int render_process_id,
23     int render_view_id,
24     const base::FilePath& profile_directory) {
25   // The plugin name and path shouldn't be needed for external plugins.
26   BrowserPpapiHostImpl* browser_ppapi_host =
27       new BrowserPpapiHostImpl(sender,
28                                permissions,
29                                std::string(),
30                                base::FilePath(),
31                                profile_directory,
32                                false /* in_process */,
33                                true /* external_plugin */);
34   browser_ppapi_host->set_plugin_process(
35       base::Process::DeprecatedGetProcessFromHandle(plugin_child_process));
36 
37   scoped_refptr<PepperMessageFilter> pepper_message_filter(
38       new PepperMessageFilter());
39   channel->AddFilter(pepper_message_filter->GetFilter());
40   channel->AddFilter(browser_ppapi_host->message_filter().get());
41 
42   return browser_ppapi_host;
43 }
44 
BrowserPpapiHostImpl(IPC::Sender * sender,const ppapi::PpapiPermissions & permissions,const std::string & plugin_name,const base::FilePath & plugin_path,const base::FilePath & profile_data_directory,bool in_process,bool external_plugin)45 BrowserPpapiHostImpl::BrowserPpapiHostImpl(
46     IPC::Sender* sender,
47     const ppapi::PpapiPermissions& permissions,
48     const std::string& plugin_name,
49     const base::FilePath& plugin_path,
50     const base::FilePath& profile_data_directory,
51     bool in_process,
52     bool external_plugin)
53     : ppapi_host_(new ppapi::host::PpapiHost(sender, permissions)),
54       plugin_name_(plugin_name),
55       plugin_path_(plugin_path),
56       profile_data_directory_(profile_data_directory),
57       in_process_(in_process),
58       external_plugin_(external_plugin) {
59   message_filter_ = new HostMessageFilter(ppapi_host_.get(), this);
60   ppapi_host_->AddHostFactoryFilter(std::unique_ptr<ppapi::host::HostFactory>(
61       new ContentBrowserPepperHostFactory(this)));
62 }
63 
~BrowserPpapiHostImpl()64 BrowserPpapiHostImpl::~BrowserPpapiHostImpl() {
65   // Notify the filter so it won't foward messages to us.
66   message_filter_->OnHostDestroyed();
67 
68   // Notify instance observers about our impending destruction.
69   for (auto& instance_data : instance_map_) {
70     for (auto& observer : instance_data.second->observer_list)
71       observer.OnHostDestroyed();
72   }
73 
74   // Delete the host explicitly first. This shutdown will destroy the
75   // resources, which may want to do cleanup in their destructors and expect
76   // their pointers to us to be valid.
77   ppapi_host_.reset();
78 }
79 
GetPpapiHost()80 ppapi::host::PpapiHost* BrowserPpapiHostImpl::GetPpapiHost() {
81   return ppapi_host_.get();
82 }
83 
GetPluginProcess()84 const base::Process& BrowserPpapiHostImpl::GetPluginProcess() {
85   // Handle should previously have been set before use.
86   DCHECK(in_process_ || plugin_process_.IsValid());
87   return plugin_process_;
88 }
89 
IsValidInstance(PP_Instance instance)90 bool BrowserPpapiHostImpl::IsValidInstance(PP_Instance instance) {
91   return instance_map_.find(instance) != instance_map_.end();
92 }
93 
GetRenderFrameIDsForInstance(PP_Instance instance,int * render_process_id,int * render_frame_id)94 bool BrowserPpapiHostImpl::GetRenderFrameIDsForInstance(PP_Instance instance,
95                                                         int* render_process_id,
96                                                         int* render_frame_id) {
97   auto it = instance_map_.find(instance);
98   if (it == instance_map_.end()) {
99     *render_process_id = 0;
100     *render_frame_id = 0;
101     return false;
102   }
103 
104   *render_process_id = it->second->renderer_data.render_process_id;
105   *render_frame_id = it->second->renderer_data.render_frame_id;
106   return true;
107 }
108 
GetPluginName()109 const std::string& BrowserPpapiHostImpl::GetPluginName() {
110   return plugin_name_;
111 }
112 
GetPluginPath()113 const base::FilePath& BrowserPpapiHostImpl::GetPluginPath() {
114   return plugin_path_;
115 }
116 
GetProfileDataDirectory()117 const base::FilePath& BrowserPpapiHostImpl::GetProfileDataDirectory() {
118   return profile_data_directory_;
119 }
120 
GetDocumentURLForInstance(PP_Instance instance)121 GURL BrowserPpapiHostImpl::GetDocumentURLForInstance(PP_Instance instance) {
122   auto it = instance_map_.find(instance);
123   if (it == instance_map_.end())
124     return GURL();
125   return it->second->renderer_data.document_url;
126 }
127 
GetPluginURLForInstance(PP_Instance instance)128 GURL BrowserPpapiHostImpl::GetPluginURLForInstance(PP_Instance instance) {
129   auto it = instance_map_.find(instance);
130   if (it == instance_map_.end())
131     return GURL();
132   return it->second->renderer_data.plugin_url;
133 }
134 
IsPotentiallySecurePluginContext(PP_Instance instance)135 bool BrowserPpapiHostImpl::IsPotentiallySecurePluginContext(
136     PP_Instance instance) {
137   auto it = instance_map_.find(instance);
138   if (it == instance_map_.end())
139     return false;
140   return it->second->renderer_data.is_potentially_secure_plugin_context;
141 }
142 
AddInstance(PP_Instance instance,const PepperRendererInstanceData & renderer_instance_data)143 void BrowserPpapiHostImpl::AddInstance(
144     PP_Instance instance,
145     const PepperRendererInstanceData& renderer_instance_data) {
146   // NOTE: 'instance' may be coming from a compromised renderer process. We
147   // take care here to make sure an attacker can't overwrite data for an
148   // existing plugin instance.
149   // See http://crbug.com/733548.
150   if (instance_map_.find(instance) == instance_map_.end()) {
151     instance_map_[instance] =
152         std::make_unique<InstanceData>(renderer_instance_data);
153   } else {
154     NOTREACHED();
155   }
156 }
157 
DeleteInstance(PP_Instance instance)158 void BrowserPpapiHostImpl::DeleteInstance(PP_Instance instance) {
159   // NOTE: 'instance' may be coming from a compromised renderer process. We
160   // take care here to make sure an attacker can't cause a UAF by deleting a
161   // non-existent plugin instance.
162   // See http://crbug.com/733548.
163   auto it = instance_map_.find(instance);
164   if (it != instance_map_.end()) {
165     // We need to tell the observers for that instance that we are destroyed
166     // because we won't have the opportunity to once we remove them from the
167     // |instance_map_|. If the instance was deleted, observers for those
168     // instances should never call back into the host anyway, so it is safe to
169     // tell them that the host is destroyed.
170     for (auto& observer : it->second->observer_list)
171       observer.OnHostDestroyed();
172 
173     instance_map_.erase(it);
174   } else {
175     NOTREACHED();
176   }
177 }
178 
AddInstanceObserver(PP_Instance instance,InstanceObserver * observer)179 void BrowserPpapiHostImpl::AddInstanceObserver(PP_Instance instance,
180                                                InstanceObserver* observer) {
181   instance_map_[instance]->observer_list.AddObserver(observer);
182 }
183 
RemoveInstanceObserver(PP_Instance instance,InstanceObserver * observer)184 void BrowserPpapiHostImpl::RemoveInstanceObserver(PP_Instance instance,
185                                                   InstanceObserver* observer) {
186   auto it = instance_map_.find(instance);
187   if (it != instance_map_.end())
188     it->second->observer_list.RemoveObserver(observer);
189 }
190 
OnThrottleStateChanged(PP_Instance instance,bool is_throttled)191 void BrowserPpapiHostImpl::OnThrottleStateChanged(PP_Instance instance,
192                                                   bool is_throttled) {
193   auto it = instance_map_.find(instance);
194   if (it != instance_map_.end()) {
195     it->second->is_throttled = is_throttled;
196     for (auto& observer : it->second->observer_list)
197       observer.OnThrottleStateChanged(is_throttled);
198   }
199 }
200 
IsThrottled(PP_Instance instance) const201 bool BrowserPpapiHostImpl::IsThrottled(PP_Instance instance) const {
202   auto it = instance_map_.find(instance);
203   if (it != instance_map_.end())
204     return it->second->is_throttled;
205 
206   return false;
207 }
208 
HostMessageFilter(ppapi::host::PpapiHost * ppapi_host,BrowserPpapiHostImpl * browser_ppapi_host_impl)209 BrowserPpapiHostImpl::HostMessageFilter::HostMessageFilter(
210     ppapi::host::PpapiHost* ppapi_host,
211     BrowserPpapiHostImpl* browser_ppapi_host_impl)
212     : ppapi_host_(ppapi_host),
213       browser_ppapi_host_impl_(browser_ppapi_host_impl) {}
214 
OnMessageReceived(const IPC::Message & msg)215 bool BrowserPpapiHostImpl::HostMessageFilter::OnMessageReceived(
216     const IPC::Message& msg) {
217   // Don't forward messages if our owner object has been destroyed.
218   if (!ppapi_host_)
219     return false;
220 
221   bool handled = true;
222   IPC_BEGIN_MESSAGE_MAP(BrowserPpapiHostImpl::HostMessageFilter, msg)
223   // Add necessary message handlers here.
224   IPC_MESSAGE_HANDLER(PpapiHostMsg_LogInterfaceUsage,
225                       OnHostMsgLogInterfaceUsage)
226   IPC_MESSAGE_UNHANDLED(handled = ppapi_host_->OnMessageReceived(msg))
227   IPC_END_MESSAGE_MAP()
228   return handled;
229 }
230 
OnHostDestroyed()231 void BrowserPpapiHostImpl::HostMessageFilter::OnHostDestroyed() {
232   DCHECK(ppapi_host_);
233   ppapi_host_ = nullptr;
234   browser_ppapi_host_impl_ = nullptr;
235 }
236 
~HostMessageFilter()237 BrowserPpapiHostImpl::HostMessageFilter::~HostMessageFilter() {}
238 
OnHostMsgLogInterfaceUsage(int hash) const239 void BrowserPpapiHostImpl::HostMessageFilter::OnHostMsgLogInterfaceUsage(
240     int hash) const {
241   base::UmaHistogramSparse("Pepper.InterfaceUsed", hash);
242 }
243 
InstanceData(const PepperRendererInstanceData & renderer_data)244 BrowserPpapiHostImpl::InstanceData::InstanceData(
245     const PepperRendererInstanceData& renderer_data)
246     : renderer_data(renderer_data), is_throttled(false) {
247 }
248 
~InstanceData()249 BrowserPpapiHostImpl::InstanceData::~InstanceData() {
250 }
251 
252 }  // namespace content
253