OLD | NEW |
| (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 "chrome/browser/nacl_host/pnacl_file_host.h" | |
6 | |
7 #include "base/bind.h" | |
8 #include "base/file_util.h" | |
9 #include "base/files/file_path.h" | |
10 #include "base/memory/ref_counted.h" | |
11 #include "base/path_service.h" | |
12 #include "base/platform_file.h" | |
13 #include "base/utf_string_conversions.h" | |
14 #include "chrome/browser/renderer_host/chrome_render_message_filter.h" | |
15 #include "chrome/common/chrome_paths.h" | |
16 #include "chrome/common/render_messages.h" | |
17 #include "content/public/browser/browser_thread.h" | |
18 #include "ipc/ipc_platform_file.h" | |
19 | |
20 using content::BrowserThread; | |
21 | |
22 namespace { | |
23 | |
24 // Force a prefix to prevent user from opening "magic" files. | |
25 const char* kExpectedFilePrefix = "pnacl_public_"; | |
26 | |
27 // Restrict PNaCl file lengths to reduce likelyhood of hitting bugs | |
28 // in file name limit error-handling-code-paths, etc. | |
29 const size_t kMaxFileLength = 40; | |
30 | |
31 void NotifyRendererOfError( | |
32 ChromeRenderMessageFilter* chrome_render_message_filter, | |
33 IPC::Message* reply_msg) { | |
34 reply_msg->set_reply_error(); | |
35 chrome_render_message_filter->Send(reply_msg); | |
36 } | |
37 | |
38 bool PnaclDoOpenFile(const base::FilePath& file_to_open, | |
39 base::PlatformFile* out_file) { | |
40 base::PlatformFileError error_code; | |
41 *out_file = base::CreatePlatformFile(file_to_open, | |
42 base::PLATFORM_FILE_OPEN | | |
43 base::PLATFORM_FILE_READ, | |
44 NULL, | |
45 &error_code); | |
46 if (error_code != base::PLATFORM_FILE_OK) { | |
47 return false; | |
48 } | |
49 return true; | |
50 } | |
51 | |
52 void DoOpenPnaclFile( | |
53 ChromeRenderMessageFilter* chrome_render_message_filter, | |
54 const std::string& filename, | |
55 IPC::Message* reply_msg) { | |
56 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
57 base::FilePath full_filepath; | |
58 | |
59 // Do some validation. | |
60 if (!pnacl_file_host::PnaclCanOpenFile(filename, &full_filepath)) { | |
61 NotifyRendererOfError(chrome_render_message_filter, reply_msg); | |
62 return; | |
63 } | |
64 | |
65 base::PlatformFile file_to_open; | |
66 if (!PnaclDoOpenFile(full_filepath, &file_to_open)) { | |
67 NotifyRendererOfError(chrome_render_message_filter, reply_msg); | |
68 return; | |
69 } | |
70 | |
71 // Send the reply! | |
72 // Do any DuplicateHandle magic that is necessary first. | |
73 IPC::PlatformFileForTransit target_desc = | |
74 IPC::GetFileHandleForProcess(file_to_open, | |
75 chrome_render_message_filter->peer_handle(), | |
76 true /* Close source */); | |
77 if (target_desc == IPC::InvalidPlatformFileForTransit()) { | |
78 NotifyRendererOfError(chrome_render_message_filter, reply_msg); | |
79 return; | |
80 } | |
81 ChromeViewHostMsg_GetReadonlyPnaclFD::WriteReplyParams( | |
82 reply_msg, target_desc); | |
83 chrome_render_message_filter->Send(reply_msg); | |
84 } | |
85 | |
86 void DoCreateTemporaryFile( | |
87 ChromeRenderMessageFilter* chrome_render_message_filter, | |
88 IPC::Message* reply_msg) { | |
89 DCHECK(BrowserThread::CurrentlyOn(BrowserThread::FILE)); | |
90 | |
91 base::FilePath file_path; | |
92 if (!file_util::CreateTemporaryFile(&file_path)) { | |
93 NotifyRendererOfError(chrome_render_message_filter, reply_msg); | |
94 return; | |
95 } | |
96 | |
97 base::PlatformFileError error; | |
98 base::PlatformFile file_handle = base::CreatePlatformFile( | |
99 file_path, | |
100 base::PLATFORM_FILE_CREATE_ALWAYS | base::PLATFORM_FILE_READ | | |
101 base::PLATFORM_FILE_WRITE | base::PLATFORM_FILE_TEMPORARY | | |
102 base::PLATFORM_FILE_DELETE_ON_CLOSE, | |
103 NULL, &error); | |
104 | |
105 if (error != base::PLATFORM_FILE_OK) { | |
106 NotifyRendererOfError(chrome_render_message_filter, reply_msg); | |
107 return; | |
108 } | |
109 | |
110 // Send the reply! | |
111 // Do any DuplicateHandle magic that is necessary first. | |
112 IPC::PlatformFileForTransit target_desc = | |
113 IPC::GetFileHandleForProcess(file_handle, | |
114 chrome_render_message_filter->peer_handle(), | |
115 true); | |
116 if (target_desc == IPC::InvalidPlatformFileForTransit()) { | |
117 NotifyRendererOfError(chrome_render_message_filter, reply_msg); | |
118 return; | |
119 } | |
120 | |
121 ChromeViewHostMsg_NaClCreateTemporaryFile::WriteReplyParams( | |
122 reply_msg, target_desc); | |
123 chrome_render_message_filter->Send(reply_msg); | |
124 } | |
125 | |
126 } // namespace | |
127 | |
128 namespace pnacl_file_host { | |
129 | |
130 void GetReadonlyPnaclFd( | |
131 ChromeRenderMessageFilter* chrome_render_message_filter, | |
132 const std::string& filename, | |
133 IPC::Message* reply_msg) { | |
134 if (!BrowserThread::PostTask( | |
135 BrowserThread::FILE, FROM_HERE, | |
136 base::Bind(&DoOpenPnaclFile, | |
137 make_scoped_refptr(chrome_render_message_filter), | |
138 filename, | |
139 reply_msg))) { | |
140 NotifyRendererOfError(chrome_render_message_filter, reply_msg); | |
141 } | |
142 } | |
143 | |
144 // This function is security sensitive. Be sure to check with a security | |
145 // person before you modify it. | |
146 bool PnaclCanOpenFile(const std::string& filename, | |
147 base::FilePath* file_to_open) { | |
148 if (filename.length() > kMaxFileLength) | |
149 return false; | |
150 | |
151 if (filename.empty()) | |
152 return false; | |
153 | |
154 // Restrict character set of the file name to something really simple | |
155 // (a-z, 0-9, and underscores). | |
156 for (size_t i = 0; i < filename.length(); ++i) { | |
157 char charAt = filename[i]; | |
158 if (charAt < 'a' || charAt > 'z') | |
159 if (charAt < '0' || charAt > '9') | |
160 if (charAt != '_') | |
161 return false; | |
162 } | |
163 | |
164 // PNaCl must be installed. | |
165 base::FilePath pnacl_dir; | |
166 if (!PathService::Get(chrome::DIR_PNACL_COMPONENT, &pnacl_dir) || | |
167 pnacl_dir.empty()) | |
168 return false; | |
169 | |
170 // Prepend the prefix to restrict files to a whitelisted set. | |
171 base::FilePath full_path = pnacl_dir.AppendASCII( | |
172 std::string(kExpectedFilePrefix) + filename); | |
173 *file_to_open = full_path; | |
174 return true; | |
175 } | |
176 | |
177 void CreateTemporaryFile( | |
178 ChromeRenderMessageFilter* chrome_render_message_filter, | |
179 IPC::Message* reply_msg) { | |
180 if (!BrowserThread::PostTask( | |
181 BrowserThread::FILE, FROM_HERE, | |
182 base::Bind(&DoCreateTemporaryFile, | |
183 make_scoped_refptr(chrome_render_message_filter), | |
184 reply_msg))) { | |
185 NotifyRendererOfError(chrome_render_message_filter, reply_msg); | |
186 } | |
187 } | |
188 | |
189 } // namespace pnacl_file_host | |
OLD | NEW |