| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 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 | 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 "base/process/launch.h" | 5 #include "base/process/launch.h" |
| 6 | 6 |
| 7 #include <dirent.h> | 7 #include <dirent.h> |
| 8 #include <errno.h> | 8 #include <errno.h> |
| 9 #include <fcntl.h> | 9 #include <fcntl.h> |
| 10 #include <signal.h> | 10 #include <signal.h> |
| (...skipping 259 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 270 // own use and will complain if we try to close them. All of | 270 // own use and will complain if we try to close them. All of |
| 271 // these FDs are >= |max_fds|, so we can check against that here | 271 // these FDs are >= |max_fds|, so we can check against that here |
| 272 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 | 272 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 |
| 273 if (fd < static_cast<int>(max_fds)) { | 273 if (fd < static_cast<int>(max_fds)) { |
| 274 int ret = IGNORE_EINTR(close(fd)); | 274 int ret = IGNORE_EINTR(close(fd)); |
| 275 DPCHECK(ret == 0); | 275 DPCHECK(ret == 0); |
| 276 } | 276 } |
| 277 } | 277 } |
| 278 } | 278 } |
| 279 | 279 |
| 280 bool LaunchProcess(const std::vector<std::string>& argv, | 280 Process LaunchProcess(const CommandLine& cmdline, |
| 281 const LaunchOptions& options, | 281 const LaunchOptions& options) { |
| 282 ProcessHandle* process_handle) { | 282 return LaunchProcess(cmdline.argv(), options); |
| 283 } |
| 284 |
| 285 Process LaunchProcess(const std::vector<std::string>& argv, |
| 286 const LaunchOptions& options) { |
| 283 size_t fd_shuffle_size = 0; | 287 size_t fd_shuffle_size = 0; |
| 284 if (options.fds_to_remap) { | 288 if (options.fds_to_remap) { |
| 285 fd_shuffle_size = options.fds_to_remap->size(); | 289 fd_shuffle_size = options.fds_to_remap->size(); |
| 286 } | 290 } |
| 287 | 291 |
| 288 InjectiveMultimap fd_shuffle1; | 292 InjectiveMultimap fd_shuffle1; |
| 289 InjectiveMultimap fd_shuffle2; | 293 InjectiveMultimap fd_shuffle2; |
| 290 fd_shuffle1.reserve(fd_shuffle_size); | 294 fd_shuffle1.reserve(fd_shuffle_size); |
| 291 fd_shuffle2.reserve(fd_shuffle_size); | 295 fd_shuffle2.reserve(fd_shuffle_size); |
| 292 | 296 |
| (...skipping 11 matching lines...) Expand all Loading... |
| 304 const sigset_t orig_sigmask = SetSignalMask(full_sigset); | 308 const sigset_t orig_sigmask = SetSignalMask(full_sigset); |
| 305 | 309 |
| 306 pid_t pid; | 310 pid_t pid; |
| 307 #if defined(OS_LINUX) | 311 #if defined(OS_LINUX) |
| 308 if (options.clone_flags) { | 312 if (options.clone_flags) { |
| 309 // Signal handling in this function assumes the creation of a new | 313 // Signal handling in this function assumes the creation of a new |
| 310 // process, so we check that a thread is not being created by mistake | 314 // process, so we check that a thread is not being created by mistake |
| 311 // and that signal handling follows the process-creation rules. | 315 // and that signal handling follows the process-creation rules. |
| 312 RAW_CHECK( | 316 RAW_CHECK( |
| 313 !(options.clone_flags & (CLONE_SIGHAND | CLONE_THREAD | CLONE_VM))); | 317 !(options.clone_flags & (CLONE_SIGHAND | CLONE_THREAD | CLONE_VM))); |
| 314 pid = syscall(__NR_clone, options.clone_flags, 0, 0, 0); | 318 |
| 319 // We specify a null ptid and ctid. |
| 320 RAW_CHECK( |
| 321 !(options.clone_flags & |
| 322 (CLONE_CHILD_CLEARTID | CLONE_CHILD_SETTID | CLONE_PARENT_SETTID))); |
| 323 |
| 324 // Since we use waitpid, we do not support custom termination signals in the |
| 325 // clone flags. |
| 326 RAW_CHECK((options.clone_flags & 0xff) == 0); |
| 327 |
| 328 pid = ForkWithFlags(options.clone_flags | SIGCHLD, nullptr, nullptr); |
| 315 } else | 329 } else |
| 316 #endif | 330 #endif |
| 317 { | 331 { |
| 318 pid = fork(); | 332 pid = fork(); |
| 319 } | 333 } |
| 320 | 334 |
| 321 // Always restore the original signal mask in the parent. | 335 // Always restore the original signal mask in the parent. |
| 322 if (pid != 0) { | 336 if (pid != 0) { |
| 323 SetSignalMask(orig_sigmask); | 337 SetSignalMask(orig_sigmask); |
| 324 } | 338 } |
| 325 | 339 |
| 326 if (pid < 0) { | 340 if (pid < 0) { |
| 327 DPLOG(ERROR) << "fork"; | 341 DPLOG(ERROR) << "fork"; |
| 328 return false; | 342 return Process(); |
| 329 } else if (pid == 0) { | 343 } else if (pid == 0) { |
| 330 // Child process | 344 // Child process |
| 331 | 345 |
| 332 // DANGER: no calls to malloc or locks are allowed from now on: | 346 // DANGER: no calls to malloc or locks are allowed from now on: |
| 333 // http://crbug.com/36678 | 347 // http://crbug.com/36678 |
| 334 | 348 |
| 335 // DANGER: fork() rule: in the child, if you don't end up doing exec*(), | 349 // DANGER: fork() rule: in the child, if you don't end up doing exec*(), |
| 336 // you call _exit() instead of exit(). This is because _exit() does not | 350 // you call _exit() instead of exit(). This is because _exit() does not |
| 337 // call any previously-registered (in the parent) exit handlers, which | 351 // call any previously-registered (in the parent) exit handlers, which |
| 338 // might do things like block waiting for threads that don't even exist | 352 // might do things like block waiting for threads that don't even exist |
| (...skipping 102 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 441 #define PR_SET_NO_NEW_PRIVS 38 | 455 #define PR_SET_NO_NEW_PRIVS 38 |
| 442 #endif | 456 #endif |
| 443 if (!options.allow_new_privs) { | 457 if (!options.allow_new_privs) { |
| 444 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) && errno != EINVAL) { | 458 if (prctl(PR_SET_NO_NEW_PRIVS, 1, 0, 0, 0) && errno != EINVAL) { |
| 445 // Only log if the error is not EINVAL (i.e. not supported). | 459 // Only log if the error is not EINVAL (i.e. not supported). |
| 446 RAW_LOG(FATAL, "prctl(PR_SET_NO_NEW_PRIVS) failed"); | 460 RAW_LOG(FATAL, "prctl(PR_SET_NO_NEW_PRIVS) failed"); |
| 447 } | 461 } |
| 448 } | 462 } |
| 449 #endif | 463 #endif |
| 450 | 464 |
| 465 #if defined(OS_POSIX) |
| 466 if (options.pre_exec_delegate != nullptr) { |
| 467 options.pre_exec_delegate->RunAsyncSafe(); |
| 468 } |
| 469 #endif |
| 470 |
| 451 for (size_t i = 0; i < argv.size(); i++) | 471 for (size_t i = 0; i < argv.size(); i++) |
| 452 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); | 472 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); |
| 453 argv_cstr[argv.size()] = NULL; | 473 argv_cstr[argv.size()] = NULL; |
| 454 execvp(argv_cstr[0], argv_cstr.get()); | 474 execvp(argv_cstr[0], argv_cstr.get()); |
| 455 | 475 |
| 456 RAW_LOG(ERROR, "LaunchProcess: failed to execvp:"); | 476 RAW_LOG(ERROR, "LaunchProcess: failed to execvp:"); |
| 457 RAW_LOG(ERROR, argv_cstr[0]); | 477 RAW_LOG(ERROR, argv_cstr[0]); |
| 458 _exit(127); | 478 _exit(127); |
| 459 } else { | 479 } else { |
| 460 // Parent process | 480 // Parent process |
| 461 if (options.wait) { | 481 if (options.wait) { |
| 462 // While this isn't strictly disk IO, waiting for another process to | 482 // While this isn't strictly disk IO, waiting for another process to |
| 463 // finish is the sort of thing ThreadRestrictions is trying to prevent. | 483 // finish is the sort of thing ThreadRestrictions is trying to prevent. |
| 464 base::ThreadRestrictions::AssertIOAllowed(); | 484 base::ThreadRestrictions::AssertIOAllowed(); |
| 465 pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0)); | 485 pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0)); |
| 466 DPCHECK(ret > 0); | 486 DPCHECK(ret > 0); |
| 467 } | 487 } |
| 468 | |
| 469 if (process_handle) | |
| 470 *process_handle = pid; | |
| 471 } | 488 } |
| 472 | 489 |
| 473 return true; | 490 return Process(pid); |
| 474 } | |
| 475 | |
| 476 Process LaunchProcess(const std::vector<std::string>& argv, | |
| 477 const LaunchOptions& options) { | |
| 478 ProcessHandle process_handle; | |
| 479 if (LaunchProcess(argv, options, &process_handle)) | |
| 480 return Process(process_handle); | |
| 481 | |
| 482 return Process(); | |
| 483 } | |
| 484 | |
| 485 | |
| 486 bool LaunchProcess(const CommandLine& cmdline, | |
| 487 const LaunchOptions& options, | |
| 488 ProcessHandle* process_handle) { | |
| 489 return LaunchProcess(cmdline.argv(), options, process_handle); | |
| 490 } | |
| 491 | |
| 492 Process LaunchProcess(const CommandLine& cmdline, | |
| 493 const LaunchOptions& options) { | |
| 494 ProcessHandle process_handle; | |
| 495 if (LaunchProcess(cmdline, options, &process_handle)) | |
| 496 return Process(process_handle); | |
| 497 | |
| 498 return Process(); | |
| 499 } | 491 } |
| 500 | 492 |
| 501 void RaiseProcessToHighPriority() { | 493 void RaiseProcessToHighPriority() { |
| 502 // On POSIX, we don't actually do anything here. We could try to nice() or | 494 // On POSIX, we don't actually do anything here. We could try to nice() or |
| 503 // setpriority() or sched_getscheduler, but these all require extra rights. | 495 // setpriority() or sched_getscheduler, but these all require extra rights. |
| 504 } | 496 } |
| 505 | 497 |
| 506 // Return value used by GetAppOutputInternal to encapsulate the various exit | 498 // Return value used by GetAppOutputInternal to encapsulate the various exit |
| 507 // scenarios from the function. | 499 // scenarios from the function. |
| 508 enum GetAppOutputInternalResult { | 500 enum GetAppOutputInternalResult { |
| (...skipping 164 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 673 std::string* output, | 665 std::string* output, |
| 674 int* exit_code) { | 666 int* exit_code) { |
| 675 // Run |execve()| with the current environment and store "unlimited" data. | 667 // Run |execve()| with the current environment and store "unlimited" data. |
| 676 GetAppOutputInternalResult result = GetAppOutputInternal( | 668 GetAppOutputInternalResult result = GetAppOutputInternal( |
| 677 cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true, | 669 cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true, |
| 678 exit_code); | 670 exit_code); |
| 679 return result == EXECUTE_SUCCESS; | 671 return result == EXECUTE_SUCCESS; |
| 680 } | 672 } |
| 681 | 673 |
| 682 } // namespace base | 674 } // namespace base |
| OLD | NEW |