| OLD | NEW |
| 1 // Copyright (c) 2010 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2010 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 <dirent.h> | 5 #include <dirent.h> |
| 6 #include <errno.h> | 6 #include <errno.h> |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <signal.h> | 8 #include <signal.h> |
| 9 #include <stdlib.h> | 9 #include <stdlib.h> |
| 10 #include <sys/resource.h> | 10 #include <sys/resource.h> |
| (...skipping 14 matching lines...) Expand all Loading... |
| 25 #include "base/platform_thread.h" | 25 #include "base/platform_thread.h" |
| 26 #include "base/process_util.h" | 26 #include "base/process_util.h" |
| 27 #include "base/scoped_ptr.h" | 27 #include "base/scoped_ptr.h" |
| 28 #include "base/stringprintf.h" | 28 #include "base/stringprintf.h" |
| 29 #include "base/time.h" | 29 #include "base/time.h" |
| 30 #include "base/waitable_event.h" | 30 #include "base/waitable_event.h" |
| 31 | 31 |
| 32 #if defined(OS_MACOSX) | 32 #if defined(OS_MACOSX) |
| 33 #include <crt_externs.h> | 33 #include <crt_externs.h> |
| 34 #define environ (*_NSGetEnviron()) | 34 #define environ (*_NSGetEnviron()) |
| 35 #include "base/mach_ipc_mac.h" | |
| 36 #include "base/rand_util.h" | |
| 37 #else | 35 #else |
| 38 extern char** environ; | 36 extern char** environ; |
| 39 #endif | 37 #endif |
| 40 | 38 |
| 41 namespace base { | 39 namespace base { |
| 42 | 40 |
| 43 namespace { | 41 namespace { |
| 44 | 42 |
| 45 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, | 43 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, |
| 46 bool* success) { | 44 bool* success) { |
| (...skipping 247 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 294 // own use and will complain if we try to close them. All of | 292 // own use and will complain if we try to close them. All of |
| 295 // these FDs are >= |max_fds|, so we can check against that here | 293 // these FDs are >= |max_fds|, so we can check against that here |
| 296 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 | 294 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 |
| 297 if (fd < static_cast<int>(max_fds)) { | 295 if (fd < static_cast<int>(max_fds)) { |
| 298 int ret = HANDLE_EINTR(close(fd)); | 296 int ret = HANDLE_EINTR(close(fd)); |
| 299 DPCHECK(ret == 0); | 297 DPCHECK(ret == 0); |
| 300 } | 298 } |
| 301 } | 299 } |
| 302 } | 300 } |
| 303 | 301 |
| 304 #if defined(OS_MACOSX) | |
| 305 static std::string MachErrorCode(kern_return_t err) { | |
| 306 return StringPrintf("0x%x %s", err, mach_error_string(err)); | |
| 307 } | |
| 308 | |
| 309 // Forks the current process and returns the child's |task_t| in the parent | |
| 310 // process. | |
| 311 static pid_t fork_and_get_task(task_t* child_task) { | |
| 312 const int kTimeoutMs = 100; | |
| 313 kern_return_t err; | |
| 314 | |
| 315 // Put a random number into the channel name, so that a compromised renderer | |
| 316 // can't pretend being the child that's forked off. | |
| 317 std::string mach_connection_name = StringPrintf( | |
| 318 "com.google.Chrome.samplingfork.%p.%d", | |
| 319 child_task, base::RandInt(0, std::numeric_limits<int>::max())); | |
| 320 | |
| 321 // Create the mach receive port before forking to ensure that it exists when | |
| 322 // the child tries to connect. Mach ports are not duped into the child, so | |
| 323 // this is safe to set up here. | |
| 324 ReceivePort parent_recv_port(mach_connection_name.c_str()); | |
| 325 | |
| 326 // Error handling philosophy: If Mach IPC fails, don't touch |child_task| but | |
| 327 // return a valid pid. If IPC fails in the child, the parent will have to wait | |
| 328 // until kTimeoutMs is over. This is not optimal, but I've never seen it | |
| 329 // happen, and stuff should still mostly work. | |
| 330 pid_t pid = fork(); | |
| 331 switch (pid) { | |
| 332 case -1: | |
| 333 return pid; | |
| 334 case 0: { // child | |
| 335 // Must reset signal handlers before doing any mach IPC, as the mach IPC | |
| 336 // calls can potentially hang forever. | |
| 337 ResetChildSignalHandlersToDefaults(); | |
| 338 MachSendMessage child_message(/* id= */0); | |
| 339 if (!child_message.AddDescriptor(mach_task_self())) { | |
| 340 LOG(ERROR) << "child AddDescriptor(mach_task_self()) failed."; | |
| 341 return pid; | |
| 342 } | |
| 343 | |
| 344 MachPortSender child_sender(mach_connection_name.c_str()); | |
| 345 err = child_sender.SendMessage(child_message, kTimeoutMs); | |
| 346 if (err != KERN_SUCCESS) { | |
| 347 LOG(ERROR) << "child SendMessage() failed: " << MachErrorCode(err); | |
| 348 return pid; | |
| 349 } | |
| 350 break; | |
| 351 } | |
| 352 default: { // parent | |
| 353 MachReceiveMessage child_message; | |
| 354 err = parent_recv_port.WaitForMessage(&child_message, kTimeoutMs); | |
| 355 if (err != KERN_SUCCESS) { | |
| 356 LOG(ERROR) << "parent WaitForMessage() failed: " << MachErrorCode(err); | |
| 357 return pid; | |
| 358 } | |
| 359 | |
| 360 if (child_message.GetTranslatedPort(0) == MACH_PORT_NULL) { | |
| 361 LOG(ERROR) << "parent GetTranslatedPort(0) failed."; | |
| 362 return pid; | |
| 363 } | |
| 364 *child_task = child_message.GetTranslatedPort(0); | |
| 365 break; | |
| 366 } | |
| 367 } | |
| 368 return pid; | |
| 369 } | |
| 370 | |
| 371 bool LaunchApp(const std::vector<std::string>& argv, | |
| 372 const environment_vector& env_changes, | |
| 373 const file_handle_mapping_vector& fds_to_remap, | |
| 374 bool wait, ProcessHandle* process_handle) { | |
| 375 return LaunchAppAndGetTask( | |
| 376 argv, env_changes, fds_to_remap, wait, NULL, process_handle); | |
| 377 } | |
| 378 #endif // defined(OS_MACOSX) | |
| 379 | |
| 380 char** AlterEnvironment(const environment_vector& changes, | 302 char** AlterEnvironment(const environment_vector& changes, |
| 381 const char* const* const env) { | 303 const char* const* const env) { |
| 382 unsigned count = 0; | 304 unsigned count = 0; |
| 383 unsigned size = 0; | 305 unsigned size = 0; |
| 384 | 306 |
| 385 // First assume that all of the current environment will be included. | 307 // First assume that all of the current environment will be included. |
| 386 for (unsigned i = 0; env[i]; i++) { | 308 for (unsigned i = 0; env[i]; i++) { |
| 387 const char *const pair = env[i]; | 309 const char *const pair = env[i]; |
| 388 count++; | 310 count++; |
| 389 size += strlen(pair) + 1 /* terminating NUL */; | 311 size += strlen(pair) + 1 /* terminating NUL */; |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 491 *scratch++ = '='; | 413 *scratch++ = '='; |
| 492 memcpy(scratch, j->second.c_str(), j->second.size() + 1); | 414 memcpy(scratch, j->second.c_str(), j->second.size() + 1); |
| 493 scratch += j->second.size() + 1; | 415 scratch += j->second.size() + 1; |
| 494 } | 416 } |
| 495 } | 417 } |
| 496 | 418 |
| 497 ret[k] = NULL; | 419 ret[k] = NULL; |
| 498 return ret; | 420 return ret; |
| 499 } | 421 } |
| 500 | 422 |
| 501 #if defined(OS_MACOSX) | |
| 502 bool LaunchAppAndGetTask( | |
| 503 #else | |
| 504 bool LaunchApp( | 423 bool LaunchApp( |
| 505 #endif | |
| 506 const std::vector<std::string>& argv, | 424 const std::vector<std::string>& argv, |
| 507 const environment_vector& env_changes, | 425 const environment_vector& env_changes, |
| 508 const file_handle_mapping_vector& fds_to_remap, | 426 const file_handle_mapping_vector& fds_to_remap, |
| 509 bool wait, | 427 bool wait, |
| 510 #if defined(OS_MACOSX) | |
| 511 task_t* task_handle, | |
| 512 #endif | |
| 513 ProcessHandle* process_handle) { | 428 ProcessHandle* process_handle) { |
| 514 pid_t pid; | 429 pid_t pid; |
| 515 InjectiveMultimap fd_shuffle1, fd_shuffle2; | 430 InjectiveMultimap fd_shuffle1, fd_shuffle2; |
| 516 fd_shuffle1.reserve(fds_to_remap.size()); | 431 fd_shuffle1.reserve(fds_to_remap.size()); |
| 517 fd_shuffle2.reserve(fds_to_remap.size()); | 432 fd_shuffle2.reserve(fds_to_remap.size()); |
| 518 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); | 433 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); |
| 519 scoped_array<char*> new_environ(AlterEnvironment(env_changes, environ)); | 434 scoped_array<char*> new_environ(AlterEnvironment(env_changes, environ)); |
| 520 | 435 |
| 521 #if defined(OS_MACOSX) | |
| 522 if (task_handle == NULL) { | |
| 523 pid = fork(); | |
| 524 } else { | |
| 525 // On OS X, the task_t for a process is needed for several reasons. Sadly, | |
| 526 // the function task_for_pid() requires privileges a normal user doesn't | |
| 527 // have. Instead, a short-lived Mach IPC connection is opened between parent | |
| 528 // and child, and the child sends its task_t to the parent at fork time. | |
| 529 *task_handle = MACH_PORT_NULL; | |
| 530 pid = fork_and_get_task(task_handle); | |
| 531 } | |
| 532 #else | |
| 533 pid = fork(); | 436 pid = fork(); |
| 534 #endif | |
| 535 if (pid < 0) | 437 if (pid < 0) |
| 536 return false; | 438 return false; |
| 537 | 439 |
| 538 if (pid == 0) { | 440 if (pid == 0) { |
| 539 // Child process | 441 // Child process |
| 540 #if defined(OS_MACOSX) | 442 #if defined(OS_MACOSX) |
| 541 RestoreDefaultExceptionHandler(); | 443 RestoreDefaultExceptionHandler(); |
| 542 #endif | 444 #endif |
| 543 | 445 |
| 544 // On mac, the signal handlers are reset in |fork_and_get_task()|. | |
| 545 #if !defined(OS_MACOSX) | |
| 546 ResetChildSignalHandlersToDefaults(); | 446 ResetChildSignalHandlersToDefaults(); |
| 547 #endif | |
| 548 | 447 |
| 549 #if 0 | 448 #if 0 |
| 550 // When debugging it can be helpful to check that we really aren't making | 449 // When debugging it can be helpful to check that we really aren't making |
| 551 // any hidden calls to malloc. | 450 // any hidden calls to malloc. |
| 552 void *malloc_thunk = | 451 void *malloc_thunk = |
| 553 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095); | 452 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095); |
| 554 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); | 453 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); |
| 555 memset(reinterpret_cast<void*>(malloc), 0xff, 8); | 454 memset(reinterpret_cast<void*>(malloc), 0xff, 8); |
| 556 #endif | 455 #endif |
| 557 | 456 |
| (...skipping 352 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 910 const ProcessFilter* filter) { | 809 const ProcessFilter* filter) { |
| 911 bool exited_cleanly = | 810 bool exited_cleanly = |
| 912 WaitForProcessesToExit(executable_name, wait_milliseconds, | 811 WaitForProcessesToExit(executable_name, wait_milliseconds, |
| 913 filter); | 812 filter); |
| 914 if (!exited_cleanly) | 813 if (!exited_cleanly) |
| 915 KillProcesses(executable_name, exit_code, filter); | 814 KillProcesses(executable_name, exit_code, filter); |
| 916 return exited_cleanly; | 815 return exited_cleanly; |
| 917 } | 816 } |
| 918 | 817 |
| 919 } // namespace base | 818 } // namespace base |
| OLD | NEW |