Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(573)

Side by Side Diff: content/browser/renderer_host/pepper/pepper_flash_file_host.cc

Issue 11359097: Refactored the PPB_Flash_File_ModuleLocal/FileRef to the new ppapi resource model (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: . Created 8 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
OLDNEW
(Empty)
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_host.h"
6
7 #include "base/bind.h"
8 #include "base/file_util.h"
9 #include "base/task_runner.h"
10 #include "base/threading/sequenced_worker_pool.h"
11 #include "content/browser/child_process_security_policy_impl.h"
12 #include "content/public/browser/browser_ppapi_host.h"
13 #include "content/public/browser/browser_thread.h"
14 #include "content/public/common/content_constants.h"
15 #include "ipc/ipc_platform_file.h"
16 #include "ppapi/c/pp_errors.h"
17 #include "ppapi/host/dispatch_host_message.h"
18 #include "ppapi/host/host_message_context.h"
19 #include "ppapi/host/ppapi_host.h"
20 #include "ppapi/proxy/ppapi_messages.h"
21 #include "ppapi/shared_impl/file_path.h"
22 #include "ppapi/shared_impl/file_type_conversion.h"
23
24 namespace content {
25
26 namespace {
27 // Used to check if the renderer has permission for the requested operation.
28 // TODO(viettrungluu): Verify these. They don't necessarily quite make sense,
29 // but it seems to be approximately what the file system code does.
30 const int kReadPermissions = base::PLATFORM_FILE_OPEN |
31 base::PLATFORM_FILE_READ |
32 base::PLATFORM_FILE_EXCLUSIVE_READ;
33 const int kWritePermissions = base::PLATFORM_FILE_OPEN |
34 base::PLATFORM_FILE_CREATE |
35 base::PLATFORM_FILE_CREATE_ALWAYS |
36 base::PLATFORM_FILE_OPEN_TRUNCATED |
37 base::PLATFORM_FILE_WRITE |
38 base::PLATFORM_FILE_EXCLUSIVE_WRITE |
39 base::PLATFORM_FILE_WRITE_ATTRIBUTES;
40
41 // All file messages are handled by BrowserThread's blocking pool.
42 class FileMessageFilter : public ppapi::host::ResourceMessageFilter {
43 public:
44 FileMessageFilter(const std::string& plugin_name,
45 const FilePath& profile_data_directory,
yzshen1 2012/12/03 18:12:23 wrong indent.
raymes 2012/12/04 20:06:15 Done.
46 int plugin_process_id,
47 base::ProcessHandle plugin_process_handle);
48 protected:
49 // ppapi::host::ResourceMessageFilter implementation.
50 virtual scoped_refptr<base::TaskRunner> OverrideTaskRunnerForMessage(
51 const IPC::Message& msg) OVERRIDE;
52 virtual int32_t OnResourceMessageReceived(
53 const IPC::Message& msg,
54 ppapi::host::HostMessageContext* context) OVERRIDE;
55
56 private:
57 virtual ~FileMessageFilter();
58
59 int32_t OnOpenFile(ppapi::host::HostMessageContext* context,
60 const ppapi::PepperFilePath& path,
61 int flags);
62 int32_t OnRenameFile(ppapi::host::HostMessageContext* context,
63 const ppapi::PepperFilePath& from_path,
64 const ppapi::PepperFilePath& to_path);
65 int32_t OnDeleteFileOrDir(ppapi::host::HostMessageContext* context,
66 const ppapi::PepperFilePath& path,
67 bool recursive);
68 int32_t OnCreateDir(ppapi::host::HostMessageContext* context,
69 const ppapi::PepperFilePath& path);
70 int32_t OnQueryFile(ppapi::host::HostMessageContext* context,
71 const ppapi::PepperFilePath& path);
72 int32_t OnGetDirContents(ppapi::host::HostMessageContext* context,
73 const ppapi::PepperFilePath& path);
74 int32_t OnCreateTemporaryFile(ppapi::host::HostMessageContext* context);
75
76 FilePath ValidateAndConvertPepperFilePath(
77 const ppapi::PepperFilePath& pepper_path,
78 int flags);
79
80 FilePath plugin_data_directory_;
81 int plugin_process_id_;
82 base::ProcessHandle plugin_process_handle_;
83 };
84
85 } // namespace
86
87 PepperFlashFileHost::PepperFlashFileHost(
88 BrowserPpapiHost* host,
89 PP_Instance instance,
90 PP_Resource resource)
91 : ResourceHost(host->GetPpapiHost(), instance, resource) {
92 AddFilter(scoped_refptr<ppapi::host::ResourceMessageFilter>(
93 new FileMessageFilter(host->GetPluginName(),
94 host->GetProfileDataDirectory(),
95 host->GetPluginProcessID(),
96 host->GetPluginProcessHandle())));
97 }
98
99 PepperFlashFileHost::~PepperFlashFileHost() {
100 }
101
102 // static
103 FilePath PepperFlashFileHost::GetDataDirName(const FilePath& profile_path) {
104 return profile_path.Append(kPepperDataDirname);
105 }
106
107 FileMessageFilter::FileMessageFilter(
yzshen1 2012/12/03 18:12:23 It looks weird to have the implementation outside
raymes 2012/12/04 20:06:15 Done.
108 const std::string& plugin_name,
109 const FilePath& profile_data_directory,
110 int plugin_process_id,
111 base::ProcessHandle plugin_process_handle)
112 : plugin_process_id_(plugin_process_id),
113 plugin_process_handle_(plugin_process_handle) {
114 if (profile_data_directory.empty() || plugin_name.empty()) {
115 // These are used to construct the path. If they are not set it means we
116 // will construct a bad path and could provide access to the wrong files.
117 // In this case, |plugin_data_directory_| will remain unset and
118 // |ValidateAndConvertPepperFilePath| will fail.
119 NOTREACHED();
120 } else {
121 plugin_data_directory_ = PepperFlashFileHost::GetDataDirName(
122 profile_data_directory).Append(FilePath::FromUTF8Unsafe(plugin_name));
123 }
124 }
125
126 FileMessageFilter::~FileMessageFilter() {
127 }
128
129 scoped_refptr<base::TaskRunner>
130 FileMessageFilter::OverrideTaskRunnerForMessage(const IPC::Message& msg) {
131 // The blocking pool provides a pool of threads to run file
132 // operations, instead of a single thread which might require
133 // queuing time. Since these messages are synchronous as sent from
134 // the plugin, the sending thread cannot send a new message until
135 // this one returns, so there is no need to sequence tasks here. If
136 // the plugin has multiple threads, it cannot make assumptions about
137 // ordering of IPC message sends, so it cannot make assumptions
138 // about ordering of operations caused by those IPC messages.
139 return scoped_refptr<base::TaskRunner>(BrowserThread::GetBlockingPool());
140 }
141
142 int32_t FileMessageFilter::OnResourceMessageReceived(
143 const IPC::Message& msg,
144 ppapi::host::HostMessageContext* context) {
145 IPC_BEGIN_MESSAGE_MAP(FileMessageFilter, msg)
146 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_OpenFile,
147 OnOpenFile)
148 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_RenameFile,
149 OnRenameFile)
150 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_DeleteFileOrDir,
151 OnDeleteFileOrDir)
152 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_CreateDir,
153 OnCreateDir)
154 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_QueryFile,
155 OnQueryFile)
156 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_GetDirContents,
157 OnGetDirContents)
158 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
159 PpapiHostMsg_FlashFile_CreateTemporaryFile,
160 OnCreateTemporaryFile)
161 IPC_END_MESSAGE_MAP()
162 return PP_ERROR_FAILED;
163 }
164
165 int32_t FileMessageFilter::OnOpenFile(
166 ppapi::host::HostMessageContext* context,
167 const ppapi::PepperFilePath& path,
168 int flags) {
169 FilePath full_path = ValidateAndConvertPepperFilePath(path, flags);
170 if (full_path.empty()) {
171 return ppapi::PlatformFileErrorToPepperError(
172 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
173 }
174
175 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
176 base::PlatformFile file_handle = base::CreatePlatformFile(
177 full_path, flags, NULL, &error);
178 if (error != base::PLATFORM_FILE_OK) {
179 DCHECK_EQ(file_handle, base::kInvalidPlatformFileValue);
180 return ppapi::PlatformFileErrorToPepperError(error);
181 }
182
183 // Make sure we didn't try to open a directory: directory fd shouldn't be
184 // passed to untrusted processes because they open security holes.
185 base::PlatformFileInfo info;
186 if (!base::GetPlatformFileInfo(file_handle, &info) || info.is_directory) {
187 // When in doubt, throw it out.
188 base::ClosePlatformFile(file_handle);
189 return ppapi::PlatformFileErrorToPepperError(
190 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
191 }
192
193 IPC::PlatformFileForTransit file = IPC::GetFileHandleForProcess(file_handle,
194 plugin_process_handle_, true);
195 ppapi::host::ReplyMessageContext reply_context =
196 context->MakeReplyMessageContext();
197 reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
198 ppapi::proxy::SerializedHandle::FILE, file));
199 SendReply(reply_context, IPC::Message());
200 return PP_OK_COMPLETIONPENDING;
201 }
202
203 int32_t FileMessageFilter::OnRenameFile(
204 ppapi::host::HostMessageContext* context,
205 const ppapi::PepperFilePath& from_path,
206 const ppapi::PepperFilePath& to_path) {
207 FilePath from_full_path = ValidateAndConvertPepperFilePath(from_path,
208 kWritePermissions);
209 FilePath to_full_path = ValidateAndConvertPepperFilePath(to_path,
210 kWritePermissions);
211 if (from_full_path.empty() || to_full_path.empty()) {
212 return ppapi::PlatformFileErrorToPepperError(
213 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
214 }
215
216 bool result = file_util::Move(from_full_path, to_full_path);
217 return ppapi::PlatformFileErrorToPepperError(result ?
218 base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
219 }
220
221 int32_t FileMessageFilter::OnDeleteFileOrDir(
222 ppapi::host::HostMessageContext* context,
223 const ppapi::PepperFilePath& path,
224 bool recursive) {
225 FilePath full_path = ValidateAndConvertPepperFilePath(path,
226 kWritePermissions);
227 if (full_path.empty()) {
228 return ppapi::PlatformFileErrorToPepperError(
229 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
230 }
231
232 bool result = file_util::Delete(full_path, recursive);
233 return ppapi::PlatformFileErrorToPepperError(result ?
234 base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
235 }
236 int32_t FileMessageFilter::OnCreateDir(
237 ppapi::host::HostMessageContext* context,
238 const ppapi::PepperFilePath& path) {
239 FilePath full_path = ValidateAndConvertPepperFilePath(path,
240 kWritePermissions);
241 if (full_path.empty()) {
242 return ppapi::PlatformFileErrorToPepperError(
243 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
244 }
245
246 bool result = file_util::CreateDirectory(full_path);
247 return ppapi::PlatformFileErrorToPepperError(result ?
248 base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
249 }
250
251 int32_t FileMessageFilter::OnQueryFile(
252 ppapi::host::HostMessageContext* context,
253 const ppapi::PepperFilePath& path) {
254 FilePath full_path = ValidateAndConvertPepperFilePath(path,
255 kReadPermissions);
256 if (full_path.empty()) {
257 return ppapi::PlatformFileErrorToPepperError(
258 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
259 }
260
261 base::PlatformFileInfo info;
262 bool result = file_util::GetFileInfo(full_path, &info);
263 context->reply_msg = PpapiPluginMsg_FlashFile_QueryFileReply(info);
264 return ppapi::PlatformFileErrorToPepperError(result ?
265 base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
266 }
267
268 int32_t FileMessageFilter::OnGetDirContents(
269 ppapi::host::HostMessageContext* context,
270 const ppapi::PepperFilePath& path) {
271 FilePath full_path = ValidateAndConvertPepperFilePath(path, kReadPermissions);
272 if (full_path.empty()) {
273 return ppapi::PlatformFileErrorToPepperError(
274 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
275 }
276
277 ppapi::DirContents contents;
278 file_util::FileEnumerator enumerator(full_path, false,
279 file_util::FileEnumerator::FILES |
280 file_util::FileEnumerator::DIRECTORIES |
281 file_util::FileEnumerator::INCLUDE_DOT_DOT);
282
283 while (!enumerator.Next().empty()) {
284 file_util::FileEnumerator::FindInfo info;
285 enumerator.GetFindInfo(&info);
286 ppapi::DirEntry entry = {
287 file_util::FileEnumerator::GetFilename(info),
288 file_util::FileEnumerator::IsDirectory(info)
289 };
290 contents.push_back(entry);
291 }
292
293 context->reply_msg = PpapiPluginMsg_FlashFile_GetDirContentsReply(contents);
294 return PP_OK;
295 }
296
297 int32_t FileMessageFilter::OnCreateTemporaryFile(
298 ppapi::host::HostMessageContext* context) {
299 ppapi::PepperFilePath dir_path(
300 ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL, FilePath());
301 FilePath validated_dir_path = ValidateAndConvertPepperFilePath(
302 dir_path, kReadPermissions | kWritePermissions);
303 if (validated_dir_path.empty() ||
304 (!file_util::DirectoryExists(validated_dir_path) &&
305 !file_util::CreateDirectory(validated_dir_path))) {
306 return ppapi::PlatformFileErrorToPepperError(
307 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
308 }
309
310 FilePath file_path;
311 if (!file_util::CreateTemporaryFileInDir(validated_dir_path, &file_path)) {
312 return ppapi::PlatformFileErrorToPepperError(
313 base::PLATFORM_FILE_ERROR_FAILED);
314 }
315
316 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
317 base::PlatformFile file_handle = base::CreatePlatformFile(
318 file_path,
319 base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ |
320 base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_TEMPORARY |
321 base::PLATFORM_FILE_DELETE_ON_CLOSE,
322 NULL, &error);
323
324 if (error != base::PLATFORM_FILE_OK) {
325 DCHECK_EQ(file_handle, base::kInvalidPlatformFileValue);
326 return ppapi::PlatformFileErrorToPepperError(error);
327 }
328
329 IPC::PlatformFileForTransit file = IPC::GetFileHandleForProcess(file_handle,
330 plugin_process_handle_, true);
331 ppapi::host::ReplyMessageContext reply_context =
332 context->MakeReplyMessageContext();
333 reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
334 ppapi::proxy::SerializedHandle::FILE, file));
335 SendReply(reply_context, IPC::Message());
336 return PP_OK_COMPLETIONPENDING;
337 }
338
339 FilePath FileMessageFilter::ValidateAndConvertPepperFilePath(
340 const ppapi::PepperFilePath& pepper_path,
341 int flags) {
342 FilePath file_path; // Empty path returned on error.
343 switch (pepper_path.domain()) {
344 case ppapi::PepperFilePath::DOMAIN_ABSOLUTE:
345 if (pepper_path.path().IsAbsolute() &&
346 ChildProcessSecurityPolicyImpl::GetInstance()->HasPermissionsForFile(
347 plugin_process_id_, pepper_path.path(), flags))
348 file_path = pepper_path.path();
349 break;
350 case ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL:
351 // This filter provides the module name portion of the path to prevent
352 // plugins from accessing each other's data.
353 if (!plugin_data_directory_.empty() &&
354 !pepper_path.path().IsAbsolute() &&
355 !pepper_path.path().ReferencesParent())
356 file_path = plugin_data_directory_.Append(pepper_path.path());
357 break;
358 default:
359 NOTREACHED();
360 break;
361 }
362 return file_path;
363 }
364
365 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698