• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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 
CanRead(int process_id,const base::FilePath & path)30 bool CanRead(int process_id, const base::FilePath& path) {
31   return ChildProcessSecurityPolicyImpl::GetInstance()->CanReadFile(process_id,
32                                                                     path);
33 }
34 
CanCreateReadWrite(int process_id,const base::FilePath & path)35 bool CanCreateReadWrite(int process_id, const base::FilePath& path) {
36   return ChildProcessSecurityPolicyImpl::GetInstance()->CanCreateReadWriteFile(
37       process_id, path);
38 }
39 
40 }  // namespace
41 
PepperFlashFileMessageFilter(PP_Instance instance,BrowserPpapiHost * host)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 
~PepperFlashFileMessageFilter()63 PepperFlashFileMessageFilter::~PepperFlashFileMessageFilter() {}
64 
65 // static
GetDataDirName(const base::FilePath & profile_path)66 base::FilePath PepperFlashFileMessageFilter::GetDataDirName(
67     const base::FilePath& profile_path) {
68   return profile_path.Append(kPepperDataDirname);
69 }
70 
71 scoped_refptr<base::TaskRunner>
OverrideTaskRunnerForMessage(const IPC::Message & msg)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 
OnResourceMessageReceived(const IPC::Message & msg,ppapi::host::HostMessageContext * context)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 
OnOpenFile(ppapi::host::HostMessageContext * context,const ppapi::PepperFilePath & path,int pp_open_flags)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 
OnRenameFile(ppapi::host::HostMessageContext * context,const ppapi::PepperFilePath & from_path,const ppapi::PepperFilePath & to_path)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 
OnDeleteFileOrDir(ppapi::host::HostMessageContext * context,const ppapi::PepperFilePath & path,bool recursive)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 }
OnCreateDir(ppapi::host::HostMessageContext * context,const ppapi::PepperFilePath & path)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 
OnQueryFile(ppapi::host::HostMessageContext * context,const ppapi::PepperFilePath & path)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 
OnGetDirContents(ppapi::host::HostMessageContext * context,const ppapi::PepperFilePath & path)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 
OnCreateTemporaryFile(ppapi::host::HostMessageContext * context)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 
ValidateAndConvertPepperFilePath(const ppapi::PepperFilePath & pepper_path,const CheckPermissionsCallback & check_permissions_callback) const268 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