|  | // Copyright 2012 The Chromium Authors | 
|  | // Use of this source code is governed by a BSD-style license that can be | 
|  | // found in the LICENSE file. | 
|  |  | 
|  | #include "content/browser/renderer_host/pepper/browser_ppapi_host_impl.h" | 
|  |  | 
|  | #include "base/observer_list.h" | 
|  | #include "content/common/pepper_renderer_instance_data.h" | 
|  | #include "content/public/common/process_type.h" | 
|  | #include "ipc/ipc_message_macros.h" | 
|  | #include "ppapi/proxy/ppapi_messages.h" | 
|  |  | 
|  | namespace content { | 
|  |  | 
|  | // static | 
|  | BrowserPpapiHost* BrowserPpapiHost::CreateExternalPluginProcess( | 
|  | IPC::Sender* sender, | 
|  | ppapi::PpapiPermissions permissions, | 
|  | base::Process plugin_child_process, | 
|  | IPC::ChannelProxy* channel, | 
|  | const base::FilePath& profile_directory) { | 
|  | // The plugin name and path shouldn't be needed for external plugins. | 
|  | BrowserPpapiHostImpl* browser_ppapi_host = | 
|  | new BrowserPpapiHostImpl(sender, | 
|  | permissions, | 
|  | std::string(), | 
|  | base::FilePath(), | 
|  | profile_directory, | 
|  | false /* in_process */, | 
|  | true /* external_plugin */); | 
|  | browser_ppapi_host->set_plugin_process(std::move(plugin_child_process)); | 
|  | channel->AddFilter(browser_ppapi_host->message_filter().get()); | 
|  |  | 
|  | return browser_ppapi_host; | 
|  | } | 
|  |  | 
|  | BrowserPpapiHostImpl::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) | 
|  | : ppapi_host_(new ppapi::host::PpapiHost(sender, permissions)), | 
|  | plugin_name_(plugin_name), | 
|  | plugin_path_(plugin_path), | 
|  | profile_data_directory_(profile_data_directory), | 
|  | in_process_(in_process), | 
|  | external_plugin_(external_plugin) { | 
|  | message_filter_ = new HostMessageFilter(ppapi_host_.get(), this); | 
|  | ppapi_host_->AddHostFactoryFilter(std::unique_ptr<ppapi::host::HostFactory>( | 
|  | new ContentBrowserPepperHostFactory(this))); | 
|  | } | 
|  |  | 
|  | BrowserPpapiHostImpl::~BrowserPpapiHostImpl() { | 
|  | // Notify the filter so it won't foward messages to us. | 
|  | message_filter_->OnHostDestroyed(); | 
|  |  | 
|  | // Notify instance observers about our impending destruction. | 
|  | for (auto& instance_data : instance_map_) { | 
|  | for (auto& observer : instance_data.second->observer_list) | 
|  | observer.OnHostDestroyed(); | 
|  | } | 
|  |  | 
|  | // Delete the host explicitly first. This shutdown will destroy the | 
|  | // resources, which may want to do cleanup in their destructors and expect | 
|  | // their pointers to us to be valid. | 
|  | ppapi_host_.reset(); | 
|  | } | 
|  |  | 
|  | ppapi::host::PpapiHost* BrowserPpapiHostImpl::GetPpapiHost() { | 
|  | return ppapi_host_.get(); | 
|  | } | 
|  |  | 
|  | const base::Process& BrowserPpapiHostImpl::GetPluginProcess() { | 
|  | // Handle should previously have been set before use. | 
|  | DCHECK(in_process_ || plugin_process_.IsValid()); | 
|  | return plugin_process_; | 
|  | } | 
|  |  | 
|  | bool BrowserPpapiHostImpl::IsValidInstance(PP_Instance instance) { | 
|  | return instance_map_.find(instance) != instance_map_.end(); | 
|  | } | 
|  |  | 
|  | bool BrowserPpapiHostImpl::GetRenderFrameIDsForInstance(PP_Instance instance, | 
|  | int* render_process_id, | 
|  | int* render_frame_id) { | 
|  | auto it = instance_map_.find(instance); | 
|  | if (it == instance_map_.end()) { | 
|  | *render_process_id = 0; | 
|  | *render_frame_id = 0; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | *render_process_id = it->second->renderer_data.render_process_id; | 
|  | *render_frame_id = it->second->renderer_data.render_frame_id; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | const std::string& BrowserPpapiHostImpl::GetPluginName() { | 
|  | return plugin_name_; | 
|  | } | 
|  |  | 
|  | const base::FilePath& BrowserPpapiHostImpl::GetPluginPath() { | 
|  | return plugin_path_; | 
|  | } | 
|  |  | 
|  | const base::FilePath& BrowserPpapiHostImpl::GetProfileDataDirectory() { | 
|  | return profile_data_directory_; | 
|  | } | 
|  |  | 
|  | GURL BrowserPpapiHostImpl::GetDocumentURLForInstance(PP_Instance instance) { | 
|  | auto it = instance_map_.find(instance); | 
|  | if (it == instance_map_.end()) | 
|  | return GURL(); | 
|  | return it->second->renderer_data.document_url; | 
|  | } | 
|  |  | 
|  | GURL BrowserPpapiHostImpl::GetPluginURLForInstance(PP_Instance instance) { | 
|  | auto it = instance_map_.find(instance); | 
|  | if (it == instance_map_.end()) | 
|  | return GURL(); | 
|  | return it->second->renderer_data.plugin_url; | 
|  | } | 
|  |  | 
|  | bool BrowserPpapiHostImpl::IsPotentiallySecurePluginContext( | 
|  | PP_Instance instance) { | 
|  | auto it = instance_map_.find(instance); | 
|  | if (it == instance_map_.end()) | 
|  | return false; | 
|  | return it->second->renderer_data.is_potentially_secure_plugin_context; | 
|  | } | 
|  |  | 
|  | void BrowserPpapiHostImpl::AddInstance( | 
|  | PP_Instance instance, | 
|  | const PepperRendererInstanceData& renderer_instance_data) { | 
|  | // NOTE: 'instance' may be coming from a compromised renderer process. We | 
|  | // take care here to make sure an attacker can't overwrite data for an | 
|  | // existing plugin instance. | 
|  | // See http://crbug.com/733548. | 
|  | if (instance_map_.find(instance) == instance_map_.end()) { | 
|  | instance_map_[instance] = | 
|  | std::make_unique<InstanceData>(renderer_instance_data); | 
|  | } else { | 
|  | NOTREACHED(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void BrowserPpapiHostImpl::DeleteInstance(PP_Instance instance) { | 
|  | // NOTE: 'instance' may be coming from a compromised renderer process. We | 
|  | // take care here to make sure an attacker can't cause a UAF by deleting a | 
|  | // non-existent plugin instance. | 
|  | // See http://crbug.com/733548. | 
|  | auto it = instance_map_.find(instance); | 
|  | if (it != instance_map_.end()) { | 
|  | // We need to tell the observers for that instance that we are destroyed | 
|  | // because we won't have the opportunity to once we remove them from the | 
|  | // |instance_map_|. If the instance was deleted, observers for those | 
|  | // instances should never call back into the host anyway, so it is safe to | 
|  | // tell them that the host is destroyed. | 
|  | for (auto& observer : it->second->observer_list) | 
|  | observer.OnHostDestroyed(); | 
|  |  | 
|  | instance_map_.erase(it); | 
|  | } else { | 
|  | NOTREACHED(); | 
|  | } | 
|  | } | 
|  |  | 
|  | void BrowserPpapiHostImpl::AddInstanceObserver(PP_Instance instance, | 
|  | InstanceObserver* observer) { | 
|  | instance_map_[instance]->observer_list.AddObserver(observer); | 
|  | } | 
|  |  | 
|  | void BrowserPpapiHostImpl::RemoveInstanceObserver(PP_Instance instance, | 
|  | InstanceObserver* observer) { | 
|  | auto it = instance_map_.find(instance); | 
|  | if (it != instance_map_.end()) | 
|  | it->second->observer_list.RemoveObserver(observer); | 
|  | } | 
|  |  | 
|  | BrowserPpapiHostImpl::HostMessageFilter::HostMessageFilter( | 
|  | ppapi::host::PpapiHost* ppapi_host, | 
|  | BrowserPpapiHostImpl* browser_ppapi_host_impl) | 
|  | : ppapi_host_(ppapi_host), | 
|  | browser_ppapi_host_impl_(browser_ppapi_host_impl) {} | 
|  |  | 
|  | bool BrowserPpapiHostImpl::HostMessageFilter::OnMessageReceived( | 
|  | const IPC::Message& msg) { | 
|  | // Don't forward messages if our owner object has been destroyed. | 
|  | if (!ppapi_host_) | 
|  | return false; | 
|  |  | 
|  | return ppapi_host_->OnMessageReceived(msg); | 
|  | } | 
|  |  | 
|  | void BrowserPpapiHostImpl::HostMessageFilter::OnHostDestroyed() { | 
|  | DCHECK(ppapi_host_); | 
|  | ppapi_host_ = nullptr; | 
|  | browser_ppapi_host_impl_ = nullptr; | 
|  | } | 
|  |  | 
|  | BrowserPpapiHostImpl::HostMessageFilter::~HostMessageFilter() {} | 
|  |  | 
|  | BrowserPpapiHostImpl::InstanceData::InstanceData( | 
|  | const PepperRendererInstanceData& renderer_data) | 
|  | : renderer_data(renderer_data) {} | 
|  |  | 
|  | BrowserPpapiHostImpl::InstanceData::~InstanceData() { | 
|  | } | 
|  |  | 
|  | }  // namespace content |