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 |