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/pepper_flash_file_message_filter.h" 6 7 #include "base/bind.h" 8 #include "base/files/file.h" 9 #include "base/files/file_enumerator.h" 10 #include "base/files/file_util.h" 11 #include "base/threading/sequenced_worker_pool.h" 12 #include "content/browser/child_process_security_policy_impl.h" 13 #include "content/browser/renderer_host/pepper/pepper_security_helper.h" 14 #include "content/public/browser/browser_ppapi_host.h" 15 #include "content/public/browser/browser_thread.h" 16 #include "content/public/common/content_constants.h" 17 #include "ipc/ipc_platform_file.h" 18 #include "ppapi/c/pp_errors.h" 19 #include "ppapi/host/dispatch_host_message.h" 20 #include "ppapi/host/host_message_context.h" 21 #include "ppapi/host/ppapi_host.h" 22 #include "ppapi/proxy/ppapi_messages.h" 23 #include "ppapi/shared_impl/file_path.h" 24 #include "ppapi/shared_impl/file_type_conversion.h" 25 26 namespace content { 27 28 namespace { 29 30 bool CanRead(int process_id, const base::FilePath& path) { 31 return ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(process_id, 32 path); 33 } 34 35 bool CanCreateReadWrite(int process_id, const base::FilePath& path) { 36 return ChildProcessSecurityPolicyImpl::GetInstance()->CanCreateReadWriteFile( 37 process_id, path); 38 } 39 40 } // namespace 41 42 PepperFlashFileMessageFilter::PepperFlashFileMessageFilter( 43 PP_Instance instance, 44 BrowserPpapiHost* host) 45 : plugin_process_handle_(host->GetPluginProcessHandle()) { 46 int unused; 47 host->GetRenderFrameIDsForInstance(instance, &render_process_id_, &unused); 48 base::FilePath profile_data_directory = host->GetProfileDataDirectory(); 49 std::string plugin_name = host->GetPluginName(); 50 51 if (profile_data_directory.empty() || plugin_name.empty()) { 52 // These are used to construct the path. If they are not set it means we 53 // will construct a bad path and could provide access to the wrong files. 54 // In this case, |plugin_data_directory_| will remain unset and 55 // |ValidateAndConvertPepperFilePath| will fail. 56 NOTREACHED(); 57 } else { 58 plugin_data_directory_ = GetDataDirName(profile_data_directory).Append( 59 base::FilePath::FromUTF8Unsafe(plugin_name)); 60 } 61 } 62 63 PepperFlashFileMessageFilter::~PepperFlashFileMessageFilter() {} 64 65 // static 66 base::FilePath PepperFlashFileMessageFilter::GetDataDirName( 67 const base::FilePath& profile_path) { 68 return profile_path.Append(kPepperDataDirname); 69 } 70 71 scoped_refptr<base::TaskRunner> 72 PepperFlashFileMessageFilter::OverrideTaskRunnerForMessage( 73 const IPC::Message& msg) { 74 // The blocking pool provides a pool of threads to run file 75 // operations, instead of a single thread which might require 76 // queuing time. Since these messages are synchronous as sent from 77 // the plugin, the sending thread cannot send a new message until 78 // this one returns, so there is no need to sequence tasks here. If 79 // the plugin has multiple threads, it cannot make assumptions about 80 // ordering of IPC message sends, so it cannot make assumptions 81 // about ordering of operations caused by those IPC messages. 82 return scoped_refptr<base::TaskRunner>(BrowserThread::GetBlockingPool()); 83 } 84 85 int32_t PepperFlashFileMessageFilter::OnResourceMessageReceived( 86 const IPC::Message& msg, 87 ppapi::host::HostMessageContext* context) { 88 PPAPI_BEGIN_MESSAGE_MAP(PepperFlashFileMessageFilter, msg) 89 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_OpenFile, 90 OnOpenFile) 91 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_RenameFile, 92 OnRenameFile) 93 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_DeleteFileOrDir, 94 OnDeleteFileOrDir) 95 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_CreateDir, 96 OnCreateDir) 97 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_QueryFile, 98 OnQueryFile) 99 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_GetDirContents, 100 OnGetDirContents) 101 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0( 102 PpapiHostMsg_FlashFile_CreateTemporaryFile, OnCreateTemporaryFile) 103 PPAPI_END_MESSAGE_MAP() 104 return PP_ERROR_FAILED; 105 } 106 107 int32_t PepperFlashFileMessageFilter::OnOpenFile( 108 ppapi::host::HostMessageContext* context, 109 const ppapi::PepperFilePath& path, 110 int pp_open_flags) { 111 base::FilePath full_path = ValidateAndConvertPepperFilePath( 112 path, base::Bind(&CanOpenWithPepperFlags, pp_open_flags)); 113 if (full_path.empty()) { 114 return ppapi::FileErrorToPepperError(base::File::FILE_ERROR_ACCESS_DENIED); 115 } 116 117 int platform_file_flags = 0; 118 if (!ppapi::PepperFileOpenFlagsToPlatformFileFlags(pp_open_flags, 119 &platform_file_flags)) { 120 return base::File::FILE_ERROR_FAILED; 121 } 122 123 base::File file(full_path, platform_file_flags); 124 if (!file.IsValid()) { 125 return ppapi::FileErrorToPepperError(file.error_details()); 126 } 127 128 // Make sure we didn't try to open a directory: directory fd shouldn't be 129 // passed to untrusted processes because they open security holes. 130 base::File::Info info; 131 if (!file.GetInfo(&info) || info.is_directory) { 132 // When in doubt, throw it out. 133 return ppapi::FileErrorToPepperError(base::File::FILE_ERROR_ACCESS_DENIED); 134 } 135 136 IPC::PlatformFileForTransit transit_file = 137 IPC::TakeFileHandleForProcess(file.Pass(), plugin_process_handle_); 138 ppapi::host::ReplyMessageContext reply_context = 139 context->MakeReplyMessageContext(); 140 reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle( 141 ppapi::proxy::SerializedHandle::FILE, transit_file)); 142 SendReply(reply_context, IPC::Message()); 143 return PP_OK_COMPLETIONPENDING; 144 } 145 146 int32_t PepperFlashFileMessageFilter::OnRenameFile( 147 ppapi::host::HostMessageContext* context, 148 const ppapi::PepperFilePath& from_path, 149 const ppapi::PepperFilePath& to_path) { 150 base::FilePath from_full_path = ValidateAndConvertPepperFilePath( 151 from_path, base::Bind(&CanCreateReadWrite)); 152 base::FilePath to_full_path = ValidateAndConvertPepperFilePath( 153 to_path, base::Bind(&CanCreateReadWrite)); 154 if (from_full_path.empty() || to_full_path.empty()) { 155 return ppapi::FileErrorToPepperError(base::File::FILE_ERROR_ACCESS_DENIED); 156 } 157 158 bool result = base::Move(from_full_path, to_full_path); 159 return ppapi::FileErrorToPepperError( 160 result ? base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED); 161 } 162 163 int32_t PepperFlashFileMessageFilter::OnDeleteFileOrDir( 164 ppapi::host::HostMessageContext* context, 165 const ppapi::PepperFilePath& path, 166 bool recursive) { 167 base::FilePath full_path = 168 ValidateAndConvertPepperFilePath(path, base::Bind(&CanCreateReadWrite)); 169 if (full_path.empty()) { 170 return ppapi::FileErrorToPepperError(base::File::FILE_ERROR_ACCESS_DENIED); 171 } 172 173 bool result = base::DeleteFile(full_path, recursive); 174 return ppapi::FileErrorToPepperError( 175 result ? base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED); 176 } 177 int32_t PepperFlashFileMessageFilter::OnCreateDir( 178 ppapi::host::HostMessageContext* context, 179 const ppapi::PepperFilePath& path) { 180 base::FilePath full_path = 181 ValidateAndConvertPepperFilePath(path, base::Bind(&CanCreateReadWrite)); 182 if (full_path.empty()) { 183 return ppapi::FileErrorToPepperError(base::File::FILE_ERROR_ACCESS_DENIED); 184 } 185 186 bool result = base::CreateDirectory(full_path); 187 return ppapi::FileErrorToPepperError( 188 result ? base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED); 189 } 190 191 int32_t PepperFlashFileMessageFilter::OnQueryFile( 192 ppapi::host::HostMessageContext* context, 193 const ppapi::PepperFilePath& path) { 194 base::FilePath full_path = 195 ValidateAndConvertPepperFilePath(path, base::Bind(&CanRead)); 196 if (full_path.empty()) { 197 return ppapi::FileErrorToPepperError(base::File::FILE_ERROR_ACCESS_DENIED); 198 } 199 200 base::File::Info info; 201 bool result = base::GetFileInfo(full_path, &info); 202 context->reply_msg = PpapiPluginMsg_FlashFile_QueryFileReply(info); 203 return ppapi::FileErrorToPepperError( 204 result ? base::File::FILE_OK : base::File::FILE_ERROR_ACCESS_DENIED); 205 } 206 207 int32_t PepperFlashFileMessageFilter::OnGetDirContents( 208 ppapi::host::HostMessageContext* context, 209 const ppapi::PepperFilePath& path) { 210 base::FilePath full_path = 211 ValidateAndConvertPepperFilePath(path, base::Bind(&CanRead)); 212 if (full_path.empty()) { 213 return ppapi::FileErrorToPepperError(base::File::FILE_ERROR_ACCESS_DENIED); 214 } 215 216 ppapi::DirContents contents; 217 base::FileEnumerator enumerator(full_path, 218 false, 219 base::FileEnumerator::FILES | 220 base::FileEnumerator::DIRECTORIES | 221 base::FileEnumerator::INCLUDE_DOT_DOT); 222 223 while (!enumerator.Next().empty()) { 224 base::FileEnumerator::FileInfo info = enumerator.GetInfo(); 225 ppapi::DirEntry entry = {info.GetName(), info.IsDirectory()}; 226 contents.push_back(entry); 227 } 228 229 context->reply_msg = PpapiPluginMsg_FlashFile_GetDirContentsReply(contents); 230 return PP_OK; 231 } 232 233 int32_t PepperFlashFileMessageFilter::OnCreateTemporaryFile( 234 ppapi::host::HostMessageContext* context) { 235 ppapi::PepperFilePath dir_path(ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL, 236 base::FilePath()); 237 base::FilePath validated_dir_path = ValidateAndConvertPepperFilePath( 238 dir_path, base::Bind(&CanCreateReadWrite)); 239 if (validated_dir_path.empty() || 240 (!base::DirectoryExists(validated_dir_path) && 241 !base::CreateDirectory(validated_dir_path))) { 242 return ppapi::FileErrorToPepperError(base::File::FILE_ERROR_ACCESS_DENIED); 243 } 244 245 base::FilePath file_path; 246 if (!base::CreateTemporaryFileInDir(validated_dir_path, &file_path)) { 247 return ppapi::FileErrorToPepperError(base::File::FILE_ERROR_FAILED); 248 } 249 250 base::File file(file_path, 251 base::File::FLAG_CREATE_ALWAYS | base::File::FLAG_READ | 252 base::File::FLAG_WRITE | base::File::FLAG_TEMPORARY | 253 base::File::FLAG_DELETE_ON_CLOSE); 254 255 if (!file.IsValid()) 256 return ppapi::FileErrorToPepperError(file.error_details()); 257 258 IPC::PlatformFileForTransit transit_file = 259 IPC::TakeFileHandleForProcess(file.Pass(), plugin_process_handle_); 260 ppapi::host::ReplyMessageContext reply_context = 261 context->MakeReplyMessageContext(); 262 reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle( 263 ppapi::proxy::SerializedHandle::FILE, transit_file)); 264 SendReply(reply_context, IPC::Message()); 265 return PP_OK_COMPLETIONPENDING; 266 } 267 268 base::FilePath PepperFlashFileMessageFilter::ValidateAndConvertPepperFilePath( 269 const ppapi::PepperFilePath& pepper_path, 270 const CheckPermissionsCallback& check_permissions_callback) const { 271 base::FilePath file_path; // Empty path returned on error. 272 switch (pepper_path.domain()) { 273 case ppapi::PepperFilePath::DOMAIN_ABSOLUTE: 274 if (pepper_path.path().IsAbsolute() && 275 check_permissions_callback.Run(render_process_id_, 276 pepper_path.path())) 277 file_path = pepper_path.path(); 278 break; 279 case ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL: 280 // This filter provides the module name portion of the path to prevent 281 // plugins from accessing each other's data. 282 if (!plugin_data_directory_.empty() && !pepper_path.path().IsAbsolute() && 283 !pepper_path.path().ReferencesParent()) 284 file_path = plugin_data_directory_.Append(pepper_path.path()); 285 break; 286 default: 287 NOTREACHED(); 288 break; 289 } 290 return file_path; 291 } 292 293 } // namespace content 294