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

Side by Side Diff: content/browser/zygote_main_linux.cc

Issue 8342017: Add UMA reports for Linux nacl_helper startup status (Closed) Base URL: svn://svn.chromium.org/chrome/trunk/src
Patch Set: review nits Created 9 years, 2 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
OLDNEW
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. 1 // Copyright (c) 2011 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/browser/zygote_host_linux.h" 5 #include "content/browser/zygote_host_linux.h"
6 6
7 #include <dlfcn.h> 7 #include <dlfcn.h>
8 #include <fcntl.h> 8 #include <fcntl.h>
9 #include <pthread.h> 9 #include <pthread.h>
10 #include <sys/socket.h> 10 #include <sys/socket.h>
(...skipping 78 matching lines...) Expand 10 before | Expand all | Expand 10 after
89 } 89 }
90 #endif // CHROMIUM_SELINUX 90 #endif // CHROMIUM_SELINUX
91 91
92 // This is the object which implements the zygote. The ZygoteMain function, 92 // This is the object which implements the zygote. The ZygoteMain function,
93 // which is called from ChromeMain, simply constructs one of these objects and 93 // which is called from ChromeMain, simply constructs one of these objects and
94 // runs it. 94 // runs it.
95 class Zygote { 95 class Zygote {
96 public: 96 public:
97 Zygote(int sandbox_flags, ZygoteForkDelegate* helper) 97 Zygote(int sandbox_flags, ZygoteForkDelegate* helper)
98 : sandbox_flags_(sandbox_flags), helper_(helper) { 98 : sandbox_flags_(sandbox_flags), helper_(helper) {
99 if (helper_)
100 helper_->InitialUMA(&initial_uma_name_,
101 &initial_uma_sample_,
102 &initial_uma_boundary_value_);
99 } 103 }
100 104
101 bool ProcessRequests() { 105 bool ProcessRequests() {
102 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the 106 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
103 // browser on it. 107 // browser on it.
104 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel. 108 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel.
105 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC 109 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
106 110
107 // We need to accept SIGCHLD, even though our handler is a no-op because 111 // We need to accept SIGCHLD, even though our handler is a no-op because
108 // otherwise we cannot wait on children. (According to POSIX 2001.) 112 // otherwise we cannot wait on children. (According to POSIX 2001.)
(...skipping 137 matching lines...) Expand 10 before | Expand all | Expand 10 after
246 write_pickle.WriteInt(exit_code); 250 write_pickle.WriteInt(exit_code);
247 ssize_t written = 251 ssize_t written =
248 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); 252 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size()));
249 if (written != static_cast<ssize_t>(write_pickle.size())) 253 if (written != static_cast<ssize_t>(write_pickle.size()))
250 PLOG(ERROR) << "write"; 254 PLOG(ERROR) << "write";
251 } 255 }
252 256
253 // This is equivalent to fork(), except that, when using the SUID 257 // This is equivalent to fork(), except that, when using the SUID
254 // sandbox, it returns the real PID of the child process as it 258 // sandbox, it returns the real PID of the child process as it
255 // appears outside the sandbox, rather than returning the PID inside 259 // appears outside the sandbox, rather than returning the PID inside
256 // the sandbox. 260 // the sandbox. Optionally, it fills in uma_name et al with a report
261 // the helper wants to make via UMA_HISTOGRAM_ENUMERATION.
257 int ForkWithRealPid(const std::string& process_type, std::vector<int>& fds, 262 int ForkWithRealPid(const std::string& process_type, std::vector<int>& fds,
258 const std::string& channel_switch) { 263 const std::string& channel_switch,
259 const bool use_helper = (helper_ && helper_->CanHelp(process_type)); 264 std::string* uma_name,
265 int* uma_sample, int* uma_boundary_value) {
266 const bool use_helper = (helper_ && helper_->CanHelp(process_type,
267 uma_name,
268 uma_sample,
269 uma_boundary_value));
260 if (!(use_helper || g_suid_sandbox_active)) { 270 if (!(use_helper || g_suid_sandbox_active)) {
261 return fork(); 271 return fork();
262 } 272 }
263 273
264 int dummy_fd; 274 int dummy_fd;
265 ino_t dummy_inode; 275 ino_t dummy_inode;
266 int pipe_fds[2] = { -1, -1 }; 276 int pipe_fds[2] = { -1, -1 };
267 base::ProcessId pid = 0; 277 base::ProcessId pid = 0;
268 278
269 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); 279 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
(...skipping 105 matching lines...) Expand 10 before | Expand all | Expand 10 after
375 if (pipe_fds[1] >= 0) 385 if (pipe_fds[1] >= 0)
376 close(pipe_fds[1]); 386 close(pipe_fds[1]);
377 return -1; 387 return -1;
378 } 388 }
379 389
380 // Unpacks process type and arguments from |pickle| and forks a new process. 390 // Unpacks process type and arguments from |pickle| and forks a new process.
381 // Returns -1 on error, otherwise returns twice, returning 0 to the child 391 // Returns -1 on error, otherwise returns twice, returning 0 to the child
382 // process and the child process ID to the parent process, like fork(). 392 // process and the child process ID to the parent process, like fork().
383 base::ProcessId ReadArgsAndFork(const Pickle& pickle, 393 base::ProcessId ReadArgsAndFork(const Pickle& pickle,
384 void* iter, 394 void* iter,
385 std::vector<int>& fds) { 395 std::vector<int>& fds,
396 std::string* uma_name,
397 int* uma_sample,
398 int* uma_boundary_value) {
386 std::vector<std::string> args; 399 std::vector<std::string> args;
387 int argc = 0; 400 int argc = 0;
388 int numfds = 0; 401 int numfds = 0;
389 base::GlobalDescriptors::Mapping mapping; 402 base::GlobalDescriptors::Mapping mapping;
390 std::string process_type; 403 std::string process_type;
391 std::string channel_id; 404 std::string channel_id;
392 const std::string channel_id_prefix = std::string("--") 405 const std::string channel_id_prefix = std::string("--")
393 + switches::kProcessChannelID + std::string("="); 406 + switches::kProcessChannelID + std::string("=");
394 407
395 if (!pickle.ReadString(&iter, &process_type)) 408 if (!pickle.ReadString(&iter, &process_type))
(...skipping 19 matching lines...) Expand all
415 base::GlobalDescriptors::Key key; 428 base::GlobalDescriptors::Key key;
416 if (!pickle.ReadUInt32(&iter, &key)) 429 if (!pickle.ReadUInt32(&iter, &key))
417 return -1; 430 return -1;
418 mapping.push_back(std::make_pair(key, fds[i])); 431 mapping.push_back(std::make_pair(key, fds[i]));
419 } 432 }
420 433
421 mapping.push_back(std::make_pair( 434 mapping.push_back(std::make_pair(
422 static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); 435 static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor));
423 436
424 // Returns twice, once per process. 437 // Returns twice, once per process.
425 base::ProcessId child_pid = ForkWithRealPid(process_type, fds, channel_id); 438 base::ProcessId child_pid = ForkWithRealPid(process_type, fds, channel_id,
439 uma_name, uma_sample,
440 uma_boundary_value);
426 if (!child_pid) { 441 if (!child_pid) {
427 // This is the child process. 442 // This is the child process.
428 #if defined(SECCOMP_SANDBOX) 443 #if defined(SECCOMP_SANDBOX)
429 if (SeccompSandboxEnabled() && g_proc_fd >= 0) { 444 if (SeccompSandboxEnabled() && g_proc_fd >= 0) {
430 // Try to open /proc/self/maps as the seccomp sandbox needs access to it 445 // Try to open /proc/self/maps as the seccomp sandbox needs access to it
431 int proc_self_maps = openat(g_proc_fd, "self/maps", O_RDONLY); 446 int proc_self_maps = openat(g_proc_fd, "self/maps", O_RDONLY);
432 if (proc_self_maps >= 0) { 447 if (proc_self_maps >= 0) {
433 SeccompSandboxSetProcSelfMaps(proc_self_maps); 448 SeccompSandboxSetProcSelfMaps(proc_self_maps);
434 } else { 449 } else {
435 PLOG(ERROR) << "openat(/proc/self/maps)"; 450 PLOG(ERROR) << "openat(/proc/self/maps)";
(...skipping 27 matching lines...) Expand all
463 } 478 }
464 return child_pid; 479 return child_pid;
465 } 480 }
466 481
467 // Handle a 'fork' request from the browser: this means that the browser 482 // Handle a 'fork' request from the browser: this means that the browser
468 // wishes to start a new renderer. Returns true if we are in a new process, 483 // wishes to start a new renderer. Returns true if we are in a new process,
469 // otherwise writes the child_pid back to the browser via |fd|. Writes a 484 // otherwise writes the child_pid back to the browser via |fd|. Writes a
470 // child_pid of -1 on error. 485 // child_pid of -1 on error.
471 bool HandleForkRequest(int fd, const Pickle& pickle, 486 bool HandleForkRequest(int fd, const Pickle& pickle,
472 void* iter, std::vector<int>& fds) { 487 void* iter, std::vector<int>& fds) {
473 base::ProcessId child_pid = ReadArgsAndFork(pickle, iter, fds); 488 std::string uma_name;
489 int uma_sample;
490 int uma_boundary_value;
491 base::ProcessId child_pid = ReadArgsAndFork(pickle, iter, fds,
492 &uma_name, &uma_sample,
493 &uma_boundary_value);
474 if (child_pid == 0) 494 if (child_pid == 0)
475 return true; 495 return true;
476 for (std::vector<int>::const_iterator 496 for (std::vector<int>::const_iterator
477 i = fds.begin(); i != fds.end(); ++i) 497 i = fds.begin(); i != fds.end(); ++i)
478 close(*i); 498 close(*i);
499 if (uma_name.empty()) {
500 // There is no UMA report from this particular fork.
501 // Use the initial UMA report if any, and clear that record for next time.
502 // Note the swap method here is the efficient way to do this, since
503 // we know uma_name is empty.
504 uma_name.swap(initial_uma_name_);
505 uma_sample = initial_uma_sample_;
506 uma_boundary_value = initial_uma_boundary_value_;
507 }
479 // Must always send reply, as ZygoteHost blocks while waiting for it. 508 // Must always send reply, as ZygoteHost blocks while waiting for it.
480 if (HANDLE_EINTR(write(fd, &child_pid, sizeof(child_pid))) < 0) 509 Pickle reply_pickle;
510 reply_pickle.WriteInt(child_pid);
511 reply_pickle.WriteString(uma_name);
512 if (!uma_name.empty()) {
513 reply_pickle.WriteInt(uma_sample);
514 reply_pickle.WriteInt(uma_boundary_value);
515 }
516 if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) !=
517 (ssize_t) reply_pickle.size())
brettw 2011/10/20 06:07:09 Use static_cast instead of C-style casts.
481 PLOG(ERROR) << "write"; 518 PLOG(ERROR) << "write";
482 return false; 519 return false;
483 } 520 }
484 521
485 bool HandleGetSandboxStatus(int fd, const Pickle& pickle, void* iter) { 522 bool HandleGetSandboxStatus(int fd, const Pickle& pickle, void* iter) {
486 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_)) != 523 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_)) !=
487 sizeof(sandbox_flags_))) { 524 sizeof(sandbox_flags_))) {
488 PLOG(ERROR) << "write"; 525 PLOG(ERROR) << "write";
489 } 526 }
490 527
491 return false; 528 return false;
492 } 529 }
493 530
494 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs 531 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs
495 // fork() returns are not the real PIDs, so we need to map the Real PIDS 532 // fork() returns are not the real PIDs, so we need to map the Real PIDS
496 // into the sandbox PID namespace. 533 // into the sandbox PID namespace.
497 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; 534 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap;
498 ProcessMap real_pids_to_sandbox_pids; 535 ProcessMap real_pids_to_sandbox_pids;
499 536
500 const int sandbox_flags_; 537 const int sandbox_flags_;
501 ZygoteForkDelegate* helper_; 538 ZygoteForkDelegate* helper_;
539
540 // These might be set by helper_->InitialUMA. They supply a UMA
541 // enumeration sample we should report on the first fork.
542 std::string initial_uma_name_;
543 int initial_uma_sample_;
544 int initial_uma_boundary_value_;
502 }; 545 };
503 546
504 // With SELinux we can carve out a precise sandbox, so we don't have to play 547 // With SELinux we can carve out a precise sandbox, so we don't have to play
505 // with intercepting libc calls. 548 // with intercepting libc calls.
506 #if !defined(CHROMIUM_SELINUX) 549 #if !defined(CHROMIUM_SELINUX)
507 550
508 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, 551 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output,
509 char* timezone_out, 552 char* timezone_out,
510 size_t timezone_out_len) { 553 size_t timezone_out_len) {
511 Pickle request; 554 Pickle request;
(...skipping 310 matching lines...) Expand 10 before | Expand all | Expand 10 after
822 VLOG(1) << "Enabling experimental Seccomp sandbox."; 865 VLOG(1) << "Enabling experimental Seccomp sandbox.";
823 sandbox_flags |= ZygoteHost::kSandboxSeccomp; 866 sandbox_flags |= ZygoteHost::kSandboxSeccomp;
824 } 867 }
825 } 868 }
826 #endif // SECCOMP_SANDBOX 869 #endif // SECCOMP_SANDBOX
827 870
828 Zygote zygote(sandbox_flags, forkdelegate); 871 Zygote zygote(sandbox_flags, forkdelegate);
829 // This function call can return multiple times, once per fork(). 872 // This function call can return multiple times, once per fork().
830 return zygote.ProcessRequests(); 873 return zygote.ProcessRequests();
831 } 874 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698