| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 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> |
| 11 #include <sys/time.h> | 11 #include <sys/time.h> |
| 12 #include <sys/types.h> | 12 #include <sys/types.h> |
| 13 #include <sys/wait.h> | 13 #include <sys/wait.h> |
| 14 #include <unistd.h> | 14 #include <unistd.h> |
| 15 | 15 |
| 16 #include <limits> | 16 #include <limits> |
| 17 #include <set> | 17 #include <set> |
| 18 | 18 |
| 19 #include "base/compiler_specific.h" | 19 #include "base/compiler_specific.h" |
| 20 #include "base/debug_util.h" | 20 #include "base/debug_util.h" |
| 21 #include "base/dir_reader_posix.h" |
| 21 #include "base/eintr_wrapper.h" | 22 #include "base/eintr_wrapper.h" |
| 22 #include "base/logging.h" | 23 #include "base/logging.h" |
| 23 #include "base/platform_thread.h" | 24 #include "base/platform_thread.h" |
| 24 #include "base/process_util.h" | 25 #include "base/process_util.h" |
| 25 #include "base/rand_util.h" | 26 #include "base/rand_util.h" |
| 26 #include "base/scoped_ptr.h" | 27 #include "base/scoped_ptr.h" |
| 27 #include "base/sys_info.h" | 28 #include "base/sys_info.h" |
| 28 #include "base/time.h" | 29 #include "base/time.h" |
| 29 #include "base/waitable_event.h" | 30 #include "base/waitable_event.h" |
| 30 | 31 |
| 32 |
| 31 #if defined(OS_MACOSX) | 33 #if defined(OS_MACOSX) |
| 34 #include <crt_externs.h> |
| 35 #define environ (*_NSGetEnviron()) |
| 32 #include "base/mach_ipc_mac.h" | 36 #include "base/mach_ipc_mac.h" |
| 37 #else |
| 38 extern char** environ; |
| 33 #endif | 39 #endif |
| 34 | 40 |
| 35 const int kMicrosecondsPerSecond = 1000000; | 41 const int kMicrosecondsPerSecond = 1000000; |
| 36 | 42 |
| 37 namespace base { | 43 namespace base { |
| 38 | 44 |
| 39 namespace { | 45 namespace { |
| 40 | 46 |
| 41 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, | 47 int WaitpidWithTimeout(ProcessHandle handle, int64 wait_milliseconds, |
| 42 bool* success) { | 48 bool* success) { |
| (...skipping 123 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 166 class ScopedDIRClose { | 172 class ScopedDIRClose { |
| 167 public: | 173 public: |
| 168 inline void operator()(DIR* x) const { | 174 inline void operator()(DIR* x) const { |
| 169 if (x) { | 175 if (x) { |
| 170 closedir(x); | 176 closedir(x); |
| 171 } | 177 } |
| 172 } | 178 } |
| 173 }; | 179 }; |
| 174 typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR; | 180 typedef scoped_ptr_malloc<DIR, ScopedDIRClose> ScopedDIR; |
| 175 | 181 |
| 176 void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) { | |
| 177 #if defined(OS_LINUX) | 182 #if defined(OS_LINUX) |
| 178 static const rlim_t kSystemDefaultMaxFds = 8192; | 183 static const rlim_t kSystemDefaultMaxFds = 8192; |
| 179 static const char fd_dir[] = "/proc/self/fd"; | 184 static const char kFDDir[] = "/proc/self/fd"; |
| 180 #elif defined(OS_MACOSX) | 185 #elif defined(OS_MACOSX) |
| 181 static const rlim_t kSystemDefaultMaxFds = 256; | 186 static const rlim_t kSystemDefaultMaxFds = 256; |
| 182 static const char fd_dir[] = "/dev/fd"; | 187 static const char kFDDir[] = "/dev/fd"; |
| 183 #elif defined(OS_SOLARIS) | 188 #elif defined(OS_SOLARIS) |
| 184 static const rlim_t kSystemDefaultMaxFds = 8192; | 189 static const rlim_t kSystemDefaultMaxFds = 8192; |
| 185 static const char fd_dir[] = "/dev/fd"; | 190 static const char kFDDir[] = "/dev/fd"; |
| 186 #elif defined(OS_FREEBSD) | 191 #elif defined(OS_FREEBSD) |
| 187 static const rlim_t kSystemDefaultMaxFds = 8192; | 192 static const rlim_t kSystemDefaultMaxFds = 8192; |
| 188 static const char fd_dir[] = "/dev/fd"; | 193 static const char kFDDir[] = "/dev/fd"; |
| 189 #elif defined(OS_OPENBSD) | 194 #elif defined(OS_OPENBSD) |
| 190 static const rlim_t kSystemDefaultMaxFds = 256; | 195 static const rlim_t kSystemDefaultMaxFds = 256; |
| 191 static const char fd_dir[] = "/dev/fd"; | 196 static const char kFDDir[] = "/dev/fd"; |
| 192 #endif | 197 #endif |
| 193 std::set<int> saved_fds; | 198 |
| 199 void CloseSuperfluousFds(const base::InjectiveMultimap& saved_mapping) { |
| 200 // DANGER: no calls to malloc are allowed from now on: |
| 201 // http://crbug.com/36678 |
| 194 | 202 |
| 195 // Get the maximum number of FDs possible. | 203 // Get the maximum number of FDs possible. |
| 196 struct rlimit nofile; | 204 struct rlimit nofile; |
| 197 rlim_t max_fds; | 205 rlim_t max_fds; |
| 198 if (getrlimit(RLIMIT_NOFILE, &nofile)) { | 206 if (getrlimit(RLIMIT_NOFILE, &nofile)) { |
| 199 // getrlimit failed. Take a best guess. | 207 // getrlimit failed. Take a best guess. |
| 200 max_fds = kSystemDefaultMaxFds; | 208 max_fds = kSystemDefaultMaxFds; |
| 201 DLOG(ERROR) << "getrlimit(RLIMIT_NOFILE) failed: " << errno; | 209 DLOG(ERROR) << "getrlimit(RLIMIT_NOFILE) failed: " << errno; |
| 202 } else { | 210 } else { |
| 203 max_fds = nofile.rlim_cur; | 211 max_fds = nofile.rlim_cur; |
| 204 } | 212 } |
| 205 | 213 |
| 206 if (max_fds > INT_MAX) | 214 if (max_fds > INT_MAX) |
| 207 max_fds = INT_MAX; | 215 max_fds = INT_MAX; |
| 208 | 216 |
| 209 // Don't close stdin, stdout and stderr | 217 DirReaderPosix fd_dir(kFDDir); |
| 210 saved_fds.insert(STDIN_FILENO); | |
| 211 saved_fds.insert(STDOUT_FILENO); | |
| 212 saved_fds.insert(STDERR_FILENO); | |
| 213 | 218 |
| 214 for (base::InjectiveMultimap::const_iterator | 219 if (!fd_dir.IsValid()) { |
| 215 i = saved_mapping.begin(); i != saved_mapping.end(); ++i) { | |
| 216 saved_fds.insert(i->dest); | |
| 217 } | |
| 218 | |
| 219 ScopedDIR dir_closer(opendir(fd_dir)); | |
| 220 DIR *dir = dir_closer.get(); | |
| 221 if (NULL == dir) { | |
| 222 DLOG(ERROR) << "Unable to open " << fd_dir; | |
| 223 | |
| 224 // Fallback case: Try every possible fd. | 220 // Fallback case: Try every possible fd. |
| 225 for (rlim_t i = 0; i < max_fds; ++i) { | 221 for (rlim_t i = 0; i < max_fds; ++i) { |
| 226 const int fd = static_cast<int>(i); | 222 const int fd = static_cast<int>(i); |
| 227 if (saved_fds.find(fd) != saved_fds.end()) | 223 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) |
| 224 continue; |
| 225 InjectiveMultimap::const_iterator i; |
| 226 for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) { |
| 227 if (fd == i->dest) |
| 228 break; |
| 229 } |
| 230 if (i != saved_mapping.end()) |
| 228 continue; | 231 continue; |
| 229 | 232 |
| 230 // Since we're just trying to close anything we can find, | 233 // Since we're just trying to close anything we can find, |
| 231 // ignore any error return values of close(). | 234 // ignore any error return values of close(). |
| 232 int unused ALLOW_UNUSED = HANDLE_EINTR(close(fd)); | 235 int unused ALLOW_UNUSED = HANDLE_EINTR(close(fd)); |
| 233 } | 236 } |
| 234 return; | 237 return; |
| 235 } | 238 } |
| 236 int dir_fd = dirfd(dir); | |
| 237 | 239 |
| 238 struct dirent *ent; | 240 const int dir_fd = fd_dir.fd(); |
| 239 while ((ent = readdir(dir))) { | 241 |
| 242 for ( ; fd_dir.Next(); ) { |
| 240 // Skip . and .. entries. | 243 // Skip . and .. entries. |
| 241 if (ent->d_name[0] == '.') | 244 if (fd_dir.name()[0] == '.') |
| 242 continue; | 245 continue; |
| 243 | 246 |
| 244 char *endptr; | 247 char *endptr; |
| 245 errno = 0; | 248 errno = 0; |
| 246 const long int fd = strtol(ent->d_name, &endptr, 10); | 249 const long int fd = strtol(fd_dir.name(), &endptr, 10); |
| 247 if (ent->d_name[0] == 0 || *endptr || fd < 0 || errno) | 250 if (fd_dir.name()[0] == 0 || *endptr || fd < 0 || errno) |
| 248 continue; | 251 continue; |
| 249 if (saved_fds.find(fd) != saved_fds.end()) | 252 if (fd == STDIN_FILENO || fd == STDOUT_FILENO || fd == STDERR_FILENO) |
| 253 continue; |
| 254 InjectiveMultimap::const_iterator i; |
| 255 for (i = saved_mapping.begin(); i != saved_mapping.end(); i++) { |
| 256 if (fd == i->dest) |
| 257 break; |
| 258 } |
| 259 if (i != saved_mapping.end()) |
| 250 continue; | 260 continue; |
| 251 if (fd == dir_fd) | 261 if (fd == dir_fd) |
| 252 continue; | 262 continue; |
| 253 | 263 |
| 254 // When running under Valgrind, Valgrind opens several FDs for its | 264 // When running under Valgrind, Valgrind opens several FDs for its |
| 255 // 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 |
| 256 // 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 |
| 257 // 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 |
| 258 if (fd < static_cast<int>(max_fds)) { | 268 if (fd < static_cast<int>(max_fds)) { |
| 259 int ret = HANDLE_EINTR(close(fd)); | 269 int ret = HANDLE_EINTR(close(fd)); |
| 260 DPCHECK(ret == 0); | 270 DPCHECK(ret == 0); |
| 261 } | 271 } |
| 262 } | 272 } |
| 263 } | 273 } |
| 264 | 274 |
| 265 // Sets all file descriptors to close on exec except for stdin, stdout | |
| 266 // and stderr. | |
| 267 // TODO(agl): Remove this function. It's fundamentally broken for multithreaded | |
| 268 // apps. | |
| 269 void SetAllFDsToCloseOnExec() { | |
| 270 #if defined(OS_LINUX) | |
| 271 const char fd_dir[] = "/proc/self/fd"; | |
| 272 #elif defined(OS_MACOSX) || defined(OS_FREEBSD) || defined(OS_SOLARIS) | |
| 273 const char fd_dir[] = "/dev/fd"; | |
| 274 #endif | |
| 275 ScopedDIR dir_closer(opendir(fd_dir)); | |
| 276 DIR *dir = dir_closer.get(); | |
| 277 if (NULL == dir) { | |
| 278 DLOG(ERROR) << "Unable to open " << fd_dir; | |
| 279 return; | |
| 280 } | |
| 281 | |
| 282 struct dirent *ent; | |
| 283 while ((ent = readdir(dir))) { | |
| 284 // Skip . and .. entries. | |
| 285 if (ent->d_name[0] == '.') | |
| 286 continue; | |
| 287 int i = atoi(ent->d_name); | |
| 288 // We don't close stdin, stdout or stderr. | |
| 289 if (i <= STDERR_FILENO) | |
| 290 continue; | |
| 291 | |
| 292 int flags = fcntl(i, F_GETFD); | |
| 293 if ((flags == -1) || (fcntl(i, F_SETFD, flags | FD_CLOEXEC) == -1)) { | |
| 294 DLOG(ERROR) << "fcntl failure."; | |
| 295 } | |
| 296 } | |
| 297 } | |
| 298 | |
| 299 #if defined(OS_MACOSX) | 275 #if defined(OS_MACOSX) |
| 300 static std::string MachErrorCode(kern_return_t err) { | 276 static std::string MachErrorCode(kern_return_t err) { |
| 301 return StringPrintf("0x%x %s", err, mach_error_string(err)); | 277 return StringPrintf("0x%x %s", err, mach_error_string(err)); |
| 302 } | 278 } |
| 303 | 279 |
| 304 // Forks the current process and returns the child's |task_t| in the parent | 280 // Forks the current process and returns the child's |task_t| in the parent |
| 305 // process. | 281 // process. |
| 306 static pid_t fork_and_get_task(task_t* child_task) { | 282 static pid_t fork_and_get_task(task_t* child_task) { |
| 307 const int kTimeoutMs = 100; | 283 const int kTimeoutMs = 100; |
| 308 kern_return_t err; | 284 kern_return_t err; |
| (...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 350 return pid; | 326 return pid; |
| 351 } | 327 } |
| 352 *child_task = child_message.GetTranslatedPort(0); | 328 *child_task = child_message.GetTranslatedPort(0); |
| 353 break; | 329 break; |
| 354 } | 330 } |
| 355 } | 331 } |
| 356 return pid; | 332 return pid; |
| 357 } | 333 } |
| 358 | 334 |
| 359 bool LaunchApp(const std::vector<std::string>& argv, | 335 bool LaunchApp(const std::vector<std::string>& argv, |
| 360 const environment_vector& environ, | 336 const environment_vector& env_changes, |
| 361 const file_handle_mapping_vector& fds_to_remap, | 337 const file_handle_mapping_vector& fds_to_remap, |
| 362 bool wait, ProcessHandle* process_handle) { | 338 bool wait, ProcessHandle* process_handle) { |
| 363 return LaunchAppAndGetTask( | 339 return LaunchAppAndGetTask( |
| 364 argv, environ, fds_to_remap, wait, NULL, process_handle); | 340 argv, env_changes, fds_to_remap, wait, NULL, process_handle); |
| 365 } | 341 } |
| 366 #endif // defined(OS_MACOSX) | 342 #endif // defined(OS_MACOSX) |
| 367 | 343 |
| 344 // AlterEnvironment returns a modified environment vector, constructed from the |
| 345 // current environment and the list of changes given in |changes|. Each key in |
| 346 // the environment is matched against the first element of the pairs. In the |
| 347 // event of a match, the value is replaced by the second of the pair, unless |
| 348 // the second is empty, in which case the key-value is removed. |
| 349 // |
| 350 // The returned array is allocated using new[] and must be freed by the caller. |
| 351 // Additionally, the first element is also allocated using new[] and should be |
| 352 // freed by the caller. |
| 353 static char** AlterEnvironment(const environment_vector& changes) { |
| 354 unsigned count = 0; |
| 355 unsigned size = 0; |
| 356 |
| 357 for (unsigned i = 0; environ[i]; i++) { |
| 358 const char *const pair = environ[i]; |
| 359 const char *const equals = strchr(pair, '='); |
| 360 if (!equals) { |
| 361 count++; |
| 362 size += strlen(pair) + 1 /* terminating NUL */; |
| 363 continue; |
| 364 } |
| 365 const unsigned keylen = equals - pair; |
| 366 bool handled = false; |
| 367 for (environment_vector::const_iterator |
| 368 j = changes.begin(); j != changes.end(); j++) { |
| 369 if (j->first.size() == keylen && |
| 370 memcmp(j->first.data(), pair, keylen) == 0) { |
| 371 if (!j->second.empty()) { |
| 372 count++; |
| 373 size += keylen + 1 /* '=' */ + j->second.size() + 1 /* NUL */; |
| 374 } |
| 375 handled = true; |
| 376 break; |
| 377 } |
| 378 } |
| 379 |
| 380 if (!handled) { |
| 381 count++; |
| 382 size += strlen(pair) + 1 /* terminating NUL */; |
| 383 } |
| 384 } |
| 385 |
| 386 char **const ret = new char*[count + 1 /* final NULL */]; |
| 387 unsigned k = 0; |
| 388 char *scratch = new char[size]; |
| 389 |
| 390 for (unsigned i = 0; environ[i]; i++) { |
| 391 const char *const pair = environ[i]; |
| 392 const char *const equals = strchr(pair, '='); |
| 393 if (!equals) { |
| 394 const unsigned len = strlen(pair); |
| 395 ret[k++] = scratch; |
| 396 memcpy(scratch, pair, len + 1); |
| 397 scratch += len + 1; |
| 398 continue; |
| 399 } |
| 400 const unsigned keylen = equals - pair; |
| 401 bool handled = false; |
| 402 for (environment_vector::const_iterator |
| 403 j = changes.begin(); j != changes.end(); j++) { |
| 404 if (j->first.size() == keylen && |
| 405 memcmp(j->first.data(), pair, keylen) == 0) { |
| 406 if (!j->second.empty()) { |
| 407 ret[k++] = scratch; |
| 408 memcpy(scratch, pair, keylen + 1); |
| 409 scratch += keylen + 1; |
| 410 memcpy(scratch, j->second.c_str(), j->second.size() + 1); |
| 411 scratch += j->second.size() + 1; |
| 412 } |
| 413 handled = true; |
| 414 break; |
| 415 } |
| 416 } |
| 417 |
| 418 if (!handled) { |
| 419 const unsigned len = strlen(pair); |
| 420 ret[k++] = scratch; |
| 421 memcpy(scratch, pair, len + 1); |
| 422 scratch += len + 1; |
| 423 } |
| 424 } |
| 425 |
| 426 ret[k] = NULL; |
| 427 return ret; |
| 428 } |
| 429 |
| 368 #if defined(OS_MACOSX) | 430 #if defined(OS_MACOSX) |
| 369 bool LaunchAppAndGetTask( | 431 bool LaunchAppAndGetTask( |
| 370 #else | 432 #else |
| 371 bool LaunchApp( | 433 bool LaunchApp( |
| 372 #endif | 434 #endif |
| 373 const std::vector<std::string>& argv, | 435 const std::vector<std::string>& argv, |
| 374 const environment_vector& environ, | 436 const environment_vector& env_changes, |
| 375 const file_handle_mapping_vector& fds_to_remap, | 437 const file_handle_mapping_vector& fds_to_remap, |
| 376 bool wait, | 438 bool wait, |
| 377 #if defined(OS_MACOSX) | 439 #if defined(OS_MACOSX) |
| 378 task_t* task_handle, | 440 task_t* task_handle, |
| 379 #endif | 441 #endif |
| 380 ProcessHandle* process_handle) { | 442 ProcessHandle* process_handle) { |
| 381 pid_t pid; | 443 pid_t pid; |
| 444 InjectiveMultimap fd_shuffle1, fd_shuffle2; |
| 445 fd_shuffle1.reserve(fds_to_remap.size()); |
| 446 fd_shuffle2.reserve(fds_to_remap.size()); |
| 447 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); |
| 448 scoped_array<char*> new_environ(AlterEnvironment(env_changes)); |
| 449 // We need to free both the array of pointers, and the memory that they're |
| 450 // all pointing into. |
| 451 scoped_array<char> environ_buffer(new_environ[0]); |
| 452 |
| 382 #if defined(OS_MACOSX) | 453 #if defined(OS_MACOSX) |
| 383 if (task_handle == NULL) { | 454 if (task_handle == NULL) { |
| 384 pid = fork(); | 455 pid = fork(); |
| 385 } else { | 456 } else { |
| 386 // On OS X, the task_t for a process is needed for several reasons. Sadly, | 457 // On OS X, the task_t for a process is needed for several reasons. Sadly, |
| 387 // the function task_for_pid() requires privileges a normal user doesn't | 458 // the function task_for_pid() requires privileges a normal user doesn't |
| 388 // have. Instead, a short-lived Mach IPC connection is opened between parent | 459 // have. Instead, a short-lived Mach IPC connection is opened between parent |
| 389 // and child, and the child sends its task_t to the parent at fork time. | 460 // and child, and the child sends its task_t to the parent at fork time. |
| 390 *task_handle = MACH_PORT_NULL; | 461 *task_handle = MACH_PORT_NULL; |
| 391 pid = fork_and_get_task(task_handle); | 462 pid = fork_and_get_task(task_handle); |
| 392 } | 463 } |
| 393 #else | 464 #else |
| 394 pid = fork(); | 465 pid = fork(); |
| 395 #endif | 466 #endif |
| 396 if (pid < 0) | 467 if (pid < 0) |
| 397 return false; | 468 return false; |
| 398 | 469 |
| 399 if (pid == 0) { | 470 if (pid == 0) { |
| 400 // Child process | 471 // Child process |
| 401 #if defined(OS_MACOSX) | 472 #if defined(OS_MACOSX) |
| 402 RestoreDefaultExceptionHandler(); | 473 RestoreDefaultExceptionHandler(); |
| 403 #endif | 474 #endif |
| 404 | 475 |
| 405 InjectiveMultimap fd_shuffle; | 476 #if 0 |
| 477 // When debugging it can be helpful to check that we really aren't making |
| 478 // any hidden calls to malloc. |
| 479 void *malloc_thunk = |
| 480 reinterpret_cast<void*>(reinterpret_cast<intptr_t>(malloc) & ~4095); |
| 481 mprotect(malloc_thunk, 4096, PROT_READ | PROT_WRITE | PROT_EXEC); |
| 482 memset(reinterpret_cast<void*>(malloc), 0xff, 8); |
| 483 #endif |
| 484 |
| 485 // DANGER: no calls to malloc are allowed from now on: |
| 486 // http://crbug.com/36678 |
| 487 |
| 406 for (file_handle_mapping_vector::const_iterator | 488 for (file_handle_mapping_vector::const_iterator |
| 407 it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) { | 489 it = fds_to_remap.begin(); it != fds_to_remap.end(); ++it) { |
| 408 fd_shuffle.push_back(InjectionArc(it->first, it->second, false)); | 490 fd_shuffle1.push_back(InjectionArc(it->first, it->second, false)); |
| 491 fd_shuffle2.push_back(InjectionArc(it->first, it->second, false)); |
| 409 } | 492 } |
| 410 | 493 |
| 411 for (environment_vector::const_iterator it = environ.begin(); | 494 environ = new_environ.get(); |
| 412 it != environ.end(); ++it) { | |
| 413 if (it->first.empty()) | |
| 414 continue; | |
| 415 | |
| 416 if (it->second.empty()) { | |
| 417 unsetenv(it->first.c_str()); | |
| 418 } else { | |
| 419 setenv(it->first.c_str(), it->second.c_str(), 1); | |
| 420 } | |
| 421 } | |
| 422 | 495 |
| 423 // Obscure fork() rule: in the child, if you don't end up doing exec*(), | 496 // Obscure fork() rule: in the child, if you don't end up doing exec*(), |
| 424 // you call _exit() instead of exit(). This is because _exit() does not | 497 // you call _exit() instead of exit(). This is because _exit() does not |
| 425 // call any previously-registered (in the parent) exit handlers, which | 498 // call any previously-registered (in the parent) exit handlers, which |
| 426 // might do things like block waiting for threads that don't even exist | 499 // might do things like block waiting for threads that don't even exist |
| 427 // in the child. | 500 // in the child. |
| 428 if (!ShuffleFileDescriptors(fd_shuffle)) | 501 |
| 502 // fd_shuffle1 is mutated by this call because it cannot malloc. |
| 503 if (!ShuffleFileDescriptors(&fd_shuffle1)) |
| 429 _exit(127); | 504 _exit(127); |
| 430 | 505 |
| 431 // If we are using the SUID sandbox, it sets a magic environment variable | 506 CloseSuperfluousFds(fd_shuffle2); |
| 432 // ("SBX_D"), so we remove that variable from the environment here on the | |
| 433 // off chance that it's already set. | |
| 434 unsetenv("SBX_D"); | |
| 435 | 507 |
| 436 CloseSuperfluousFds(fd_shuffle); | |
| 437 | |
| 438 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); | |
| 439 for (size_t i = 0; i < argv.size(); i++) | 508 for (size_t i = 0; i < argv.size(); i++) |
| 440 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); | 509 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); |
| 441 argv_cstr[argv.size()] = NULL; | 510 argv_cstr[argv.size()] = NULL; |
| 442 execvp(argv_cstr[0], argv_cstr.get()); | 511 execvp(argv_cstr[0], argv_cstr.get()); |
| 443 PLOG(ERROR) << "LaunchApp: execvp(" << argv_cstr[0] << ") failed"; | 512 RAW_LOG(ERROR, "LaunchApp: failed to execvp:"); |
| 513 RAW_LOG(ERROR, argv_cstr[0]); |
| 444 _exit(127); | 514 _exit(127); |
| 445 } else { | 515 } else { |
| 446 // Parent process | 516 // Parent process |
| 447 if (wait) { | 517 if (wait) { |
| 448 pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0)); | 518 pid_t ret = HANDLE_EINTR(waitpid(pid, 0, 0)); |
| 449 DPCHECK(ret > 0); | 519 DPCHECK(ret > 0); |
| 450 } | 520 } |
| 451 | 521 |
| 452 if (process_handle) | 522 if (process_handle) |
| 453 *process_handle = pid; | 523 *process_handle = pid; |
| (...skipping 172 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 626 // the current environment. If |do_search_path| is false, |cl| should fully | 696 // the current environment. If |do_search_path| is false, |cl| should fully |
| 627 // specify the path of the application, and |envp| will be used as the | 697 // specify the path of the application, and |envp| will be used as the |
| 628 // environment. Redirects stderr to /dev/null. Returns true on success | 698 // environment. Redirects stderr to /dev/null. Returns true on success |
| 629 // (application launched and exited cleanly, with exit code indicating success). | 699 // (application launched and exited cleanly, with exit code indicating success). |
| 630 // |output| is modified only when the function finished successfully. | 700 // |output| is modified only when the function finished successfully. |
| 631 static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], | 701 static bool GetAppOutputInternal(const CommandLine& cl, char* const envp[], |
| 632 std::string* output, size_t max_output, | 702 std::string* output, size_t max_output, |
| 633 bool do_search_path) { | 703 bool do_search_path) { |
| 634 int pipe_fd[2]; | 704 int pipe_fd[2]; |
| 635 pid_t pid; | 705 pid_t pid; |
| 706 InjectiveMultimap fd_shuffle1, fd_shuffle2; |
| 707 const std::vector<std::string>& argv = cl.argv(); |
| 708 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); |
| 709 |
| 710 fd_shuffle1.reserve(3); |
| 711 fd_shuffle2.reserve(3); |
| 636 | 712 |
| 637 // Either |do_search_path| should be false or |envp| should be null, but not | 713 // Either |do_search_path| should be false or |envp| should be null, but not |
| 638 // both. | 714 // both. |
| 639 DCHECK(!do_search_path ^ !envp); | 715 DCHECK(!do_search_path ^ !envp); |
| 640 | 716 |
| 641 if (pipe(pipe_fd) < 0) | 717 if (pipe(pipe_fd) < 0) |
| 642 return false; | 718 return false; |
| 643 | 719 |
| 644 switch (pid = fork()) { | 720 switch (pid = fork()) { |
| 645 case -1: // error | 721 case -1: // error |
| 646 close(pipe_fd[0]); | 722 close(pipe_fd[0]); |
| 647 close(pipe_fd[1]); | 723 close(pipe_fd[1]); |
| 648 return false; | 724 return false; |
| 649 case 0: // child | 725 case 0: // child |
| 650 { | 726 { |
| 651 #if defined(OS_MACOSX) | 727 #if defined(OS_MACOSX) |
| 652 RestoreDefaultExceptionHandler(); | 728 RestoreDefaultExceptionHandler(); |
| 653 #endif | 729 #endif |
| 730 // DANGER: no calls to malloc are allowed from now on: |
| 731 // http://crbug.com/36678 |
| 654 | 732 |
| 655 // Obscure fork() rule: in the child, if you don't end up doing exec*(), | 733 // Obscure fork() rule: in the child, if you don't end up doing exec*(), |
| 656 // you call _exit() instead of exit(). This is because _exit() does not | 734 // you call _exit() instead of exit(). This is because _exit() does not |
| 657 // call any previously-registered (in the parent) exit handlers, which | 735 // call any previously-registered (in the parent) exit handlers, which |
| 658 // might do things like block waiting for threads that don't even exist | 736 // might do things like block waiting for threads that don't even exist |
| 659 // in the child. | 737 // in the child. |
| 660 int dev_null = open("/dev/null", O_WRONLY); | 738 int dev_null = open("/dev/null", O_WRONLY); |
| 661 if (dev_null < 0) | 739 if (dev_null < 0) |
| 662 _exit(127); | 740 _exit(127); |
| 663 | 741 |
| 664 InjectiveMultimap fd_shuffle; | 742 fd_shuffle1.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); |
| 665 fd_shuffle.push_back(InjectionArc(pipe_fd[1], STDOUT_FILENO, true)); | 743 fd_shuffle1.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); |
| 666 fd_shuffle.push_back(InjectionArc(dev_null, STDERR_FILENO, true)); | 744 fd_shuffle1.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); |
| 667 fd_shuffle.push_back(InjectionArc(dev_null, STDIN_FILENO, true)); | 745 // Adding another element here? Remeber to increase the argument to |
| 746 // reserve(), above. |
| 668 | 747 |
| 669 if (!ShuffleFileDescriptors(fd_shuffle)) | 748 std::copy(fd_shuffle1.begin(), fd_shuffle1.end(), |
| 749 std::back_inserter(fd_shuffle2)); |
| 750 |
| 751 if (!ShuffleFileDescriptors(&fd_shuffle1)) |
| 670 _exit(127); | 752 _exit(127); |
| 671 | 753 |
| 672 CloseSuperfluousFds(fd_shuffle); | 754 CloseSuperfluousFds(fd_shuffle2); |
| 673 | 755 |
| 674 const std::vector<std::string> argv = cl.argv(); | |
| 675 scoped_array<char*> argv_cstr(new char*[argv.size() + 1]); | |
| 676 for (size_t i = 0; i < argv.size(); i++) | 756 for (size_t i = 0; i < argv.size(); i++) |
| 677 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); | 757 argv_cstr[i] = const_cast<char*>(argv[i].c_str()); |
| 678 argv_cstr[argv.size()] = NULL; | 758 argv_cstr[argv.size()] = NULL; |
| 679 if (do_search_path) | 759 if (do_search_path) |
| 680 execvp(argv_cstr[0], argv_cstr.get()); | 760 execvp(argv_cstr[0], argv_cstr.get()); |
| 681 else | 761 else |
| 682 execve(argv_cstr[0], argv_cstr.get(), envp); | 762 execve(argv_cstr[0], argv_cstr.get(), envp); |
| 683 _exit(127); | 763 _exit(127); |
| 684 } | 764 } |
| 685 default: // parent | 765 default: // parent |
| (...skipping 101 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 787 const ProcessFilter* filter) { | 867 const ProcessFilter* filter) { |
| 788 bool exited_cleanly = | 868 bool exited_cleanly = |
| 789 WaitForProcessesToExit(executable_name, wait_milliseconds, | 869 WaitForProcessesToExit(executable_name, wait_milliseconds, |
| 790 filter); | 870 filter); |
| 791 if (!exited_cleanly) | 871 if (!exited_cleanly) |
| 792 KillProcesses(executable_name, exit_code, filter); | 872 KillProcesses(executable_name, exit_code, filter); |
| 793 return exited_cleanly; | 873 return exited_cleanly; |
| 794 } | 874 } |
| 795 | 875 |
| 796 } // namespace base | 876 } // namespace base |
| OLD | NEW |