Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(221)

Side by Side Diff: content/zygote/zygote_linux.cc

Issue 240463005: Stop using chrome-sandbox to determine real pids (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: Fix an embarassing number of compile errors Created 6 years, 8 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « content/public/common/zygote_fork_delegate_linux.h ('k') | content/zygote/zygote_main_linux.cc » ('j') | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
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 "content/zygote/zygote_linux.h" 5 #include "content/zygote/zygote_linux.h"
6 6
7 #include <fcntl.h> 7 #include <fcntl.h>
8 #include <string.h> 8 #include <string.h>
9 #include <sys/socket.h> 9 #include <sys/socket.h>
10 #include <sys/types.h> 10 #include <sys/types.h>
(...skipping 65 matching lines...) Expand 10 before | Expand all | Expand 10 after
76 // We need to accept SIGCHLD, even though our handler is a no-op because 76 // We need to accept SIGCHLD, even though our handler is a no-op because
77 // otherwise we cannot wait on children. (According to POSIX 2001.) 77 // otherwise we cannot wait on children. (According to POSIX 2001.)
78 struct sigaction action; 78 struct sigaction action;
79 memset(&action, 0, sizeof(action)); 79 memset(&action, 0, sizeof(action));
80 action.sa_handler = &SIGCHLDHandler; 80 action.sa_handler = &SIGCHLDHandler;
81 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); 81 CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
82 82
83 if (UsingSUIDSandbox()) { 83 if (UsingSUIDSandbox()) {
84 // Let the ZygoteHost know we are ready to go. 84 // Let the ZygoteHost know we are ready to go.
85 // The receiving code is in content/browser/zygote_host_linux.cc. 85 // The receiving code is in content/browser/zygote_host_linux.cc.
86 std::vector<int> empty;
87 bool r = UnixDomainSocket::SendMsg(kZygoteSocketPairFd, 86 bool r = UnixDomainSocket::SendMsg(kZygoteSocketPairFd,
88 kZygoteHelloMessage, 87 kZygoteHelloMessage,
89 sizeof(kZygoteHelloMessage), empty); 88 sizeof(kZygoteHelloMessage),
89 std::vector<int>());
90 #if defined(OS_CHROMEOS) 90 #if defined(OS_CHROMEOS)
91 LOG_IF(WARNING, !r) << "Sending zygote magic failed"; 91 LOG_IF(WARNING, !r) << "Sending zygote magic failed";
92 // Exit normally on chromeos because session manager may send SIGTERM 92 // Exit normally on chromeos because session manager may send SIGTERM
93 // right after the process starts and it may fail to send zygote magic 93 // right after the process starts and it may fail to send zygote magic
94 // number to browser process. 94 // number to browser process.
95 if (!r) 95 if (!r)
96 _exit(RESULT_CODE_NORMAL_EXIT); 96 _exit(RESULT_CODE_NORMAL_EXIT);
97 #else 97 #else
98 CHECK(r) << "Sending zygote magic failed"; 98 CHECK(r) << "Sending zygote magic failed";
99 #endif 99 #endif
(...skipping 197 matching lines...) Expand 10 before | Expand all | Expand 10 after
297 int Zygote::ForkWithRealPid(const std::string& process_type, 297 int Zygote::ForkWithRealPid(const std::string& process_type,
298 const base::GlobalDescriptors::Mapping& fd_mapping, 298 const base::GlobalDescriptors::Mapping& fd_mapping,
299 const std::string& channel_id, 299 const std::string& channel_id,
300 std::string* uma_name, 300 std::string* uma_name,
301 int* uma_sample, 301 int* uma_sample,
302 int* uma_boundary_value) { 302 int* uma_boundary_value) {
303 const bool use_helper = (helper_ && helper_->CanHelp(process_type, 303 const bool use_helper = (helper_ && helper_->CanHelp(process_type,
304 uma_name, 304 uma_name,
305 uma_sample, 305 uma_sample,
306 uma_boundary_value)); 306 uma_boundary_value));
307 int dummy_fd;
308 ino_t dummy_inode;
309 int pipe_fds[2] = { -1, -1 };
310 base::ProcessId pid = 0;
311 307
312 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); 308 int pipe_fds[2] = {-1, -1};
313 if (dummy_fd < 0) {
314 LOG(ERROR) << "Failed to create dummy FD";
315 goto error;
316 }
317 if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd)) {
318 LOG(ERROR) << "Failed to get inode for dummy FD";
319 goto error;
320 }
321 if (pipe(pipe_fds) != 0) { 309 if (pipe(pipe_fds) != 0) {
322 LOG(ERROR) << "Failed to create pipe"; 310 LOG(ERROR) << "Failed to create pipe";
323 goto error; 311 return -1;
324 } 312 }
313 base::ScopedFD read_pipe(pipe_fds[0]);
314 base::ScopedFD write_pipe(pipe_fds[1]);
325 315
316 base::ProcessId pid = -1;
326 if (use_helper) { 317 if (use_helper) {
327 std::vector<int> fds; 318 std::vector<int> fds;
328 int ipc_channel_fd = LookUpFd(fd_mapping, kPrimaryIPCChannel); 319 int ipc_channel_fd = LookUpFd(fd_mapping, kPrimaryIPCChannel);
329 if (ipc_channel_fd < 0) { 320 if (ipc_channel_fd < 0) {
330 DLOG(ERROR) << "Failed to find kPrimaryIPCChannel in FD mapping"; 321 DLOG(ERROR) << "Failed to find kPrimaryIPCChannel in FD mapping";
331 goto error; 322 return -1;
332 } 323 }
333 fds.push_back(ipc_channel_fd); // kBrowserFDIndex 324 fds.push_back(ipc_channel_fd); // kBrowserFDIndex
334 fds.push_back(dummy_fd); // kDummyFDIndex 325 fds.push_back(write_pipe.get()); // kParentFDIndex
335 fds.push_back(pipe_fds[0]); // kParentFDIndex
336 pid = helper_->Fork(process_type, fds, channel_id); 326 pid = helper_->Fork(process_type, fds, channel_id);
337 } else { 327 } else {
338 pid = fork(); 328 pid = fork();
339 } 329 }
340 if (pid < 0) { 330 if (pid < 0) {
341 goto error; 331 return -1;
342 } else if (pid == 0) { 332 }
333 if (pid == 0) {
343 // In the child process. 334 // In the child process.
344 close(pipe_fds[1]); 335 read_pipe.reset();
336
345 base::ProcessId real_pid; 337 base::ProcessId real_pid;
346 // Wait until the parent process has discovered our PID. We 338 if (!SendRealPidToZygote(write_pipe.get(), &real_pid)) {
347 // should not fork any child processes (which the seccomp 339 LOG(FATAL) << "Failed to synchronise with parent process";
348 // sandbox does) until then, because that can interfere with the
349 // parent's discovery of our PID.
350 if (!base::ReadFromFD(pipe_fds[0], reinterpret_cast<char*>(&real_pid),
351 sizeof(real_pid))) {
352 LOG(FATAL) << "Failed to synchronise with parent zygote process";
353 } 340 }
354 if (real_pid <= 0) { 341 write_pipe.reset();
355 LOG(FATAL) << "Invalid pid from parent zygote"; 342
356 }
357 #if defined(OS_LINUX) 343 #if defined(OS_LINUX)
358 // Sandboxed processes need to send the global, non-namespaced PID when 344 // Sandboxed processes need to send the global, non-namespaced PID when
359 // setting up an IPC channel to their parent. 345 // setting up an IPC channel to their parent.
360 IPC::Channel::SetGlobalPid(real_pid); 346 IPC::Channel::SetGlobalPid(real_pid);
361 // Force the real PID so chrome event data have a PID that corresponds 347 // Force the real PID so chrome event data have a PID that corresponds
362 // to system trace event data. 348 // to system trace event data.
363 base::debug::TraceLog::GetInstance()->SetProcessID( 349 base::debug::TraceLog::GetInstance()->SetProcessID(
364 static_cast<int>(real_pid)); 350 static_cast<int>(real_pid));
365 #endif 351 #endif
366 close(pipe_fds[0]);
367 close(dummy_fd);
368 return 0; 352 return 0;
369 } else {
370 // In the parent process.
371 close(dummy_fd);
372 dummy_fd = -1;
373 close(pipe_fds[0]);
374 pipe_fds[0] = -1;
375 base::ProcessId real_pid;
376 if (UsingSUIDSandbox()) {
377 uint8_t reply_buf[512];
378 Pickle request;
379 request.WriteInt(LinuxSandbox::METHOD_GET_CHILD_WITH_INODE);
380 request.WriteUInt64(dummy_inode);
381
382 const ssize_t r = UnixDomainSocket::SendRecvMsg(
383 GetSandboxFD(), reply_buf, sizeof(reply_buf), NULL,
384 request);
385 if (r == -1) {
386 LOG(ERROR) << "Failed to get child process's real PID";
387 goto error;
388 }
389
390 Pickle reply(reinterpret_cast<char*>(reply_buf), r);
391 PickleIterator iter(reply);
392 if (!reply.ReadInt(&iter, &real_pid))
393 goto error;
394 if (real_pid <= 0) {
395 // METHOD_GET_CHILD_WITH_INODE failed. Did the child die already?
396 LOG(ERROR) << "METHOD_GET_CHILD_WITH_INODE failed";
397 goto error;
398 }
399 } else {
400 // If no SUID sandbox is involved then no pid translation is
401 // necessary.
402 real_pid = pid;
403 }
404
405 // Now set-up this process to be tracked by the Zygote.
406 if (process_info_map_.find(real_pid) != process_info_map_.end()) {
407 LOG(ERROR) << "Already tracking PID " << real_pid;
408 NOTREACHED();
409 }
410 process_info_map_[real_pid].internal_pid = pid;
411 process_info_map_[real_pid].started_from_helper = use_helper;
412
413 // If we're using a helper, we still need to let the child process know
414 // we've discovered its real PID, but we don't actually reveal the PID.
415 const base::ProcessId pid_for_child = use_helper ? 0 : real_pid;
416 ssize_t written =
417 HANDLE_EINTR(write(pipe_fds[1], &pid_for_child, sizeof(pid_for_child)));
418 if (written != sizeof(pid_for_child)) {
419 LOG(ERROR) << "Failed to synchronise with child process";
420 goto error;
421 }
422 close(pipe_fds[1]);
423 return real_pid;
424 } 353 }
425 354
426 error: 355 // In the parent process.
427 if (pid > 0) { 356 write_pipe.reset();
357
358 base::ProcessId real_pid;
359 if (!base::ReadFromFD(read_pipe.get(),
360 reinterpret_cast<char*>(&real_pid),
361 sizeof(real_pid))) {
362 LOG(ERROR) << "Failed to synchronise with child process";
363 // TODO(mdempsky): Dispatch to helper
428 if (waitpid(pid, NULL, WNOHANG) == -1) 364 if (waitpid(pid, NULL, WNOHANG) == -1)
429 LOG(ERROR) << "Failed to wait for process"; 365 LOG(ERROR) << "Failed to wait for process";
366 return -1;
430 } 367 }
431 if (dummy_fd >= 0) 368 read_pipe.reset();
432 close(dummy_fd); 369
433 if (pipe_fds[0] >= 0) 370 // Now set-up this process to be tracked by the Zygote.
434 close(pipe_fds[0]); 371 if (process_info_map_.find(real_pid) != process_info_map_.end()) {
435 if (pipe_fds[1] >= 0) 372 LOG(ERROR) << "Already tracking PID " << real_pid;
436 close(pipe_fds[1]); 373 NOTREACHED();
437 return -1; 374 }
375 process_info_map_[real_pid].internal_pid = pid;
376 process_info_map_[real_pid].started_from_helper = use_helper;
377
378 return real_pid;
438 } 379 }
439 380
440 base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle, 381 base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle,
441 PickleIterator iter, 382 PickleIterator iter,
442 std::vector<int>& fds, 383 std::vector<int>& fds,
443 std::string* uma_name, 384 std::string* uma_name,
444 int* uma_sample, 385 int* uma_sample,
445 int* uma_boundary_value) { 386 int* uma_boundary_value) {
446 std::vector<std::string> args; 387 std::vector<std::string> args;
447 int argc = 0; 388 int argc = 0;
(...skipping 34 matching lines...) Expand 10 before | Expand all | Expand 10 after
482 static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD())); 423 static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD()));
483 424
484 // Returns twice, once per process. 425 // Returns twice, once per process.
485 base::ProcessId child_pid = ForkWithRealPid(process_type, mapping, channel_id, 426 base::ProcessId child_pid = ForkWithRealPid(process_type, mapping, channel_id,
486 uma_name, uma_sample, 427 uma_name, uma_sample,
487 uma_boundary_value); 428 uma_boundary_value);
488 if (!child_pid) { 429 if (!child_pid) {
489 // This is the child process. 430 // This is the child process.
490 431
491 close(kZygoteSocketPairFd); // Our socket from the browser. 432 close(kZygoteSocketPairFd); // Our socket from the browser.
492 if (UsingSUIDSandbox())
493 close(kZygoteIdFd); // Another socket from the browser.
494 base::GlobalDescriptors::GetInstance()->Reset(mapping); 433 base::GlobalDescriptors::GetInstance()->Reset(mapping);
495 434
496 // Reset the process-wide command line to our new command line. 435 // Reset the process-wide command line to our new command line.
497 CommandLine::Reset(); 436 CommandLine::Reset();
498 CommandLine::Init(0, NULL); 437 CommandLine::Init(0, NULL);
499 CommandLine::ForCurrentProcess()->InitFromArgv(args); 438 CommandLine::ForCurrentProcess()->InitFromArgv(args);
500 439
501 // Update the process title. The argv was already cached by the call to 440 // Update the process title. The argv was already cached by the call to
502 // SetProcessTitleFromCommandLine in ChromeMain, so we can pass NULL here 441 // SetProcessTitleFromCommandLine in ChromeMain, so we can pass NULL here
503 // (we don't have the original argv at this point). 442 // (we don't have the original argv at this point).
(...skipping 48 matching lines...) Expand 10 before | Expand all | Expand 10 after
552 PickleIterator iter) { 491 PickleIterator iter) {
553 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) != 492 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) !=
554 sizeof(sandbox_flags_)) { 493 sizeof(sandbox_flags_)) {
555 PLOG(ERROR) << "write"; 494 PLOG(ERROR) << "write";
556 } 495 }
557 496
558 return false; 497 return false;
559 } 498 }
560 499
561 } // namespace content 500 } // namespace content
OLDNEW
« no previous file with comments | « content/public/common/zygote_fork_delegate_linux.h ('k') | content/zygote/zygote_main_linux.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698