OLD | NEW |
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "build/build_config.h" | 5 #include "build/build_config.h" |
6 | 6 |
7 #include "chrome/browser/nacl_host/nacl_process_host.h" | 7 #include "chrome/browser/nacl_host/nacl_process_host.h" |
8 | 8 |
9 #if defined(OS_POSIX) | 9 #if defined(OS_POSIX) |
10 #include <fcntl.h> | 10 #include <fcntl.h> |
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
45 } | 45 } |
46 #endif | 46 #endif |
47 | 47 |
48 } // namespace | 48 } // namespace |
49 | 49 |
50 struct NaClProcessHost::NaClInternal { | 50 struct NaClProcessHost::NaClInternal { |
51 std::vector<nacl::Handle> sockets_for_renderer; | 51 std::vector<nacl::Handle> sockets_for_renderer; |
52 std::vector<nacl::Handle> sockets_for_sel_ldr; | 52 std::vector<nacl::Handle> sockets_for_sel_ldr; |
53 }; | 53 }; |
54 | 54 |
| 55 bool NaClProcessHost::RunningOnWOW64() { |
| 56 #if defined(OS_WIN) |
| 57 return (base::win::OSInfo::GetInstance()->wow64_status() == |
| 58 base::win::OSInfo::WOW64_ENABLED); |
| 59 #else |
| 60 return false; |
| 61 #endif |
| 62 } |
| 63 |
55 NaClProcessHost::NaClProcessHost(const std::wstring& url) | 64 NaClProcessHost::NaClProcessHost(const std::wstring& url) |
56 : BrowserChildProcessHost(NACL_LOADER_PROCESS), | 65 : BrowserChildProcessHost(NACL_LOADER_PROCESS), |
57 reply_msg_(NULL), | 66 reply_msg_(NULL), |
58 internal_(new NaClInternal()), | 67 internal_(new NaClInternal()), |
59 running_on_wow64_(false), | |
60 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { | 68 ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) { |
61 set_name(WideToUTF16Hack(url)); | 69 set_name(WideToUTF16Hack(url)); |
62 #if defined(OS_WIN) | |
63 running_on_wow64_ = (base::win::OSInfo::GetInstance()->wow64_status() == | |
64 base::win::OSInfo::WOW64_ENABLED); | |
65 #endif | |
66 } | 70 } |
67 | 71 |
68 NaClProcessHost::~NaClProcessHost() { | 72 NaClProcessHost::~NaClProcessHost() { |
69 // nacl::Close() is not available at link time if DISABLE_NACL is | 73 // nacl::Close() is not available at link time if DISABLE_NACL is |
70 // defined, but we still compile a bunch of other code from this | 74 // defined, but we still compile a bunch of other code from this |
71 // file anyway. TODO(mseaborn): Make this less messy. | 75 // file anyway. TODO(mseaborn): Make this less messy. |
72 #ifndef DISABLE_NACL | 76 #ifndef DISABLE_NACL |
73 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) { | 77 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) { |
74 if (nacl::Close(internal_->sockets_for_renderer[i]) != 0) { | 78 if (nacl::Close(internal_->sockets_for_renderer[i]) != 0) { |
75 LOG(ERROR) << "nacl::Close() failed"; | 79 LOG(ERROR) << "nacl::Close() failed"; |
(...skipping 22 matching lines...) Expand all Loading... |
98 NOTIMPLEMENTED() << "Native Client disabled at build time"; | 102 NOTIMPLEMENTED() << "Native Client disabled at build time"; |
99 return false; | 103 return false; |
100 #else | 104 #else |
101 // Place an arbitrary limit on the number of sockets to limit | 105 // Place an arbitrary limit on the number of sockets to limit |
102 // exposure in case the renderer is compromised. We can increase | 106 // exposure in case the renderer is compromised. We can increase |
103 // this if necessary. | 107 // this if necessary. |
104 if (socket_count > 8) { | 108 if (socket_count > 8) { |
105 return false; | 109 return false; |
106 } | 110 } |
107 | 111 |
| 112 if (irt_platform_file_ == base::kInvalidPlatformFileValue) { |
| 113 LOG(ERROR) << "Cannot launch NaCl process after IRT file open failed"; |
| 114 return false; |
| 115 } |
| 116 |
108 // Rather than creating a socket pair in the renderer, and passing | 117 // Rather than creating a socket pair in the renderer, and passing |
109 // one side through the browser to sel_ldr, socket pairs are created | 118 // one side through the browser to sel_ldr, socket pairs are created |
110 // in the browser and then passed to the renderer and sel_ldr. | 119 // in the browser and then passed to the renderer and sel_ldr. |
111 // | 120 // |
112 // This is mainly for the benefit of Windows, where sockets cannot | 121 // This is mainly for the benefit of Windows, where sockets cannot |
113 // be passed in messages, but are copied via DuplicateHandle(). | 122 // be passed in messages, but are copied via DuplicateHandle(). |
114 // This means the sandboxed renderer cannot send handles to the | 123 // This means the sandboxed renderer cannot send handles to the |
115 // browser process. | 124 // browser process. |
116 | 125 |
117 for (int i = 0; i < socket_count; i++) { | 126 for (int i = 0; i < socket_count; i++) { |
(...skipping 55 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
173 switches::kNaClLoaderProcess); | 182 switches::kNaClLoaderProcess); |
174 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); | 183 cmd_line->AppendSwitchASCII(switches::kProcessChannelID, channel_id()); |
175 if (logging::DialogsAreSuppressed()) | 184 if (logging::DialogsAreSuppressed()) |
176 cmd_line->AppendSwitch(switches::kNoErrorDialogs); | 185 cmd_line->AppendSwitch(switches::kNoErrorDialogs); |
177 | 186 |
178 if (!nacl_loader_prefix.empty()) | 187 if (!nacl_loader_prefix.empty()) |
179 cmd_line->PrependWrapper(nacl_loader_prefix); | 188 cmd_line->PrependWrapper(nacl_loader_prefix); |
180 | 189 |
181 // On Windows we might need to start the broker process to launch a new loader | 190 // On Windows we might need to start the broker process to launch a new loader |
182 #if defined(OS_WIN) | 191 #if defined(OS_WIN) |
183 if (running_on_wow64_) { | 192 if (RunningOnWOW64()) { |
184 return NaClBrokerService::GetInstance()->LaunchLoader( | 193 return NaClBrokerService::GetInstance()->LaunchLoader( |
185 this, ASCIIToWide(channel_id())); | 194 this, ASCIIToWide(channel_id())); |
186 } else { | 195 } else { |
187 BrowserChildProcessHost::Launch(FilePath(), cmd_line); | 196 BrowserChildProcessHost::Launch(FilePath(), cmd_line); |
188 } | 197 } |
189 #elif defined(OS_POSIX) | 198 #elif defined(OS_POSIX) |
190 BrowserChildProcessHost::Launch(nacl_loader_prefix.empty(), // use_zygote | 199 BrowserChildProcessHost::Launch(nacl_loader_prefix.empty(), // use_zygote |
191 base::environment_vector(), | 200 base::environment_vector(), |
192 cmd_line); | 201 cmd_line); |
193 #endif | 202 #endif |
194 | 203 |
195 return true; | 204 return true; |
196 } | 205 } |
197 | 206 |
198 void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) { | 207 void NaClProcessHost::OnProcessLaunchedByBroker(base::ProcessHandle handle) { |
199 set_handle(handle); | 208 set_handle(handle); |
200 OnProcessLaunched(); | 209 OnProcessLaunched(); |
201 } | 210 } |
202 | 211 |
203 base::TerminationStatus NaClProcessHost::GetChildTerminationStatus( | 212 base::TerminationStatus NaClProcessHost::GetChildTerminationStatus( |
204 int* exit_code) { | 213 int* exit_code) { |
205 if (running_on_wow64_) | 214 if (RunningOnWOW64()) |
206 return base::GetTerminationStatus(handle(), exit_code); | 215 return base::GetTerminationStatus(handle(), exit_code); |
207 return BrowserChildProcessHost::GetChildTerminationStatus(exit_code); | 216 return BrowserChildProcessHost::GetChildTerminationStatus(exit_code); |
208 } | 217 } |
209 | 218 |
210 void NaClProcessHost::OnChildDied() { | 219 void NaClProcessHost::OnChildDied() { |
211 int exit_code; | 220 int exit_code; |
212 GetChildTerminationStatus(&exit_code); | 221 GetChildTerminationStatus(&exit_code); |
213 std::string message = | 222 std::string message = |
214 base::StringPrintf("NaCl process exited with status %i (0x%x)", | 223 base::StringPrintf("NaCl process exited with status %i (0x%x)", |
215 exit_code, exit_code); | 224 exit_code, exit_code); |
216 if (exit_code == 0) { | 225 if (exit_code == 0) { |
217 LOG(INFO) << message; | 226 LOG(INFO) << message; |
218 } else { | 227 } else { |
219 LOG(ERROR) << message; | 228 LOG(ERROR) << message; |
220 } | 229 } |
221 | 230 |
222 #if defined(OS_WIN) | 231 #if defined(OS_WIN) |
223 NaClBrokerService::GetInstance()->OnLoaderDied(); | 232 NaClBrokerService::GetInstance()->OnLoaderDied(); |
224 #endif | 233 #endif |
225 BrowserChildProcessHost::OnChildDied(); | 234 BrowserChildProcessHost::OnChildDied(); |
226 } | 235 } |
227 | 236 |
228 FilePath::StringType NaClProcessHost::GetIrtLibraryFilename() { | 237 base::PlatformFile NaClProcessHost::irt_platform_file_; |
229 bool on_x86_64 = running_on_wow64_; | |
230 #if defined(__x86_64__) | |
231 on_x86_64 = true; | |
232 #endif | |
233 if (on_x86_64) { | |
234 return FILE_PATH_LITERAL("nacl_irt_x86_64.nexe"); | |
235 } else { | |
236 return FILE_PATH_LITERAL("nacl_irt_x86_32.nexe"); | |
237 } | |
238 } | |
239 | 238 |
240 void NaClProcessHost::OnProcessLaunched() { | 239 void NaClProcessHost::OpenIrtLibraryFile() { |
241 // TODO(mseaborn): Opening the IRT file every time a NaCl process is | 240 irt_platform_file_ = base::kInvalidPlatformFileValue; |
242 // launched probably does not work with auto-update on Linux. We | 241 |
243 // might need to open the file on startup. If so, we would need to | 242 FilePath irt_filepath; |
244 // ensure that NaCl's ELF loader does not use lseek() on the shared | 243 |
245 // IRT file descriptor, otherwise there would be a race condition. | |
246 FilePath irt_path; | |
247 // Allow the IRT library to be overridden via an environment | 244 // Allow the IRT library to be overridden via an environment |
248 // variable. This allows the NaCl/Chromium integration bot to | 245 // variable. This allows the NaCl/Chromium integration bot to |
249 // specify a newly-built IRT rather than using a prebuilt one | 246 // specify a newly-built IRT rather than using a prebuilt one |
250 // downloaded via Chromium's DEPS file. We use the same environment | 247 // downloaded via Chromium's DEPS file. We use the same environment |
251 // variable that the standalone NaCl PPAPI plugin accepts. | 248 // variable that the standalone NaCl PPAPI plugin accepts. |
252 const char* irt_path_var = getenv("NACL_IRT_LIBRARY"); | 249 const char* irt_path_var = getenv("NACL_IRT_LIBRARY"); |
253 if (irt_path_var != NULL) { | 250 if (irt_path_var != NULL) { |
254 FilePath::StringType string(irt_path_var, | 251 FilePath::StringType path_string( |
255 irt_path_var + strlen(irt_path_var)); | 252 irt_path_var, const_cast<const char*>(strchr(irt_path_var, '\0'))); |
256 irt_path = FilePath(string); | 253 irt_filepath = FilePath(path_string); |
257 } else { | 254 } else { |
258 FilePath plugin_dir; | 255 FilePath plugin_dir; |
259 if (!PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &plugin_dir)) { | 256 if (!PathService::Get(chrome::DIR_INTERNAL_PLUGINS, &plugin_dir)) { |
260 LOG(ERROR) << "Failed to locate the plugins directory"; | 257 LOG(ERROR) << "Failed to locate the plugins directory"; |
261 delete this; | |
262 return; | 258 return; |
263 } | 259 } |
264 irt_path = plugin_dir.Append(GetIrtLibraryFilename()); | 260 |
| 261 bool on_x86_64 = RunningOnWOW64(); |
| 262 #if defined(__x86_64__) |
| 263 on_x86_64 = true; |
| 264 #endif |
| 265 FilePath::StringType irt_name; |
| 266 if (on_x86_64) { |
| 267 irt_name = FILE_PATH_LITERAL("nacl_irt_x86_64.nexe"); |
| 268 } else { |
| 269 irt_name = FILE_PATH_LITERAL("nacl_irt_x86_32.nexe"); |
| 270 } |
| 271 |
| 272 irt_filepath = plugin_dir.Append(irt_name); |
265 } | 273 } |
266 | 274 |
267 if (!base::FileUtilProxy::CreateOrOpen( | 275 base::PlatformFileError error_code; |
268 BrowserThread::GetMessageLoopProxyForThread(BrowserThread::FILE), | 276 irt_platform_file_ = base::CreatePlatformFile(irt_filepath, |
269 irt_path, | 277 base::PLATFORM_FILE_OPEN | |
270 base::PLATFORM_FILE_OPEN | base::PLATFORM_FILE_READ, | 278 base::PLATFORM_FILE_READ, |
271 base::Bind(&NaClProcessHost::OpenIrtFileDone, | 279 NULL, |
272 weak_factory_.GetWeakPtr()))) { | 280 &error_code); |
273 delete this; | 281 if (error_code != base::PLATFORM_FILE_OK) { |
| 282 LOG(ERROR) << "Failed to open NaCl IRT file \"" |
| 283 << irt_filepath.LossyDisplayName() |
| 284 << "\": " << error_code; |
274 } | 285 } |
275 } | 286 } |
276 | 287 |
277 void NaClProcessHost::OpenIrtFileDone(base::PlatformFileError error_code, | 288 void NaClProcessHost::OnProcessLaunched() { |
278 base::PassPlatformFile file, | 289 SendStart(irt_platform_file_); |
279 bool created) { | 290 } |
| 291 |
| 292 static bool SendHandleToSelLdr( |
| 293 base::ProcessHandle processh, |
| 294 nacl::Handle sourceh, bool close_source, |
| 295 std::vector<nacl::FileDescriptor> *handles_for_sel_ldr) { |
| 296 #if defined(OS_WIN) |
| 297 HANDLE channel; |
| 298 int flags = DUPLICATE_SAME_ACCESS; |
| 299 if (close_source) |
| 300 flags |= DUPLICATE_CLOSE_SOURCE; |
| 301 if (!DuplicateHandle(GetCurrentProcess(), |
| 302 reinterpret_cast<HANDLE>(sourceh), |
| 303 processh, |
| 304 &channel, |
| 305 0, // Unused given DUPLICATE_SAME_ACCESS. |
| 306 FALSE, |
| 307 flags)) { |
| 308 LOG(ERROR) << "DuplicateHandle() failed"; |
| 309 return false; |
| 310 } |
| 311 handles_for_sel_ldr->push_back( |
| 312 reinterpret_cast<nacl::FileDescriptor>(channel)); |
| 313 #else |
| 314 nacl::FileDescriptor channel; |
| 315 channel.fd = sourceh; |
| 316 channel.auto_close = close_source; |
| 317 handles_for_sel_ldr->push_back(channel); |
| 318 #endif |
| 319 return true; |
| 320 } |
| 321 |
| 322 void NaClProcessHost::SendStart(base::PlatformFile irt_file) { |
280 std::vector<nacl::FileDescriptor> handles_for_renderer; | 323 std::vector<nacl::FileDescriptor> handles_for_renderer; |
281 base::ProcessHandle nacl_process_handle; | 324 base::ProcessHandle nacl_process_handle; |
282 bool have_irt_file = false; | |
283 if (base::PLATFORM_FILE_OK == error_code) { | |
284 internal_->sockets_for_sel_ldr.push_back(file.ReleaseValue()); | |
285 have_irt_file = true; | |
286 } else { | |
287 LOG(ERROR) << "Failed to open the NaCl IRT library file"; | |
288 } | |
289 | 325 |
290 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) { | 326 for (size_t i = 0; i < internal_->sockets_for_renderer.size(); i++) { |
291 #if defined(OS_WIN) | 327 #if defined(OS_WIN) |
292 // Copy the handle into the renderer process. | 328 // Copy the handle into the renderer process. |
293 HANDLE handle_in_renderer; | 329 HANDLE handle_in_renderer; |
294 if (!DuplicateHandle(base::GetCurrentProcessHandle(), | 330 if (!DuplicateHandle(base::GetCurrentProcessHandle(), |
295 reinterpret_cast<HANDLE>( | 331 reinterpret_cast<HANDLE>( |
296 internal_->sockets_for_renderer[i]), | 332 internal_->sockets_for_renderer[i]), |
297 chrome_render_message_filter_->peer_handle(), | 333 chrome_render_message_filter_->peer_handle(), |
298 &handle_in_renderer, | 334 &handle_in_renderer, |
(...skipping 39 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
338 | 374 |
339 ChromeViewHostMsg_LaunchNaCl::WriteReplyParams( | 375 ChromeViewHostMsg_LaunchNaCl::WriteReplyParams( |
340 reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id); | 376 reply_msg_, handles_for_renderer, nacl_process_handle, nacl_process_id); |
341 chrome_render_message_filter_->Send(reply_msg_); | 377 chrome_render_message_filter_->Send(reply_msg_); |
342 chrome_render_message_filter_ = NULL; | 378 chrome_render_message_filter_ = NULL; |
343 reply_msg_ = NULL; | 379 reply_msg_ = NULL; |
344 internal_->sockets_for_renderer.clear(); | 380 internal_->sockets_for_renderer.clear(); |
345 | 381 |
346 std::vector<nacl::FileDescriptor> handles_for_sel_ldr; | 382 std::vector<nacl::FileDescriptor> handles_for_sel_ldr; |
347 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) { | 383 for (size_t i = 0; i < internal_->sockets_for_sel_ldr.size(); i++) { |
348 #if defined(OS_WIN) | 384 if (!SendHandleToSelLdr(handle(), |
349 HANDLE channel; | 385 internal_->sockets_for_sel_ldr[i], true, |
350 if (!DuplicateHandle(GetCurrentProcess(), | 386 &handles_for_sel_ldr)) { |
351 reinterpret_cast<HANDLE>( | |
352 internal_->sockets_for_sel_ldr[i]), | |
353 handle(), | |
354 &channel, | |
355 0, // Unused given DUPLICATE_SAME_ACCESS. | |
356 FALSE, | |
357 DUPLICATE_CLOSE_SOURCE | DUPLICATE_SAME_ACCESS)) { | |
358 LOG(ERROR) << "DuplicateHandle() failed"; | |
359 delete this; | 387 delete this; |
360 return; | 388 return; |
361 } | 389 } |
362 handles_for_sel_ldr.push_back( | 390 } |
363 reinterpret_cast<nacl::FileDescriptor>(channel)); | 391 |
364 #else | 392 // Send over the IRT file handle. We don't close our own copy! |
365 nacl::FileDescriptor channel; | 393 if (!SendHandleToSelLdr(handle(), irt_file, false, &handles_for_sel_ldr)) { |
366 channel.fd = internal_->sockets_for_sel_ldr[i]; | 394 delete this; |
367 channel.auto_close = true; | 395 return; |
368 handles_for_sel_ldr.push_back(channel); | |
369 #endif | |
370 } | 396 } |
371 | 397 |
372 #if defined(OS_MACOSX) | 398 #if defined(OS_MACOSX) |
373 // For dynamic loading support, NaCl requires a file descriptor that | 399 // For dynamic loading support, NaCl requires a file descriptor that |
374 // was created in /tmp, since those created with shm_open() are not | 400 // was created in /tmp, since those created with shm_open() are not |
375 // mappable with PROT_EXEC. Rather than requiring an extra IPC | 401 // mappable with PROT_EXEC. Rather than requiring an extra IPC |
376 // round trip out of the sandbox, we create an FD here. | 402 // round trip out of the sandbox, we create an FD here. |
377 base::SharedMemory memory_buffer; | 403 base::SharedMemory memory_buffer; |
378 if (!memory_buffer.CreateAnonymous(/* size= */ 1)) { | 404 if (!memory_buffer.CreateAnonymous(/* size= */ 1)) { |
379 LOG(ERROR) << "Failed to allocate memory buffer"; | 405 LOG(ERROR) << "Failed to allocate memory buffer"; |
380 delete this; | 406 delete this; |
381 return; | 407 return; |
382 } | 408 } |
383 nacl::FileDescriptor memory_fd; | 409 nacl::FileDescriptor memory_fd; |
384 memory_fd.fd = dup(memory_buffer.handle().fd); | 410 memory_fd.fd = dup(memory_buffer.handle().fd); |
385 if (memory_fd.fd < 0) { | 411 if (memory_fd.fd < 0) { |
386 LOG(ERROR) << "Failed to dup() a file descriptor"; | 412 LOG(ERROR) << "Failed to dup() a file descriptor"; |
387 delete this; | 413 delete this; |
388 return; | 414 return; |
389 } | 415 } |
390 memory_fd.auto_close = true; | 416 memory_fd.auto_close = true; |
391 handles_for_sel_ldr.push_back(memory_fd); | 417 handles_for_sel_ldr.push_back(memory_fd); |
392 #endif | 418 #endif |
393 | 419 |
394 Send(new NaClProcessMsg_Start(handles_for_sel_ldr, have_irt_file)); | 420 Send(new NaClProcessMsg_Start(handles_for_sel_ldr)); |
395 internal_->sockets_for_sel_ldr.clear(); | 421 internal_->sockets_for_sel_ldr.clear(); |
396 } | 422 } |
397 | 423 |
398 bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) { | 424 bool NaClProcessHost::OnMessageReceived(const IPC::Message& msg) { |
399 NOTREACHED() << "Invalid message with type = " << msg.type(); | 425 NOTREACHED() << "Invalid message with type = " << msg.type(); |
400 return false; | 426 return false; |
401 } | 427 } |
402 | 428 |
403 bool NaClProcessHost::CanShutdown() { | 429 bool NaClProcessHost::CanShutdown() { |
404 return true; | 430 return true; |
405 } | 431 } |
OLD | NEW |