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