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