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

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

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

Powered by Google App Engine
This is Rietveld 408576698