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

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

Powered by Google App Engine
This is Rietveld 408576698