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

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

Issue 6995121: New NaCl zygote implementation 2 (Closed) Base URL: http://git.chromium.org/git/chromium.git@trunk
Patch Set: Addressing feedback from John Created 9 years, 6 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 19 matching lines...) Expand all
30 #include "content/common/chrome_descriptors.h" 30 #include "content/common/chrome_descriptors.h"
31 #include "content/common/content_switches.h" 31 #include "content/common/content_switches.h"
32 #include "content/common/font_config_ipc_linux.h" 32 #include "content/common/font_config_ipc_linux.h"
33 #include "content/common/main_function_params.h" 33 #include "content/common/main_function_params.h"
34 #include "content/common/pepper_plugin_registry.h" 34 #include "content/common/pepper_plugin_registry.h"
35 #include "content/common/process_watcher.h" 35 #include "content/common/process_watcher.h"
36 #include "content/common/result_codes.h" 36 #include "content/common/result_codes.h"
37 #include "content/common/sandbox_methods_linux.h" 37 #include "content/common/sandbox_methods_linux.h"
38 #include "content/common/set_process_title.h" 38 #include "content/common/set_process_title.h"
39 #include "content/common/unix_domain_socket_posix.h" 39 #include "content/common/unix_domain_socket_posix.h"
40 #include "content/common/zygote_fork_delegate.h"
41 #include "media/base/media.h"
40 #include "seccompsandbox/sandbox.h" 42 #include "seccompsandbox/sandbox.h"
41 #include "skia/ext/SkFontHost_fontconfig_control.h" 43 #include "skia/ext/SkFontHost_fontconfig_control.h"
42 #include "unicode/timezone.h" 44 #include "unicode/timezone.h"
43 45
44 #if defined(OS_LINUX) 46 #if defined(OS_LINUX)
45 #include <sys/epoll.h> 47 #include <sys/epoll.h>
46 #include <sys/prctl.h> 48 #include <sys/prctl.h>
47 #include <sys/signal.h> 49 #include <sys/signal.h>
48 #else 50 #else
49 #include <signal.h> 51 #include <signal.h>
(...skipping 40 matching lines...) Expand 10 before | Expand all | Expand 10 after
90 "the policies haven't been loaded into the kernel?)"; 92 "the policies haven't been loaded into the kernel?)";
91 } 93 }
92 } 94 }
93 #endif // CHROMIUM_SELINUX 95 #endif // CHROMIUM_SELINUX
94 96
95 // This is the object which implements the zygote. The ZygoteMain function, 97 // This is the object which implements the zygote. The ZygoteMain function,
96 // which is called from ChromeMain, simply constructs one of these objects and 98 // which is called from ChromeMain, simply constructs one of these objects and
97 // runs it. 99 // runs it.
98 class Zygote { 100 class Zygote {
99 public: 101 public:
100 explicit Zygote(int sandbox_flags) 102 explicit Zygote(int sandbox_flags, ZygoteForkDelegate* helper)
101 : sandbox_flags_(sandbox_flags) { 103 : sandbox_flags_(sandbox_flags),
104 helper_(helper) {
102 } 105 }
103 106
104 bool ProcessRequests() { 107 bool ProcessRequests() {
105 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the 108 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
106 // browser on it. 109 // browser on it.
107 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel. 110 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel.
108 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC 111 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
109 112
110 // We need to accept SIGCHLD, even though our handler is a no-op because 113 // We need to accept SIGCHLD, even though our handler is a no-op because
111 // otherwise we cannot wait on children. (According to POSIX 2001.) 114 // otherwise we cannot wait on children. (According to POSIX 2001.)
(...skipping 41 matching lines...) Expand 10 before | Expand all | Expand 10 after
153 156
154 if (len == -1) { 157 if (len == -1) {
155 PLOG(ERROR) << "Error reading message from browser"; 158 PLOG(ERROR) << "Error reading message from browser";
156 return false; 159 return false;
157 } 160 }
158 161
159 Pickle pickle(buf, len); 162 Pickle pickle(buf, len);
160 void* iter = NULL; 163 void* iter = NULL;
161 164
162 int kind; 165 int kind;
166 std::string process_type;
163 if (pickle.ReadInt(&iter, &kind)) { 167 if (pickle.ReadInt(&iter, &kind)) {
164 switch (kind) { 168 switch (kind) {
165 case ZygoteHost::kCmdFork: 169 case ZygoteHost::kCmdFork:
166 // This function call can return multiple times, once per fork(). 170 // This function call can return multiple times, once per fork().
167 return HandleForkRequest(fd, pickle, iter, fds); 171 pickle.ReadString(&iter, &process_type);
172 return HandleForkRequest(fd, pickle, iter, fds, process_type);
173
168 case ZygoteHost::kCmdReap: 174 case ZygoteHost::kCmdReap:
169 if (!fds.empty()) 175 if (!fds.empty())
170 break; 176 break;
171 HandleReapRequest(fd, pickle, iter); 177 HandleReapRequest(fd, pickle, iter);
172 return false; 178 return false;
173 case ZygoteHost::kCmdGetTerminationStatus: 179 case ZygoteHost::kCmdGetTerminationStatus:
174 if (!fds.empty()) 180 if (!fds.empty())
175 break; 181 break;
176 HandleGetTerminationStatus(fd, pickle, iter); 182 HandleGetTerminationStatus(fd, pickle, iter);
177 return false; 183 return false;
(...skipping 62 matching lines...) Expand 10 before | Expand all | Expand 10 after
240 ssize_t written = 246 ssize_t written =
241 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); 247 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size()));
242 if (written != static_cast<ssize_t>(write_pickle.size())) 248 if (written != static_cast<ssize_t>(write_pickle.size()))
243 PLOG(ERROR) << "write"; 249 PLOG(ERROR) << "write";
244 } 250 }
245 251
246 // This is equivalent to fork(), except that, when using the SUID 252 // This is equivalent to fork(), except that, when using the SUID
247 // sandbox, it returns the real PID of the child process as it 253 // sandbox, it returns the real PID of the child process as it
248 // appears outside the sandbox, rather than returning the PID inside 254 // appears outside the sandbox, rather than returning the PID inside
249 // the sandbox. 255 // the sandbox.
250 int ForkWithRealPid() { 256 int ForkWithRealPid(const std::string process_type, std::vector<int>& fds) {
251 if (!g_suid_sandbox_active) 257 if (!g_suid_sandbox_active) {
252 return fork(); 258 VLOG(1) << "suid sandbox NOT active";
259 VLOG(1) << "fds.size() is " << fds.size();
260 if (helper_->CanHelp(process_type)) {
261 return helper_->Fork(fds);
262 } else {
263 return fork();
264 }
265 }
253 266
254 int dummy_fd; 267 int dummy_fd;
255 ino_t dummy_inode; 268 ino_t dummy_inode;
256 int pipe_fds[2] = { -1, -1 }; 269 int pipe_fds[2] = { -1, -1 };
257 base::ProcessId pid = 0; 270 base::ProcessId pid = 0;
258 271
259 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0); 272 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
260 if (dummy_fd < 0) { 273 if (dummy_fd < 0) {
261 LOG(ERROR) << "Failed to create dummy FD"; 274 LOG(ERROR) << "Failed to create dummy FD";
262 goto error; 275 goto error;
263 } 276 }
264 if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd)) { 277 if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd)) {
265 LOG(ERROR) << "Failed to get inode for dummy FD"; 278 LOG(ERROR) << "Failed to get inode for dummy FD";
266 goto error; 279 goto error;
267 } 280 }
268 if (pipe(pipe_fds) != 0) { 281 if (pipe(pipe_fds) != 0) {
269 LOG(ERROR) << "Failed to create pipe"; 282 LOG(ERROR) << "Failed to create pipe";
270 goto error; 283 goto error;
271 } 284 }
272 285
273 pid = fork(); 286 if (helper_->CanHelp(process_type)) {
287 fds.push_back(dummy_fd);
288 fds.push_back(pipe_fds[0]);
289 pid = helper_->Fork(fds);
290 } else {
291 pid = fork();
292 }
274 if (pid < 0) { 293 if (pid < 0) {
275 goto error; 294 goto error;
276 } else if (pid == 0) { 295 } else if (pid == 0) {
277 // In the child process. 296 // In the child process.
278 close(pipe_fds[1]); 297 close(pipe_fds[1]);
279 char buffer[1]; 298 char buffer[1];
280 // Wait until the parent process has discovered our PID. We 299 // Wait until the parent process has discovered our PID. We
281 // should not fork any child processes (which the seccomp 300 // should not fork any child processes (which the seccomp
282 // sandbox does) until then, because that can interfere with the 301 // sandbox does) until then, because that can interfere with the
283 // parent's discovery of our PID. 302 // parent's discovery of our PID.
(...skipping 51 matching lines...) Expand 10 before | Expand all | Expand 10 after
335 close(dummy_fd); 354 close(dummy_fd);
336 if (pipe_fds[0] >= 0) 355 if (pipe_fds[0] >= 0)
337 close(pipe_fds[0]); 356 close(pipe_fds[0]);
338 if (pipe_fds[1] >= 0) 357 if (pipe_fds[1] >= 0)
339 close(pipe_fds[1]); 358 close(pipe_fds[1]);
340 return -1; 359 return -1;
341 } 360 }
342 361
343 // Handle a 'fork' request from the browser: this means that the browser 362 // Handle a 'fork' request from the browser: this means that the browser
344 // wishes to start a new renderer. 363 // wishes to start a new renderer.
345 bool HandleForkRequest(int fd, const Pickle& pickle, void* iter, 364 bool HandleForkRequest(int fd, const Pickle& pickle,
346 std::vector<int>& fds) { 365 void* iter, std::vector<int>& fds,
366 const std::string process_type) {
347 std::vector<std::string> args; 367 std::vector<std::string> args;
348 int argc, numfds; 368 int argc, numfds;
349 base::GlobalDescriptors::Mapping mapping; 369 base::GlobalDescriptors::Mapping mapping;
350 base::ProcessId child; 370 base::ProcessId child;
351 371
352 if (!pickle.ReadInt(&iter, &argc)) 372 if (!pickle.ReadInt(&iter, &argc))
353 goto error; 373 goto error;
354 374
355 for (int i = 0; i < argc; ++i) { 375 for (int i = 0; i < argc; ++i) {
356 std::string arg; 376 std::string arg;
(...skipping 10 matching lines...) Expand all
367 for (int i = 0; i < numfds; ++i) { 387 for (int i = 0; i < numfds; ++i) {
368 base::GlobalDescriptors::Key key; 388 base::GlobalDescriptors::Key key;
369 if (!pickle.ReadUInt32(&iter, &key)) 389 if (!pickle.ReadUInt32(&iter, &key))
370 goto error; 390 goto error;
371 mapping.push_back(std::make_pair(key, fds[i])); 391 mapping.push_back(std::make_pair(key, fds[i]));
372 } 392 }
373 393
374 mapping.push_back(std::make_pair( 394 mapping.push_back(std::make_pair(
375 static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor)); 395 static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor));
376 396
377 child = ForkWithRealPid(); 397 child = ForkWithRealPid(process_type, fds);
378 398
379 if (!child) { 399 if (!child) {
380 #if defined(SECCOMP_SANDBOX) 400 #if defined(SECCOMP_SANDBOX)
381 // Try to open /proc/self/maps as the seccomp sandbox needs access to it 401 // Try to open /proc/self/maps as the seccomp sandbox needs access to it
382 if (g_proc_fd >= 0) { 402 if (g_proc_fd >= 0) {
383 int proc_self_maps = openat(g_proc_fd, "self/maps", O_RDONLY); 403 int proc_self_maps = openat(g_proc_fd, "self/maps", O_RDONLY);
384 if (proc_self_maps >= 0) { 404 if (proc_self_maps >= 0) {
385 SeccompSandboxSetProcSelfMaps(proc_self_maps); 405 SeccompSandboxSetProcSelfMaps(proc_self_maps);
386 } 406 }
387 close(g_proc_fd); 407 close(g_proc_fd);
(...skipping 52 matching lines...) Expand 10 before | Expand all | Expand 10 after
440 return false; 460 return false;
441 } 461 }
442 462
443 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs 463 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs
444 // fork() returns are not the real PIDs, so we need to map the Real PIDS 464 // fork() returns are not the real PIDs, so we need to map the Real PIDS
445 // into the sandbox PID namespace. 465 // into the sandbox PID namespace.
446 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; 466 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap;
447 ProcessMap real_pids_to_sandbox_pids; 467 ProcessMap real_pids_to_sandbox_pids;
448 468
449 const int sandbox_flags_; 469 const int sandbox_flags_;
470 ZygoteForkDelegate* helper_;
450 }; 471 };
451 472
452 // With SELinux we can carve out a precise sandbox, so we don't have to play 473 // With SELinux we can carve out a precise sandbox, so we don't have to play
453 // with intercepting libc calls. 474 // with intercepting libc calls.
454 #if !defined(CHROMIUM_SELINUX) 475 #if !defined(CHROMIUM_SELINUX)
455 476
456 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output, 477 static void ProxyLocaltimeCallToBrowser(time_t input, struct tm* output,
457 char* timezone_out, 478 char* timezone_out,
458 size_t timezone_out_len) { 479 size_t timezone_out_len) {
459 Pickle request; 480 Pickle request;
(...skipping 238 matching lines...) Expand 10 before | Expand all | Expand 10 after
698 #else // CHROMIUM_SELINUX 719 #else // CHROMIUM_SELINUX
699 720
700 static bool EnterSandbox() { 721 static bool EnterSandbox() {
701 PreSandboxInit(); 722 PreSandboxInit();
702 SkiaFontConfigUseIPCImplementation(kMagicSandboxIPCDescriptor); 723 SkiaFontConfigUseIPCImplementation(kMagicSandboxIPCDescriptor);
703 return true; 724 return true;
704 } 725 }
705 726
706 #endif // CHROMIUM_SELINUX 727 #endif // CHROMIUM_SELINUX
707 728
708 bool ZygoteMain(const MainFunctionParams& params) { 729 bool ZygoteMain(const MainFunctionParams& params,
730 ZygoteForkDelegate* forkdelegate) {
709 #if !defined(CHROMIUM_SELINUX) 731 #if !defined(CHROMIUM_SELINUX)
710 g_am_zygote_or_renderer = true; 732 g_am_zygote_or_renderer = true;
711 #endif 733 #endif
712 734
713 #if defined(SECCOMP_SANDBOX) 735 #if defined(SECCOMP_SANDBOX)
714 // The seccomp sandbox needs access to files in /proc, which might be denied 736 // The seccomp sandbox needs access to files in /proc, which might be denied
715 // after one of the other sandboxes have been started. So, obtain a suitable 737 // after one of the other sandboxes have been started. So, obtain a suitable
716 // file handle in advance. 738 // file handle in advance.
717 if (CommandLine::ForCurrentProcess()->HasSwitch( 739 if (CommandLine::ForCurrentProcess()->HasSwitch(
718 switches::kEnableSeccompSandbox)) { 740 switches::kEnableSeccompSandbox)) {
719 g_proc_fd = open("/proc", O_DIRECTORY | O_RDONLY); 741 g_proc_fd = open("/proc", O_DIRECTORY | O_RDONLY);
720 if (g_proc_fd < 0) { 742 if (g_proc_fd < 0) {
721 LOG(ERROR) << "WARNING! Cannot access \"/proc\". Disabling seccomp " 743 LOG(ERROR) << "WARNING! Cannot access \"/proc\". Disabling seccomp "
722 "sandboxing."; 744 "sandboxing.";
723 } 745 }
724 } 746 }
725 #endif // SECCOMP_SANDBOX 747 #endif // SECCOMP_SANDBOX
726 748
749 // initialize the fork helper
750 VLOG(1) << "initializing fork delegate";
751 forkdelegate->Init(getenv("SBX_D") != NULL, // g_suid_sandbox_active,
752 kBrowserDescriptor, kMagicSandboxIPCDescriptor);
753
727 // Turn on the SELinux or SUID sandbox 754 // Turn on the SELinux or SUID sandbox
728 if (!EnterSandbox()) { 755 if (!EnterSandbox()) {
729 LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " 756 LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: "
730 << errno << ")"; 757 << errno << ")";
731 return false; 758 return false;
732 } 759 }
733 760
734 int sandbox_flags = 0; 761 int sandbox_flags = 0;
735 if (getenv("SBX_D")) 762 if (getenv("SBX_D"))
736 sandbox_flags |= ZygoteHost::kSandboxSUID; 763 sandbox_flags |= ZygoteHost::kSandboxSUID;
(...skipping 16 matching lines...) Expand all
753 LOG(ERROR) << "WARNING! This machine lacks support needed for the " 780 LOG(ERROR) << "WARNING! This machine lacks support needed for the "
754 "Seccomp sandbox. Running renderers with Seccomp " 781 "Seccomp sandbox. Running renderers with Seccomp "
755 "sandboxing disabled."; 782 "sandboxing disabled.";
756 } else { 783 } else {
757 VLOG(1) << "Enabling experimental Seccomp sandbox."; 784 VLOG(1) << "Enabling experimental Seccomp sandbox.";
758 sandbox_flags |= ZygoteHost::kSandboxSeccomp; 785 sandbox_flags |= ZygoteHost::kSandboxSeccomp;
759 } 786 }
760 } 787 }
761 #endif // SECCOMP_SANDBOX 788 #endif // SECCOMP_SANDBOX
762 789
763 Zygote zygote(sandbox_flags); 790 Zygote zygote(sandbox_flags, forkdelegate);
764 // This function call can return multiple times, once per fork(). 791 // This function call can return multiple times, once per fork().
765 return zygote.ProcessRequests(); 792 return zygote.ProcessRequests();
766 } 793 }
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698