OLD | NEW |
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/browser/zygote_host_impl_linux.h" | |
6 | |
7 #include <dlfcn.h> | 5 #include <dlfcn.h> |
8 #include <fcntl.h> | 6 #include <fcntl.h> |
9 #include <pthread.h> | 7 #include <pthread.h> |
10 #include <stdio.h> | 8 #include <stdio.h> |
11 #include <sys/socket.h> | 9 #include <sys/socket.h> |
12 #include <sys/stat.h> | 10 #include <sys/stat.h> |
13 #include <sys/types.h> | 11 #include <sys/types.h> |
14 #include <sys/wait.h> | 12 #include <sys/wait.h> |
15 #include <unistd.h> | 13 #include <unistd.h> |
16 | 14 |
(...skipping 14 matching lines...) Expand all Loading... |
31 #include "base/sys_info.h" | 29 #include "base/sys_info.h" |
32 #include "build/build_config.h" | 30 #include "build/build_config.h" |
33 #include "crypto/nss_util.h" | 31 #include "crypto/nss_util.h" |
34 #include "content/common/chrome_descriptors.h" | 32 #include "content/common/chrome_descriptors.h" |
35 #include "content/common/font_config_ipc_linux.h" | 33 #include "content/common/font_config_ipc_linux.h" |
36 #include "content/common/pepper_plugin_registry.h" | 34 #include "content/common/pepper_plugin_registry.h" |
37 #include "content/common/sandbox_methods_linux.h" | 35 #include "content/common/sandbox_methods_linux.h" |
38 #include "content/common/seccomp_sandbox.h" | 36 #include "content/common/seccomp_sandbox.h" |
39 #include "content/common/set_process_title.h" | 37 #include "content/common/set_process_title.h" |
40 #include "content/common/unix_domain_socket_posix.h" | 38 #include "content/common/unix_domain_socket_posix.h" |
| 39 #include "content/common/zygote_commands_linux.h" |
41 #include "content/public/common/content_switches.h" | 40 #include "content/public/common/content_switches.h" |
42 #include "content/public/common/main_function_params.h" | 41 #include "content/public/common/main_function_params.h" |
43 #include "content/public/common/result_codes.h" | 42 #include "content/public/common/result_codes.h" |
| 43 #include "content/public/common/sandbox_linux.h" |
44 #include "content/public/common/zygote_fork_delegate_linux.h" | 44 #include "content/public/common/zygote_fork_delegate_linux.h" |
45 #include "skia/ext/SkFontHost_fontconfig_control.h" | 45 #include "skia/ext/SkFontHost_fontconfig_control.h" |
46 #include "unicode/timezone.h" | 46 #include "unicode/timezone.h" |
47 #include "ipc/ipc_channel.h" | 47 #include "ipc/ipc_channel.h" |
48 #include "ipc/ipc_switches.h" | 48 #include "ipc/ipc_switches.h" |
49 | 49 |
50 #if defined(OS_LINUX) | 50 #if defined(OS_LINUX) |
51 #include <sys/epoll.h> | 51 #include <sys/epoll.h> |
52 #include <sys/prctl.h> | 52 #include <sys/prctl.h> |
53 #include <sys/signal.h> | 53 #include <sys/signal.h> |
54 #else | 54 #else |
55 #include <signal.h> | 55 #include <signal.h> |
56 #endif | 56 #endif |
57 | 57 |
58 #if defined(CHROMIUM_SELINUX) | 58 #if defined(CHROMIUM_SELINUX) |
59 #include <selinux/selinux.h> | 59 #include <selinux/selinux.h> |
60 #include <selinux/context.h> | 60 #include <selinux/context.h> |
61 #endif | 61 #endif |
62 | 62 |
| 63 namespace content { |
| 64 |
63 // http://code.google.com/p/chromium/wiki/LinuxZygote | 65 // http://code.google.com/p/chromium/wiki/LinuxZygote |
64 | 66 |
65 static const int kBrowserDescriptor = 3; | 67 static const int kBrowserDescriptor = 3; |
66 static const int kMagicSandboxIPCDescriptor = 5; | 68 static const int kMagicSandboxIPCDescriptor = 5; |
67 static const int kZygoteIdDescriptor = 7; | 69 static const int kZygoteIdDescriptor = 7; |
68 static bool g_suid_sandbox_active = false; | 70 static bool g_suid_sandbox_active = false; |
69 | 71 |
70 static const char kUrandomDevPath[] = "/dev/urandom"; | 72 static const char kUrandomDevPath[] = "/dev/urandom"; |
71 | 73 |
72 #if defined(SECCOMP_SANDBOX) | 74 #if defined(SECCOMP_SANDBOX) |
(...skipping 18 matching lines...) Expand all Loading... |
91 "the policies haven't been loaded into the kernel?)"; | 93 "the policies haven't been loaded into the kernel?)"; |
92 } | 94 } |
93 } | 95 } |
94 #endif // CHROMIUM_SELINUX | 96 #endif // CHROMIUM_SELINUX |
95 | 97 |
96 // This is the object which implements the zygote. The ZygoteMain function, | 98 // This is the object which implements the zygote. The ZygoteMain function, |
97 // which is called from ChromeMain, simply constructs one of these objects and | 99 // which is called from ChromeMain, simply constructs one of these objects and |
98 // runs it. | 100 // runs it. |
99 class Zygote { | 101 class Zygote { |
100 public: | 102 public: |
101 Zygote(int sandbox_flags, content::ZygoteForkDelegate* helper) | 103 Zygote(int sandbox_flags, ZygoteForkDelegate* helper) |
102 : sandbox_flags_(sandbox_flags), | 104 : sandbox_flags_(sandbox_flags), |
103 helper_(helper), | 105 helper_(helper), |
104 initial_uma_sample_(0), | 106 initial_uma_sample_(0), |
105 initial_uma_boundary_value_(0) { | 107 initial_uma_boundary_value_(0) { |
106 if (helper_) | 108 if (helper_) |
107 helper_->InitialUMA(&initial_uma_name_, | 109 helper_->InitialUMA(&initial_uma_name_, |
108 &initial_uma_sample_, | 110 &initial_uma_sample_, |
109 &initial_uma_boundary_value_); | 111 &initial_uma_boundary_value_); |
110 } | 112 } |
111 | 113 |
112 bool ProcessRequests() { | 114 bool ProcessRequests() { |
113 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the | 115 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the |
114 // browser on it. | 116 // browser on it. |
115 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel. | 117 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel. |
116 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC | 118 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC |
117 | 119 |
118 // We need to accept SIGCHLD, even though our handler is a no-op because | 120 // We need to accept SIGCHLD, even though our handler is a no-op because |
119 // otherwise we cannot wait on children. (According to POSIX 2001.) | 121 // otherwise we cannot wait on children. (According to POSIX 2001.) |
120 struct sigaction action; | 122 struct sigaction action; |
121 memset(&action, 0, sizeof(action)); | 123 memset(&action, 0, sizeof(action)); |
122 action.sa_handler = SIGCHLDHandler; | 124 action.sa_handler = SIGCHLDHandler; |
123 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); | 125 CHECK(sigaction(SIGCHLD, &action, NULL) == 0); |
124 | 126 |
125 if (g_suid_sandbox_active) { | 127 if (g_suid_sandbox_active) { |
126 // Let the ZygoteHost know we are ready to go. | 128 // Let the ZygoteHost know we are ready to go. |
127 // The receiving code is in content/browser/zygote_host_linux.cc. | 129 // The receiving code is in content/browser/zygote_host_linux.cc. |
128 std::vector<int> empty; | 130 std::vector<int> empty; |
129 bool r = UnixDomainSocket::SendMsg(kBrowserDescriptor, kZygoteMagic, | 131 bool r = UnixDomainSocket::SendMsg(kBrowserDescriptor, |
130 sizeof(kZygoteMagic), empty); | 132 kZygoteHelloMessage, |
| 133 sizeof(kZygoteHelloMessage), empty); |
131 #if defined(OS_CHROMEOS) | 134 #if defined(OS_CHROMEOS) |
132 LOG_IF(WARNING, !r) << "Sending zygote magic failed"; | 135 LOG_IF(WARNING, !r) << "Sending zygote magic failed"; |
133 // Exit normally on chromeos because session manager may send SIGTERM | 136 // Exit normally on chromeos because session manager may send SIGTERM |
134 // right after the process starts and it may fail to send zygote magic | 137 // right after the process starts and it may fail to send zygote magic |
135 // number to browser process. | 138 // number to browser process. |
136 if (!r) | 139 if (!r) |
137 _exit(content::RESULT_CODE_NORMAL_EXIT); | 140 _exit(RESULT_CODE_NORMAL_EXIT); |
138 #else | 141 #else |
139 CHECK(r) << "Sending zygote magic failed"; | 142 CHECK(r) << "Sending zygote magic failed"; |
140 #endif | 143 #endif |
141 } | 144 } |
142 | 145 |
143 for (;;) { | 146 for (;;) { |
144 // This function call can return multiple times, once per fork(). | 147 // This function call can return multiple times, once per fork(). |
145 if (HandleRequestFromBrowser(kBrowserDescriptor)) | 148 if (HandleRequestFromBrowser(kBrowserDescriptor)) |
146 return true; | 149 return true; |
147 } | 150 } |
(...skipping 24 matching lines...) Expand all Loading... |
172 PLOG(ERROR) << "Error reading message from browser"; | 175 PLOG(ERROR) << "Error reading message from browser"; |
173 return false; | 176 return false; |
174 } | 177 } |
175 | 178 |
176 Pickle pickle(buf, len); | 179 Pickle pickle(buf, len); |
177 PickleIterator iter(pickle); | 180 PickleIterator iter(pickle); |
178 | 181 |
179 int kind; | 182 int kind; |
180 if (pickle.ReadInt(&iter, &kind)) { | 183 if (pickle.ReadInt(&iter, &kind)) { |
181 switch (kind) { | 184 switch (kind) { |
182 case ZygoteHostImpl::kCmdFork: | 185 case kZygoteCommandFork: |
183 // This function call can return multiple times, once per fork(). | 186 // This function call can return multiple times, once per fork(). |
184 return HandleForkRequest(fd, pickle, iter, fds); | 187 return HandleForkRequest(fd, pickle, iter, fds); |
185 | 188 |
186 case ZygoteHostImpl::kCmdReap: | 189 case kZygoteCommandReap: |
187 if (!fds.empty()) | 190 if (!fds.empty()) |
188 break; | 191 break; |
189 HandleReapRequest(fd, pickle, iter); | 192 HandleReapRequest(fd, pickle, iter); |
190 return false; | 193 return false; |
191 case ZygoteHostImpl::kCmdGetTerminationStatus: | 194 case kZygoteCommandGetTerminationStatus: |
192 if (!fds.empty()) | 195 if (!fds.empty()) |
193 break; | 196 break; |
194 HandleGetTerminationStatus(fd, pickle, iter); | 197 HandleGetTerminationStatus(fd, pickle, iter); |
195 return false; | 198 return false; |
196 case ZygoteHostImpl::kCmdGetSandboxStatus: | 199 case kZygoteCommandGetSandboxStatus: |
197 HandleGetSandboxStatus(fd, pickle, iter); | 200 HandleGetSandboxStatus(fd, pickle, iter); |
198 return false; | 201 return false; |
199 default: | 202 default: |
200 NOTREACHED(); | 203 NOTREACHED(); |
201 break; | 204 break; |
202 } | 205 } |
203 } | 206 } |
204 | 207 |
205 LOG(WARNING) << "Error parsing message from browser"; | 208 LOG(WARNING) << "Error parsing message from browser"; |
206 for (std::vector<int>::const_iterator | 209 for (std::vector<int>::const_iterator |
(...skipping 37 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
244 base::TerminationStatus status; | 247 base::TerminationStatus status; |
245 int exit_code; | 248 int exit_code; |
246 if (g_suid_sandbox_active) | 249 if (g_suid_sandbox_active) |
247 child = real_pids_to_sandbox_pids[child]; | 250 child = real_pids_to_sandbox_pids[child]; |
248 if (child) { | 251 if (child) { |
249 status = base::GetTerminationStatus(child, &exit_code); | 252 status = base::GetTerminationStatus(child, &exit_code); |
250 } else { | 253 } else { |
251 // Assume that if we can't find the child in the sandbox, then | 254 // Assume that if we can't find the child in the sandbox, then |
252 // it terminated normally. | 255 // it terminated normally. |
253 status = base::TERMINATION_STATUS_NORMAL_TERMINATION; | 256 status = base::TERMINATION_STATUS_NORMAL_TERMINATION; |
254 exit_code = content::RESULT_CODE_NORMAL_EXIT; | 257 exit_code = RESULT_CODE_NORMAL_EXIT; |
255 } | 258 } |
256 | 259 |
257 Pickle write_pickle; | 260 Pickle write_pickle; |
258 write_pickle.WriteInt(static_cast<int>(status)); | 261 write_pickle.WriteInt(static_cast<int>(status)); |
259 write_pickle.WriteInt(exit_code); | 262 write_pickle.WriteInt(exit_code); |
260 ssize_t written = | 263 ssize_t written = |
261 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); | 264 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size())); |
262 if (written != static_cast<ssize_t>(write_pickle.size())) | 265 if (written != static_cast<ssize_t>(write_pickle.size())) |
263 PLOG(ERROR) << "write"; | 266 PLOG(ERROR) << "write"; |
264 } | 267 } |
(...skipping 278 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
543 return false; | 546 return false; |
544 } | 547 } |
545 | 548 |
546 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs | 549 // In the SUID sandbox, we try to use a new PID namespace. Thus the PIDs |
547 // fork() returns are not the real PIDs, so we need to map the Real PIDS | 550 // fork() returns are not the real PIDs, so we need to map the Real PIDS |
548 // into the sandbox PID namespace. | 551 // into the sandbox PID namespace. |
549 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; | 552 typedef base::hash_map<base::ProcessHandle, base::ProcessHandle> ProcessMap; |
550 ProcessMap real_pids_to_sandbox_pids; | 553 ProcessMap real_pids_to_sandbox_pids; |
551 | 554 |
552 const int sandbox_flags_; | 555 const int sandbox_flags_; |
553 content::ZygoteForkDelegate* helper_; | 556 ZygoteForkDelegate* helper_; |
554 | 557 |
555 // These might be set by helper_->InitialUMA. They supply a UMA | 558 // These might be set by helper_->InitialUMA. They supply a UMA |
556 // enumeration sample we should report on the first fork. | 559 // enumeration sample we should report on the first fork. |
557 std::string initial_uma_name_; | 560 std::string initial_uma_name_; |
558 int initial_uma_sample_; | 561 int initial_uma_sample_; |
559 int initial_uma_boundary_value_; | 562 int initial_uma_boundary_value_; |
560 }; | 563 }; |
561 | 564 |
562 // With SELinux we can carve out a precise sandbox, so we don't have to play | 565 // With SELinux we can carve out a precise sandbox, so we don't have to play |
563 // with intercepting libc calls. | 566 // with intercepting libc calls. |
(...skipping 372 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
936 | 939 |
937 static bool EnterSandbox() { | 940 static bool EnterSandbox() { |
938 PreSandboxInit(); | 941 PreSandboxInit(); |
939 SkiaFontConfigSetImplementation( | 942 SkiaFontConfigSetImplementation( |
940 new FontConfigIPC(kMagicSandboxIPCDescriptor)); | 943 new FontConfigIPC(kMagicSandboxIPCDescriptor)); |
941 return true; | 944 return true; |
942 } | 945 } |
943 | 946 |
944 #endif // CHROMIUM_SELINUX | 947 #endif // CHROMIUM_SELINUX |
945 | 948 |
946 bool ZygoteMain(const content::MainFunctionParams& params, | 949 bool ZygoteMain(const MainFunctionParams& params, |
947 content::ZygoteForkDelegate* forkdelegate) { | 950 ZygoteForkDelegate* forkdelegate) { |
948 #if !defined(CHROMIUM_SELINUX) | 951 #if !defined(CHROMIUM_SELINUX) |
949 g_am_zygote_or_renderer = true; | 952 g_am_zygote_or_renderer = true; |
950 #endif | 953 #endif |
951 | 954 |
952 #if defined(SECCOMP_SANDBOX) | 955 #if defined(SECCOMP_SANDBOX) |
953 if (SeccompSandboxEnabled()) { | 956 if (SeccompSandboxEnabled()) { |
954 // The seccomp sandbox needs access to files in /proc, which might be denied | 957 // The seccomp sandbox needs access to files in /proc, which might be denied |
955 // after one of the other sandboxes have been started. So, obtain a suitable | 958 // after one of the other sandboxes have been started. So, obtain a suitable |
956 // file handle in advance. | 959 // file handle in advance. |
957 g_proc_fd = open("/proc", O_DIRECTORY | O_RDONLY); | 960 g_proc_fd = open("/proc", O_DIRECTORY | O_RDONLY); |
(...skipping 15 matching lines...) Expand all Loading... |
973 | 976 |
974 // Turn on the SELinux or SUID sandbox | 977 // Turn on the SELinux or SUID sandbox |
975 if (!EnterSandbox()) { | 978 if (!EnterSandbox()) { |
976 LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " | 979 LOG(FATAL) << "Failed to enter sandbox. Fail safe abort. (errno: " |
977 << errno << ")"; | 980 << errno << ")"; |
978 return false; | 981 return false; |
979 } | 982 } |
980 | 983 |
981 int sandbox_flags = 0; | 984 int sandbox_flags = 0; |
982 if (getenv("SBX_D")) | 985 if (getenv("SBX_D")) |
983 sandbox_flags |= ZygoteHostImpl::kSandboxSUID; | 986 sandbox_flags |= kSandboxLinuxSUID; |
984 if (getenv("SBX_PID_NS")) | 987 if (getenv("SBX_PID_NS")) |
985 sandbox_flags |= ZygoteHostImpl::kSandboxPIDNS; | 988 sandbox_flags |= kSandboxLinuxPIDNS; |
986 if (getenv("SBX_NET_NS")) | 989 if (getenv("SBX_NET_NS")) |
987 sandbox_flags |= ZygoteHostImpl::kSandboxNetNS; | 990 sandbox_flags |= kSandboxLinuxNetNS; |
988 | 991 |
989 #if defined(SECCOMP_SANDBOX) | 992 #if defined(SECCOMP_SANDBOX) |
990 // The seccomp sandbox will be turned on when the renderers start. But we can | 993 // The seccomp sandbox will be turned on when the renderers start. But we can |
991 // already check if sufficient support is available so that we only need to | 994 // already check if sufficient support is available so that we only need to |
992 // print one error message for the entire browser session. | 995 // print one error message for the entire browser session. |
993 if (g_proc_fd >= 0 && SeccompSandboxEnabled()) { | 996 if (g_proc_fd >= 0 && SeccompSandboxEnabled()) { |
994 if (!SupportsSeccompSandbox(g_proc_fd)) { | 997 if (!SupportsSeccompSandbox(g_proc_fd)) { |
995 // There are a good number of users who cannot use the seccomp sandbox | 998 // There are a good number of users who cannot use the seccomp sandbox |
996 // (e.g. because their distribution does not enable seccomp mode by | 999 // (e.g. because their distribution does not enable seccomp mode by |
997 // default). While we would prefer to deny execution in this case, it | 1000 // default). While we would prefer to deny execution in this case, it |
998 // seems more realistic to continue in degraded mode. | 1001 // seems more realistic to continue in degraded mode. |
999 LOG(ERROR) << "WARNING! This machine lacks support needed for the " | 1002 LOG(ERROR) << "WARNING! This machine lacks support needed for the " |
1000 "Seccomp sandbox. Running renderers with Seccomp " | 1003 "Seccomp sandbox. Running renderers with Seccomp " |
1001 "sandboxing disabled."; | 1004 "sandboxing disabled."; |
1002 } else { | 1005 } else { |
1003 VLOG(1) << "Enabling experimental Seccomp sandbox."; | 1006 VLOG(1) << "Enabling experimental Seccomp sandbox."; |
1004 sandbox_flags |= ZygoteHostImpl::kSandboxSeccomp; | 1007 sandbox_flags |= kSandboxLinuxSeccomp; |
1005 } | 1008 } |
1006 } | 1009 } |
1007 #endif // SECCOMP_SANDBOX | 1010 #endif // SECCOMP_SANDBOX |
1008 | 1011 |
1009 Zygote zygote(sandbox_flags, forkdelegate); | 1012 Zygote zygote(sandbox_flags, forkdelegate); |
1010 // This function call can return multiple times, once per fork(). | 1013 // This function call can return multiple times, once per fork(). |
1011 return zygote.ProcessRequests(); | 1014 return zygote.ProcessRequests(); |
1012 } | 1015 } |
| 1016 |
| 1017 } // namespace content |
OLD | NEW |