Home | History | Annotate | Download | only in pepper
      1 // Copyright 2013 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 "chrome/browser/renderer_host/pepper/pepper_isolated_file_system_message_filter.h"
      6 
      7 #include "chrome/browser/browser_process.h"
      8 #include "chrome/browser/extensions/extension_service.h"
      9 #include "chrome/browser/profiles/profile.h"
     10 #include "chrome/browser/profiles/profile_manager.h"
     11 #include "chrome/common/chrome_switches.h"
     12 #include "chrome/common/pepper_permission_util.h"
     13 #include "content/public/browser/browser_ppapi_host.h"
     14 #include "content/public/browser/browser_thread.h"
     15 #include "content/public/browser/child_process_security_policy.h"
     16 #include "content/public/browser/render_view_host.h"
     17 #include "extensions/browser/extension_system.h"
     18 #include "extensions/common/constants.h"
     19 #include "extensions/common/extension.h"
     20 #include "extensions/common/extension_set.h"
     21 #include "ppapi/c/pp_errors.h"
     22 #include "ppapi/host/dispatch_host_message.h"
     23 #include "ppapi/host/host_message_context.h"
     24 #include "ppapi/host/ppapi_host.h"
     25 #include "ppapi/proxy/ppapi_messages.h"
     26 #include "ppapi/shared_impl/file_system_util.h"
     27 #include "webkit/browser/fileapi/isolated_context.h"
     28 
     29 namespace chrome {
     30 
     31 namespace {
     32 
     33 const char* kPredefinedAllowedCrxFsOrigins[] = {
     34     "6EAED1924DB611B6EEF2A664BD077BE7EAD33B8F",  // see crbug.com/234789
     35     "4EB74897CB187C7633357C2FE832E0AD6A44883A"   // see crbug.com/234789
     36 };
     37 
     38 }  // namespace
     39 
     40 // static
     41 PepperIsolatedFileSystemMessageFilter*
     42 PepperIsolatedFileSystemMessageFilter::Create(PP_Instance instance,
     43                                               content::BrowserPpapiHost* host) {
     44   int render_process_id;
     45   int unused_render_frame_id;
     46   if (!host->GetRenderFrameIDsForInstance(
     47           instance, &render_process_id, &unused_render_frame_id)) {
     48     return NULL;
     49   }
     50   return new PepperIsolatedFileSystemMessageFilter(
     51       render_process_id,
     52       host->GetProfileDataDirectory(),
     53       host->GetDocumentURLForInstance(instance),
     54       host->GetPpapiHost());
     55 }
     56 
     57 PepperIsolatedFileSystemMessageFilter::PepperIsolatedFileSystemMessageFilter(
     58     int render_process_id,
     59     const base::FilePath& profile_directory,
     60     const GURL& document_url,
     61     ppapi::host::PpapiHost* ppapi_host)
     62     : render_process_id_(render_process_id),
     63       profile_directory_(profile_directory),
     64       document_url_(document_url),
     65       ppapi_host_(ppapi_host) {
     66   for (size_t i = 0; i < arraysize(kPredefinedAllowedCrxFsOrigins); ++i)
     67     allowed_crxfs_origins_.insert(kPredefinedAllowedCrxFsOrigins[i]);
     68 }
     69 
     70 PepperIsolatedFileSystemMessageFilter::
     71     ~PepperIsolatedFileSystemMessageFilter() {}
     72 
     73 scoped_refptr<base::TaskRunner>
     74 PepperIsolatedFileSystemMessageFilter::OverrideTaskRunnerForMessage(
     75     const IPC::Message& msg) {
     76   // In order to reach ExtensionSystem, we need to get ProfileManager first.
     77   // ProfileManager lives in UI thread, so we need to do this in UI thread.
     78   return content::BrowserThread::GetMessageLoopProxyForThread(
     79       content::BrowserThread::UI);
     80 }
     81 
     82 int32_t PepperIsolatedFileSystemMessageFilter::OnResourceMessageReceived(
     83     const IPC::Message& msg,
     84     ppapi::host::HostMessageContext* context) {
     85   PPAPI_BEGIN_MESSAGE_MAP(PepperIsolatedFileSystemMessageFilter, msg)
     86     PPAPI_DISPATCH_HOST_RESOURCE_CALL(
     87       PpapiHostMsg_IsolatedFileSystem_BrowserOpen,
     88       OnOpenFileSystem)
     89   PPAPI_END_MESSAGE_MAP()
     90   return PP_ERROR_FAILED;
     91 }
     92 
     93 Profile* PepperIsolatedFileSystemMessageFilter::GetProfile() {
     94   DCHECK(content::BrowserThread::CurrentlyOn(content::BrowserThread::UI));
     95   ProfileManager* profile_manager = g_browser_process->profile_manager();
     96   return profile_manager->GetProfile(profile_directory_);
     97 }
     98 
     99 std::string PepperIsolatedFileSystemMessageFilter::CreateCrxFileSystem(
    100     Profile* profile) {
    101   extensions::ExtensionSystem* extension_system =
    102       extensions::ExtensionSystem::Get(profile);
    103   if (!extension_system)
    104     return std::string();
    105 
    106   const ExtensionService* extension_service =
    107       extension_system->extension_service();
    108   if (!extension_service)
    109     return std::string();
    110 
    111   const extensions::Extension* extension =
    112       extension_service->GetExtensionById(document_url_.host(), false);
    113   if (!extension)
    114     return std::string();
    115 
    116   // First level directory for isolated filesystem to lookup.
    117   std::string kFirstLevelDirectory("crxfs");
    118   return fileapi::IsolatedContext::GetInstance()->RegisterFileSystemForPath(
    119       fileapi::kFileSystemTypeNativeLocal,
    120       std::string(),
    121       extension->path(),
    122       &kFirstLevelDirectory);
    123 }
    124 
    125 int32_t PepperIsolatedFileSystemMessageFilter::OnOpenFileSystem(
    126     ppapi::host::HostMessageContext* context,
    127     PP_IsolatedFileSystemType_Private type) {
    128   switch (type) {
    129     case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_INVALID:
    130       break;
    131     case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_CRX:
    132       return OpenCrxFileSystem(context);
    133     case PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE:
    134       return OpenPluginPrivateFileSystem(context);
    135   }
    136   NOTREACHED();
    137   context->reply_msg =
    138       PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(std::string());
    139   return PP_ERROR_FAILED;
    140 }
    141 
    142 int32_t PepperIsolatedFileSystemMessageFilter::OpenCrxFileSystem(
    143     ppapi::host::HostMessageContext* context) {
    144   Profile* profile = GetProfile();
    145   const extensions::ExtensionSet* extension_set = NULL;
    146   if (profile) {
    147     extension_set = extensions::ExtensionSystem::Get(profile)
    148                         ->extension_service()
    149                         ->extensions();
    150   }
    151   if (!IsExtensionOrSharedModuleWhitelisted(
    152           document_url_, extension_set, allowed_crxfs_origins_) &&
    153       !IsHostAllowedByCommandLine(
    154           document_url_, extension_set, switches::kAllowNaClCrxFsAPI)) {
    155     LOG(ERROR) << "Host " << document_url_.host() << " cannot use CrxFs API.";
    156     return PP_ERROR_NOACCESS;
    157   }
    158 
    159   // TODO(raymes): When we remove FileSystem from the renderer, we should create
    160   // a pending PepperFileSystemBrowserHost here with the fsid and send the
    161   // pending host ID back to the plugin.
    162   const std::string fsid = CreateCrxFileSystem(profile);
    163   if (fsid.empty()) {
    164     context->reply_msg =
    165         PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(std::string());
    166     return PP_ERROR_NOTSUPPORTED;
    167   }
    168 
    169   // Grant readonly access of isolated filesystem to renderer process.
    170   content::ChildProcessSecurityPolicy* policy =
    171       content::ChildProcessSecurityPolicy::GetInstance();
    172   policy->GrantReadFileSystem(render_process_id_, fsid);
    173 
    174   context->reply_msg = PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(fsid);
    175   return PP_OK;
    176 }
    177 
    178 int32_t PepperIsolatedFileSystemMessageFilter::OpenPluginPrivateFileSystem(
    179     ppapi::host::HostMessageContext* context) {
    180   DCHECK(ppapi_host_);
    181   // Only plugins with private permission can open the filesystem.
    182   if (!ppapi_host_->permissions().HasPermission(ppapi::PERMISSION_PRIVATE))
    183     return PP_ERROR_NOACCESS;
    184 
    185   const std::string& root_name = ppapi::IsolatedFileSystemTypeToRootName(
    186       PP_ISOLATEDFILESYSTEMTYPE_PRIVATE_PLUGINPRIVATE);
    187   const std::string& fsid =
    188       fileapi::IsolatedContext::GetInstance()->RegisterFileSystemForVirtualPath(
    189           fileapi::kFileSystemTypePluginPrivate, root_name, base::FilePath());
    190 
    191   // Grant full access of isolated filesystem to renderer process.
    192   content::ChildProcessSecurityPolicy* policy =
    193       content::ChildProcessSecurityPolicy::GetInstance();
    194   policy->GrantCreateReadWriteFileSystem(render_process_id_, fsid);
    195 
    196   context->reply_msg = PpapiPluginMsg_IsolatedFileSystem_BrowserOpenReply(fsid);
    197   return PP_OK;
    198 }
    199 
    200 }  // namespace chrome
    201