Chromium Code Reviews| 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 189 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 200 static const char kFDDir[] = "/dev/fd"; | 200 static const char kFDDir[] = "/dev/fd"; |
| 201 #elif defined(OS_FREEBSD) | 201 #elif defined(OS_FREEBSD) |
| 202 static const char kFDDir[] = "/dev/fd"; | 202 static const char kFDDir[] = "/dev/fd"; |
| 203 #elif defined(OS_OPENBSD) | 203 #elif defined(OS_OPENBSD) |
| 204 static const char kFDDir[] = "/dev/fd"; | 204 static const char kFDDir[] = "/dev/fd"; |
| 205 #elif defined(OS_ANDROID) | 205 #elif defined(OS_ANDROID) |
| 206 static const char kFDDir[] = "/proc/self/fd"; | 206 static const char kFDDir[] = "/proc/self/fd"; |
| 207 #endif | 207 #endif |
| 208 | 208 |
| 209 void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) { | 209 void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) { |
| 210 // DANGER: no calls to malloc are allowed from now on: | 210 // DANGER: no calls to malloc or locks are allowed from now on: |
| 211 // http://crbug.com/36678 | 211 // http://crbug.com/36678 |
| 212 | 212 |
| 213 // Get the maximum number of FDs possible. | 213 // Get the maximum number of FDs possible. |
| 214 size_t max_fds = GetMaxFds(); | 214 size_t max_fds = GetMaxFds(); |
| 215 | 215 |
| 216 DirReaderPosix fd_dir(kFDDir); | 216 DirReaderPosix fd_dir(kFDDir); |
| 217 if (!fd_dir.IsValid()) { | 217 if (!fd_dir.IsValid()) { |
| 218 // Fallback case: Try every possible fd. | 218 // Fallback case: Try every possible fd. |
| 219 for (size_t i = 0; i < max_fds; ++i) { | 219 for (size_t i = 0; i < max_fds; ++i) { |
| 220 const int fd = static_cast<int>(i); | 220 const int fd = static_cast<int>(i); |
| 221 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) | 221 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) |
| 222 continue; | 222 continue; |
| 223 InjectiveMultimap::const_iterator j; | 223 // Cannot use STL iterators here, since debug iterators use locks. |
| 224 for (j = saved_mapping.begin(); j != saved_mapping.end(); j++) { | 224 size_t j; |
| 225 if (fd == j->dest) | 225 for (j = 0; j < saved_mapping.size(); j++) { |
| 226 if (fd == saved_mapping[j].dest) | |
| 226 break; | 227 break; |
| 227 } | 228 } |
| 228 if (j != saved_mapping.end()) | 229 if (j < saved_mapping.size()) |
| 229 continue; | 230 continue; |
| 230 | 231 |
| 231 // Since we're just trying to close anything we can find, | 232 // Since we're just trying to close anything we can find, |
| 232 // ignore any error return values of close(). | 233 // ignore any error return values of close(). |
| 233 close(fd); | 234 close(fd); |
| 234 } | 235 } |
| 235 return; | 236 return; |
| 236 } | 237 } |
| 237 | 238 |
| 238 const int dir_fd = fd_dir.fd(); | 239 const int dir_fd = fd_dir.fd(); |
| 239 | 240 |
| 240 for ( ; fd_dir.Next(); ) { | 241 for ( ; fd_dir.Next(); ) { |
| 241 // Skip . and .. entries. | 242 // Skip . and .. entries. |
| 242 if (fd_dir.name()[0] == '.') | 243 if (fd_dir.name()[0] == '.') |
| 243 continue; | 244 continue; |
| 244 | 245 |
| 245 char *endptr; | 246 char *endptr; |
| 246 errno = 0; | 247 errno = 0; |
| 247 const long int fd = strtol(fd_dir.name(), &endptr, 10); | 248 const long int fd = strtol(fd_dir.name(), &endptr, 10); |
| 248 if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno) | 249 if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno) |
| 249 continue; | 250 continue; |
| 250 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) | 251 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) |
| 251 continue; | 252 continue; |
| 252 InjectiveMultimap::const_iterator i; | 253 // Cannot use STL iterators here, since debug iterators use locks. |
| 253 for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) { | 254 size_t i; |
| 254 if (fd == i->dest) | 255 for (i = 0; i < saved_mapping.size(); i++) { |
| 256 if (fd == saved_mapping[i].dest) | |
| 255 break; | 257 break; |
| 256 } | 258 } |
| 257 if (i != saved_mapping.end()) | 259 if (i < saved_mapping.size()) |
| 258 continue; | 260 continue; |
| 259 if (fd == dir_fd) | 261 if (fd == dir_fd) |
| 260 continue; | 262 continue; |
| 261 | 263 |
| 262 // When running under Valgrind, Valgrind opens several FDs for its | 264 // When running under Valgrind, Valgrind opens several FDs for its |
| 263 // own use and will complain if we try to close them. All of | 265 // own use and will complain if we try to close them. All of |
| 264 // these FDs are >= |max_fds|, so we can check against that here | 266 // these FDs are >= |max_fds|, so we can check against that here |
| 265 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 | 267 // before closing. See https://bugs.kde.org/show_bug.cgi?id=191758 |
| 266 if (fd < static_cast<int>(max_fds)) { | 268 if (fd < static_cast<int>(max_fds)) { |
| 267 int ret = IGNORE_EINTR(close(fd)); | 269 int ret = IGNORE_EINTR(close(fd)); |
| (...skipping 113 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 381 | 383 |
| 382 #if 0 | 384 #if 0 |
| 383 // When debugging it can be helpful to check that we really aren't making | 385 // When debugging it can be helpful to check that we really aren't making |
| 384 // any hidden calls to malloc. | 386 // any hidden calls to malloc. |
| 385 void *malloc_thunk = | 387 void *malloc_thunk = |
| 386 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095); | 388 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095); |
| 387 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); | 389 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); |
| 388 memset(reinterpret_cast<void*>(malloc), 0xff, 8); | 390 memset(reinterpret_cast<void*>(malloc), 0xff, 8); |
| 389 #endif // 0 | 391 #endif // 0 |
| 390 | 392 |
| 391 // DANGER: no calls to malloc are allowed from now on: | 393 // DANGER: no calls to malloc or locks are allowed from now on: |
| 392 // http://crbug.com/36678 | 394 // http://crbug.com/36678 |
| 393 | 395 |
| 394 #if defined(OS_CHROMEOS) | 396 #if defined(OS_CHROMEOS) |
| 395 if (options.ctrl_terminal_fd >= 0) { | 397 if (options.ctrl_terminal_fd >= 0) { |
| 396 // Set process' controlling terminal. | 398 // Set process' controlling terminal. |
| 397 if (HANDLE_EINTR(setsid()) != -1) { | 399 if (HANDLE_EINTR(setsid()) != -1) { |
| 398 if (HANDLE_EINTR( | 400 if (HANDLE_EINTR( |
| 399 ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) { | 401 ioctl(options.ctrl_terminal_fd, TIOCSCTTY, NULL)) == -1) { |
| 400 RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set"); | 402 RAW_LOG(WARNING, "ioctl(TIOCSCTTY), ctrl terminal not set"); |
| 401 } | 403 } |
| 402 } else { | 404 } else { |
| 403 RAW_LOG(WARNING, "setsid failed, ctrl terminal not set"); | 405 RAW_LOG(WARNING, "setsid failed, ctrl terminal not set"); |
| 404 } | 406 } |
| 405 } | 407 } |
| 406 #endif // defined(OS_CHROMEOS) | 408 #endif // defined(OS_CHROMEOS) |
| 407 | 409 |
| 408 if (options.fds_to_remap) { | 410 if (options.fds_to_remap) { |
| 409 for (FileHandleMappingVector::const_iterator | 411 // Cannot use STL iterators here, since debug iterators use locks. |
| 410 it = options.fds_to_remap->begin(); | 412 for (size_t i = 0; i < options.fds_to_remap->size(); ++i) { |
| 411 it != options.fds_to_remap->end(); ++it) { | 413 const FileHandleMappingVector::value_type& value = |
| 412 fd_shuffle1.push_back(InjectionArc(it->first, it->second, false)); | 414 (*options.fds_to_remap)[i]; |
| 413 fd_shuffle2.push_back(InjectionArc(it->first, it->second, false)); | 415 fd_shuffle1.push_back(InjectionArc(value.first, value.second, false)); |
| 416 fd_shuffle2.push_back(InjectionArc(value.first, value.second, false)); | |
| 414 } | 417 } |
| 415 } | 418 } |
| 416 | 419 |
| 417 if (!options.environ.empty()) | 420 if (!options.environ.empty()) |
| 418 SetEnvironment(new_environ.get()); | 421 SetEnvironment(new_environ.get()); |
| 419 | 422 |
| 420 // fd_shuffle1 is mutated by this call because it cannot malloc. | 423 // fd_shuffle1 is mutated by this call because it cannot malloc. |
| 421 if (!ShuffleFileDescriptors(&fd_shuffle1)) | 424 if (!ShuffleFileDescriptors(&fd_shuffle1)) |
| 422 _exit(127); | 425 _exit(127); |
| 423 | 426 |
| (...skipping 90 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 514 switch (pid = fork()) { | 517 switch (pid = fork()) { |
| 515 case -1: // error | 518 case -1: // error |
| 516 close(pipe_fd[0]); | 519 close(pipe_fd[0]); |
| 517 close(pipe_fd[1]); | 520 close(pipe_fd[1]); |
| 518 return EXECUTE_FAILURE; | 521 return EXECUTE_FAILURE; |
| 519 case 0: // child | 522 case 0: // child |
| 520 { | 523 { |
| 521 #if defined(OS_MACOSX) | 524 #if defined(OS_MACOSX) |
| 522 RestoreDefaultExceptionHandler(); | 525 RestoreDefaultExceptionHandler(); |
| 523 #endif | 526 #endif |
| 524 // DANGER: no calls to malloc are allowed from now on: | 527 // DANGER: no calls to malloc or locks are allowed from now on: |
| 525 // http://crbug.com/36678 | 528 // http://crbug.com/36678 |
| 526 | 529 |
| 527 // Obscure fork() rule: in the child, if you don't end up doing exec*(), | 530 // Obscure fork() rule: in the child, if you don't end up doing exec*(), |
| 528 // you call _exit() instead of exit(). This is because _exit() does not | 531 // you call _exit() instead of exit(). This is because _exit() does not |
| 529 // call any previously-registered (in the parent) exit handlers, which | 532 // call any previously-registered (in the parent) exit handlers, which |
| 530 // might do things like block waiting for threads that don't even exist | 533 // might do things like block waiting for threads that don't even exist |
| 531 // in the child. | 534 // in the child. |
| 532 int dev_null = open("/dev/null", O_WRONLY); | 535 int dev_null = open("/dev/null", O_WRONLY); |
| 533 if (dev_null < 0) | 536 if (dev_null < 0) |
| 534 _exit(127); | 537 _exit(127); |
| 535 | 538 |
| 536 // Stop type-profiler. | 539 // Stop type-profiler. |
| 537 // The profiler should be stopped between fork and exec since it inserts | 540 // The profiler should be stopped between fork and exec since it inserts |
| 538 // locks at new/delete expressions. See http://crbug.com/36678. | 541 // locks at new/delete expressions. See http://crbug.com/36678. |
| 539 base::type_profiler::Controller::Stop(); | 542 base::type_profiler::Controller::Stop(); |
| 540 | 543 |
| 541 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); | 544 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); |
| 542 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); | 545 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); |
| 543 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); | 546 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); |
| 544 // Adding another element here? Remeber to increase the argument to | 547 // Adding another element here? Remeber to increase the argument to |
| 545 // reserve(), above. | 548 // reserve(), above. |
| 546 | 549 |
| 547 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(), | 550 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(), |
|
Elliot Glaysher
2014/01/07 22:33:14
So maybe I'm wrong here, but isn't this using stl
mattm
2014/01/07 22:43:40
Oh, yeah. I missed this one and I must not have be
| |
| 548 std::back_inserter(fd_shuffle2)); | 551 std::back_inserter(fd_shuffle2)); |
| 549 | 552 |
| 550 if (!ShuffleFileDescriptors(&fd_shuffle1)) | 553 if (!ShuffleFileDescriptors(&fd_shuffle1)) |
| 551 _exit(127); | 554 _exit(127); |
| 552 | 555 |
| 553 CloseSuperfluousFds(fd_shuffle2); | 556 CloseSuperfluousFds(fd_shuffle2); |
| 554 | 557 |
| 555 for (size_t i = 0; i < argv.size(); i++) | 558 for (size_t i = 0; i < argv.size(); i++) |
| 556 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); | 559 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); |
| 557 argv_cstr[argv.size()] = NULL; | 560 argv_cstr[argv.size()] = NULL; |
| (...skipping 71 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 629 std::string* output, | 632 std::string* output, |
| 630 int* exit_code) { | 633 int* exit_code) { |
| 631 // Run |execve()| with the current environment and store "unlimited" data. | 634 // Run |execve()| with the current environment and store "unlimited" data. |
| 632 GetAppOutputInternalResult result = GetAppOutputInternal( | 635 GetAppOutputInternalResult result = GetAppOutputInternal( |
| 633 cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true, | 636 cl.argv(), NULL, output, std::numeric_limits<std::size_t>::max(), true, |
| 634 exit_code); | 637 exit_code); |
| 635 return result == EXECUTE_SUCCESS; | 638 return result == EXECUTE_SUCCESS; |
| 636 } | 639 } |
| 637 | 640 |
| 638 } // namespace base | 641 } // namespace base |
| OLD | NEW |