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

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, 1 month 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 } // namespace
41
42 PepperFlashFileHost::PepperFlashFileHost(
43 BrowserPpapiHost* host,
44 PP_Instance instance,
45 PP_Resource resource)
46 : ResourceHost(host->GetPpapiHost(), instance, resource) {
47 AddFilter(scoped_refptr<ppapi::host::ResourceMessageFilter>(
48 new FileThreadMessageFilter(host->GetPluginName(),
49 host->GetProfileDataDirectory(),
50 host->GetPluginProcessID(),
51 host->GetPluginProcessHandle())));
52 }
53
54 PepperFlashFileHost::~PepperFlashFileHost() {
55 }
56
57 // static
58 FilePath PepperFlashFileHost::GetDataDirName(const FilePath& profile_path) {
59 return profile_path.Append(kPepperDataDirname);
60 }
61
62 FileThreadMessageFilter::FileThreadMessageFilter(
63 const std::string& plugin_name,
64 const FilePath& profile_data_directory,
65 int plugin_process_id_,
66 base::ProcessHandle plugin_process_handle)
67 : plugin_process_id_(plugin_process_id_),
yzshen1 2012/11/21 00:38:59 Please don't use a suffix of '_' for the local var
raymes 2012/11/21 22:44:53 oops thanks. Done.
68 plugin_process_handle_(plugin_process_handle) {
69 if (profile_data_directory.empty() || plugin_name.empty()) {
yzshen1 2012/11/21 00:38:59 good catch. :)
raymes 2012/11/21 22:44:53 Done.
70 // These are used to construct the path. If they are not set it means we
71 // will construct a bad path and could provide access to the wrong files.
72 // In this case, |plugin_data_directory_| will remain unset and
73 // |ValidateAndConvertPepperFilePath| will fail.
74 NOTREACHED();
75 } else {
76 plugin_data_directory_ = PepperFlashFileHost::GetDataDirName(
77 profile_data_directory).Append(FilePath::FromUTF8Unsafe(plugin_name));
78 }
79 }
80
81 FileThreadMessageFilter::~FileThreadMessageFilter() {
82 }
83
84 scoped_refptr<base::TaskRunner>
85 FileThreadMessageFilter::OverrideTaskRunnerForMessage(const IPC::Message& msg) {
86 // The blocking pool provides a pool of threads to run file
87 // operations, instead of a single thread which might require
88 // queuing time. Since these messages are synchronous as sent from
89 // the plugin, the sending thread cannot send a new message until
90 // this one returns, so there is no need to sequence tasks here. If
91 // the plugin has multiple threads, it cannot make assumptions about
92 // ordering of IPC message sends, so it cannot make assumptions
93 // about ordering of operations caused by those IPC messages.
94 return scoped_refptr<base::TaskRunner>(BrowserThread::GetBlockingPool());
95 }
96
97 int32_t FileThreadMessageFilter::OnResourceMessageReceived(
98 const IPC::Message& msg,
99 ppapi::host::HostMessageContext* context) {
100 IPC_BEGIN_MESSAGE_MAP(FileThreadMessageFilter, msg)
101 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_OpenFile,
102 OnOpenFile)
103 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_RenameFile,
104 OnRenameFile)
105 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_DeleteFileOrDir,
106 OnDeleteFileOrDir)
107 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_CreateDir,
108 OnCreateDir)
109 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_QueryFile,
110 OnQueryFile)
111 PPAPI_DISPATCH_HOST_RESOURCE_CALL(PpapiHostMsg_FlashFile_GetDirContents,
112 OnGetDirContents)
113 PPAPI_DISPATCH_HOST_RESOURCE_CALL_0(
114 PpapiHostMsg_FlashFile_CreateTemporaryFile,
115 OnCreateTemporaryFile)
116 IPC_END_MESSAGE_MAP()
117 return PP_ERROR_FAILED;
118 }
119
120 int32_t FileThreadMessageFilter::OnOpenFile(
121 ppapi::host::HostMessageContext* context,
122 const ppapi::PepperFilePath& path,
123 int flags) {
124 FilePath full_path = ValidateAndConvertPepperFilePath(path, flags);
125 if (full_path.empty()) {
126 return ppapi::PlatformFileErrorToPepperError(
127 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
128 }
129
130 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
131 base::PlatformFile file_handle = base::CreatePlatformFile(
132 full_path, flags, NULL, &error);
133 if (error != base::PLATFORM_FILE_OK) {
134 DCHECK_EQ(file_handle, base::kInvalidPlatformFileValue);
135 return ppapi::PlatformFileErrorToPepperError(error);
136 }
137
138 // Make sure we didn't try to open a directory: directory fd shouldn't be
139 // passed to untrusted processes because they open security holes.
140 base::PlatformFileInfo info;
141 if (!base::GetPlatformFileInfo(file_handle, &info) || info.is_directory) {
142 // When in doubt, throw it out.
143 return ppapi::PlatformFileErrorToPepperError(
yzshen1 2012/11/21 00:38:59 is |file_handle| leaked here?
raymes 2012/11/21 22:44:53 Yes good catch. I think it potentially is. This bu
144 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
145 }
146
147 IPC::PlatformFileForTransit file = IPC::GetFileHandleForProcess(file_handle,
148 plugin_process_handle_, true);
149 ppapi::host::ReplyMessageContext reply_context =
150 context->MakeReplyMessageContext();
151 reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
152 ppapi::proxy::SerializedHandle::FILE, file));
153 SendReply(reply_context, IPC::Message());
154 return PP_OK_COMPLETIONPENDING;
155 }
156
157 int32_t FileThreadMessageFilter::OnRenameFile(
158 ppapi::host::HostMessageContext* context,
159 const ppapi::PepperFilePath& from_path,
160 const ppapi::PepperFilePath& to_path) {
161 FilePath from_full_path = ValidateAndConvertPepperFilePath(from_path,
162 kWritePermissions);
163 FilePath to_full_path = ValidateAndConvertPepperFilePath(to_path,
164 kWritePermissions);
165 if (from_full_path.empty() || to_full_path.empty()) {
166 return ppapi::PlatformFileErrorToPepperError(
167 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
168 }
169
170 bool result = file_util::Move(from_full_path, to_full_path);
171 return ppapi::PlatformFileErrorToPepperError(result ?
172 base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
173 }
174
175 int32_t FileThreadMessageFilter::OnDeleteFileOrDir(
176 ppapi::host::HostMessageContext* context,
177 const ppapi::PepperFilePath& path,
178 bool recursive) {
179 FilePath full_path = ValidateAndConvertPepperFilePath(path,
180 kWritePermissions);
181 if (full_path.empty()) {
182 return ppapi::PlatformFileErrorToPepperError(
183 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
184 }
185
186 bool result = file_util::Delete(full_path, recursive);
187 return ppapi::PlatformFileErrorToPepperError(result ?
188 base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
189 }
190 int32_t FileThreadMessageFilter::OnCreateDir(
191 ppapi::host::HostMessageContext* context,
192 const ppapi::PepperFilePath& path) {
193 FilePath full_path = ValidateAndConvertPepperFilePath(path,
194 kWritePermissions);
195 if (full_path.empty()) {
196 return ppapi::PlatformFileErrorToPepperError(
197 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
198 }
199
200 bool result = file_util::CreateDirectory(full_path);
201 return ppapi::PlatformFileErrorToPepperError(result ?
202 base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
203 }
204
205 int32_t FileThreadMessageFilter::OnQueryFile(
206 ppapi::host::HostMessageContext* context,
207 const ppapi::PepperFilePath& path) {
208 FilePath full_path = ValidateAndConvertPepperFilePath(path,
209 kWritePermissions);
yzshen1 2012/11/21 00:38:59 This should be kReadPermissions.
raymes 2012/11/21 22:44:53 Good catch. Done.
210 if (full_path.empty()) {
211 return ppapi::PlatformFileErrorToPepperError(
212 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
213 }
214
215 base::PlatformFileInfo info;
216 bool result = file_util::GetFileInfo(full_path, &info);
217 context->reply_msg = PpapiPluginMsg_FlashFile_QueryFileReply(info);
218 return ppapi::PlatformFileErrorToPepperError(result ?
219 base::PLATFORM_FILE_OK : base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
220 }
221
222 int32_t FileThreadMessageFilter::OnGetDirContents(
223 ppapi::host::HostMessageContext* context,
224 const ppapi::PepperFilePath& path) {
225 FilePath full_path = ValidateAndConvertPepperFilePath(path, kReadPermissions);
226 if (full_path.empty()) {
227 return ppapi::PlatformFileErrorToPepperError(
228 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
229 }
230
231 ppapi::DirContents contents;
232 file_util::FileEnumerator enumerator(full_path, false,
233 file_util::FileEnumerator::FILES |
234 file_util::FileEnumerator::DIRECTORIES |
235 file_util::FileEnumerator::INCLUDE_DOT_DOT);
236
237 while (!enumerator.Next().empty()) {
238 file_util::FileEnumerator::FindInfo info;
239 enumerator.GetFindInfo(&info);
240 ppapi::DirEntry entry = {
241 file_util::FileEnumerator::GetFilename(info),
242 file_util::FileEnumerator::IsDirectory(info)
243 };
244 contents.push_back(entry);
245 }
246
247 context->reply_msg = PpapiPluginMsg_FlashFile_GetDirContentsReply(contents);
248 return PP_OK;
249 }
250
251 int32_t FileThreadMessageFilter::OnCreateTemporaryFile(
252 ppapi::host::HostMessageContext* context) {
253 ppapi::PepperFilePath dir_path(
254 ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL, FilePath());
255 FilePath validated_dir_path = ValidateAndConvertPepperFilePath(
256 dir_path, kReadPermissions | kWritePermissions);
257 if (validated_dir_path.empty() ||
258 (!file_util::DirectoryExists(validated_dir_path) &&
259 !file_util::CreateDirectory(validated_dir_path))) {
260 return ppapi::PlatformFileErrorToPepperError(
261 base::PLATFORM_FILE_ERROR_ACCESS_DENIED);
262 }
263
264 FilePath file_path;
265 if (!file_util::CreateTemporaryFileInDir(validated_dir_path, &file_path)) {
266 return ppapi::PlatformFileErrorToPepperError(
267 base::PLATFORM_FILE_ERROR_FAILED);
268 }
269
270 base::PlatformFileError error = base::PLATFORM_FILE_ERROR_FAILED;
271 base::PlatformFile file_handle = base::CreatePlatformFile(
272 file_path,
273 base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ |
274 base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_TEMPORARY |
275 base::PLATFORM_FILE_DELETE_ON_CLOSE,
276 NULL, &error);
277
278 if (error != base::PLATFORM_FILE_OK) {
279 DCHECK_EQ(file_handle, base::kInvalidPlatformFileValue);
280 return ppapi::PlatformFileErrorToPepperError(error);
281 }
282
283 IPC::PlatformFileForTransit file = IPC::GetFileHandleForProcess(file_handle,
284 plugin_process_handle_, true);
285 ppapi::host::ReplyMessageContext reply_context =
286 context->MakeReplyMessageContext();
287 reply_context.params.AppendHandle(ppapi::proxy::SerializedHandle(
288 ppapi::proxy::SerializedHandle::FILE, file));
289 SendReply(reply_context, IPC::Message());
290 return PP_OK_COMPLETIONPENDING;
291 }
292
293 FilePath FileThreadMessageFilter::ValidateAndConvertPepperFilePath(
294 const ppapi::PepperFilePath& pepper_path,
295 int flags) {
296 FilePath file_path; // Empty path returned on error.
297 switch (pepper_path.domain()) {
298 case ppapi::PepperFilePath::DOMAIN_ABSOLUTE:
299 if (pepper_path.path().IsAbsolute() &&
300 ChildProcessSecurityPolicyImpl::GetInstance()->HasPermissionsForFile(
301 plugin_process_id_, pepper_path.path(), flags))
302 file_path = pepper_path.path();
303 break;
304 case ppapi::PepperFilePath::DOMAIN_MODULE_LOCAL:
305 // This filter provides the module name portion of the path to prevent
306 // plugins from accessing each other's data.
307 if (!plugin_data_directory_.empty() &&
308 !pepper_path.path().IsAbsolute() &&
309 !pepper_path.path().ReferencesParent())
310 file_path = plugin_data_directory_.Append(pepper_path.path());
311 break;
312 default:
313 NOTREACHED();
314 break;
315 }
316 return file_path;
317 }
318
319 } // namespace content
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698