Home | History | Annotate | Download | only in pepper
      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