OLD | NEW |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 Loading... |
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 } |
OLD | NEW |