[content shell] hook up testRunner.dumpEditingCallbacks
[chromium-blink-merge.git] / content / zygote / zygote_linux.cc
blob2ae6784c6a87005d915b2c3685338dc9c623f975
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
3 // found in the LICENSE file.
5 #include "content/zygote/zygote_linux.h"
7 #include <fcntl.h>
8 #include <string.h>
9 #include <sys/socket.h>
10 #include <sys/types.h>
11 #include <sys/wait.h>
13 #include "base/command_line.h"
14 #include "ipc/ipc_switches.h"
15 #include "content/public/common/sandbox_linux.h"
16 #include "base/process_util.h"
17 #include "content/public/common/result_codes.h"
18 #include "ipc/ipc_channel.h"
19 #include "base/debug/trace_event.h"
20 #include "base/file_util.h"
21 #include "base/linux_util.h"
22 #include "base/logging.h"
23 #include "base/pickle.h"
24 #include "base/posix/eintr_wrapper.h"
25 #include "base/posix/global_descriptors.h"
26 #include "base/posix/unix_domain_socket.h"
27 #include "content/common/set_process_title.h"
28 #include "content/common/sandbox_linux.h"
29 #include "content/common/zygote_commands_linux.h"
30 #include "content/public/common/content_descriptors.h"
31 #include "content/public/common/zygote_fork_delegate_linux.h"
33 #if defined(CHROMIUM_SELINUX)
34 #include <selinux/selinux.h>
35 #include <selinux/context.h>
36 #endif
38 // See http://code.google.com/p/chromium/wiki/LinuxZygote
40 namespace content {
42 namespace {
44 // NOP function. See below where this handler is installed.
45 void SIGCHLDHandler(int signal) {
48 #if defined(CHROMIUM_SELINUX)
49 void SELinuxTransitionToTypeOrDie(const char* type) {
50 security_context_t security_context;
51 if (getcon(&security_context))
52 LOG(FATAL) << "Cannot get SELinux context";
54 context_t context = context_new(security_context);
55 context_type_set(context, type);
56 const int r = setcon(context_str(context));
57 context_free(context);
58 freecon(security_context);
60 if (r) {
61 LOG(FATAL) << "dynamic transition to type '" << type << "' failed. "
62 "(this binary has been built with SELinux support, but maybe "
63 "the policies haven't been loaded into the kernel?)";
66 #endif // CHROMIUM_SELINUX
68 } // namespace
70 Zygote::Zygote(int sandbox_flags,
71 ZygoteForkDelegate* helper)
72 : sandbox_flags_(sandbox_flags),
73 helper_(helper),
74 initial_uma_sample_(0),
75 initial_uma_boundary_value_(0) {
76 if (helper_) {
77 helper_->InitialUMA(&initial_uma_name_,
78 &initial_uma_sample_,
79 &initial_uma_boundary_value_);
83 Zygote::~Zygote() {
86 bool Zygote::ProcessRequests() {
87 // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
88 // browser on it.
89 // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel.
90 // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
92 // We need to accept SIGCHLD, even though our handler is a no-op because
93 // otherwise we cannot wait on children. (According to POSIX 2001.)
94 struct sigaction action;
95 memset(&action, 0, sizeof(action));
96 action.sa_handler = &SIGCHLDHandler;
97 CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
99 if (UsingSUIDSandbox()) {
100 // Let the ZygoteHost know we are ready to go.
101 // The receiving code is in content/browser/zygote_host_linux.cc.
102 std::vector<int> empty;
103 bool r = UnixDomainSocket::SendMsg(kBrowserDescriptor,
104 kZygoteHelloMessage,
105 sizeof(kZygoteHelloMessage), empty);
106 #if defined(OS_CHROMEOS)
107 LOG_IF(WARNING, !r) << "Sending zygote magic failed";
108 // Exit normally on chromeos because session manager may send SIGTERM
109 // right after the process starts and it may fail to send zygote magic
110 // number to browser process.
111 if (!r)
112 _exit(RESULT_CODE_NORMAL_EXIT);
113 #else
114 CHECK(r) << "Sending zygote magic failed";
115 #endif
118 for (;;) {
119 // This function call can return multiple times, once per fork().
120 if (HandleRequestFromBrowser(kBrowserDescriptor))
121 return true;
125 bool Zygote::UsingSUIDSandbox() const {
126 return sandbox_flags_ & kSandboxLinuxSUID;
129 bool Zygote::HandleRequestFromBrowser(int fd) {
130 std::vector<int> fds;
131 char buf[kZygoteMaxMessageLength];
132 const ssize_t len = UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds);
134 if (len == 0 || (len == -1 && errno == ECONNRESET)) {
135 // EOF from the browser. We should die.
136 _exit(0);
137 return false;
140 if (len == -1) {
141 PLOG(ERROR) << "Error reading message from browser";
142 return false;
145 Pickle pickle(buf, len);
146 PickleIterator iter(pickle);
148 int kind;
149 if (pickle.ReadInt(&iter, &kind)) {
150 switch (kind) {
151 case kZygoteCommandFork:
152 // This function call can return multiple times, once per fork().
153 return HandleForkRequest(fd, pickle, iter, fds);
155 case kZygoteCommandReap:
156 if (!fds.empty())
157 break;
158 HandleReapRequest(fd, pickle, iter);
159 return false;
160 case kZygoteCommandGetTerminationStatus:
161 if (!fds.empty())
162 break;
163 HandleGetTerminationStatus(fd, pickle, iter);
164 return false;
165 case kZygoteCommandGetSandboxStatus:
166 HandleGetSandboxStatus(fd, pickle, iter);
167 return false;
168 default:
169 NOTREACHED();
170 break;
174 LOG(WARNING) << "Error parsing message from browser";
175 for (std::vector<int>::const_iterator
176 i = fds.begin(); i != fds.end(); ++i)
177 close(*i);
178 return false;
181 void Zygote::HandleReapRequest(int fd,
182 const Pickle& pickle,
183 PickleIterator iter) {
184 base::ProcessId child;
185 base::ProcessId actual_child;
187 if (!pickle.ReadInt(&iter, &child)) {
188 LOG(WARNING) << "Error parsing reap request from browser";
189 return;
192 if (UsingSUIDSandbox()) {
193 actual_child = real_pids_to_sandbox_pids[child];
194 if (!actual_child)
195 return;
196 real_pids_to_sandbox_pids.erase(child);
197 } else {
198 actual_child = child;
201 base::EnsureProcessTerminated(actual_child);
204 void Zygote::HandleGetTerminationStatus(int fd,
205 const Pickle& pickle,
206 PickleIterator iter) {
207 bool known_dead;
208 base::ProcessHandle child;
210 if (!pickle.ReadBool(&iter, &known_dead) ||
211 !pickle.ReadInt(&iter, &child)) {
212 LOG(WARNING) << "Error parsing GetTerminationStatus request "
213 << "from browser";
214 return;
217 base::TerminationStatus status;
218 int exit_code;
219 if (UsingSUIDSandbox())
220 child = real_pids_to_sandbox_pids[child];
221 if (child) {
222 if (known_dead) {
223 // If we know that the process is already dead and the kernel is cleaning
224 // it up, we do want to wait until it becomes a zombie and not risk
225 // returning eroneously that it is still running. However, we do not
226 // want to risk a bug where we're told a process is dead when it's not.
227 // By sending SIGKILL, we make sure that WaitForTerminationStatus will
228 // return quickly even in this case.
229 if (kill(child, SIGKILL)) {
230 PLOG(ERROR) << "kill (" << child << ")";
232 status = base::WaitForTerminationStatus(child, &exit_code);
233 } else {
234 status = base::GetTerminationStatus(child, &exit_code);
236 } else {
237 // Assume that if we can't find the child in the sandbox, then
238 // it terminated normally.
239 status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
240 exit_code = RESULT_CODE_NORMAL_EXIT;
243 Pickle write_pickle;
244 write_pickle.WriteInt(static_cast<int>(status));
245 write_pickle.WriteInt(exit_code);
246 ssize_t written =
247 HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size()));
248 if (written != static_cast<ssize_t>(write_pickle.size()))
249 PLOG(ERROR) << "write";
252 int Zygote::ForkWithRealPid(const std::string& process_type,
253 std::vector<int>& fds,
254 const std::string& channel_switch,
255 std::string* uma_name,
256 int* uma_sample,
257 int* uma_boundary_value) {
258 const bool use_helper = (helper_ && helper_->CanHelp(process_type,
259 uma_name,
260 uma_sample,
261 uma_boundary_value));
262 if (!(use_helper || UsingSUIDSandbox())) {
263 return fork();
266 int dummy_fd;
267 ino_t dummy_inode;
268 int pipe_fds[2] = { -1, -1 };
269 base::ProcessId pid = 0;
271 dummy_fd = socket(PF_UNIX, SOCK_DGRAM, 0);
272 if (dummy_fd < 0) {
273 LOG(ERROR) << "Failed to create dummy FD";
274 goto error;
276 if (!base::FileDescriptorGetInode(&dummy_inode, dummy_fd)) {
277 LOG(ERROR) << "Failed to get inode for dummy FD";
278 goto error;
280 if (pipe(pipe_fds) != 0) {
281 LOG(ERROR) << "Failed to create pipe";
282 goto error;
285 if (use_helper) {
286 fds.push_back(dummy_fd);
287 fds.push_back(pipe_fds[0]);
288 pid = helper_->Fork(fds);
289 } else {
290 pid = fork();
292 if (pid < 0) {
293 goto error;
294 } else if (pid == 0) {
295 // In the child process.
296 close(pipe_fds[1]);
297 base::ProcessId real_pid;
298 // Wait until the parent process has discovered our PID. We
299 // should not fork any child processes (which the seccomp
300 // sandbox does) until then, because that can interfere with the
301 // parent's discovery of our PID.
302 if (!file_util::ReadFromFD(pipe_fds[0],
303 reinterpret_cast<char*>(&real_pid),
304 sizeof(real_pid))) {
305 LOG(FATAL) << "Failed to synchronise with parent zygote process";
307 if (real_pid <= 0) {
308 LOG(FATAL) << "Invalid pid from parent zygote";
310 #if defined(OS_LINUX)
311 // Sandboxed processes need to send the global, non-namespaced PID when
312 // setting up an IPC channel to their parent.
313 IPC::Channel::SetGlobalPid(real_pid);
314 // Force the real PID so chrome event data have a PID that corresponds
315 // to system trace event data.
316 base::debug::TraceLog::GetInstance()->SetProcessID(
317 static_cast<int>(real_pid));
318 #endif
319 close(pipe_fds[0]);
320 close(dummy_fd);
321 return 0;
322 } else {
323 // In the parent process.
324 close(dummy_fd);
325 dummy_fd = -1;
326 close(pipe_fds[0]);
327 pipe_fds[0] = -1;
328 base::ProcessId real_pid;
329 if (UsingSUIDSandbox()) {
330 uint8_t reply_buf[512];
331 Pickle request;
332 request.WriteInt(LinuxSandbox::METHOD_GET_CHILD_WITH_INODE);
333 request.WriteUInt64(dummy_inode);
335 const ssize_t r = UnixDomainSocket::SendRecvMsg(
336 kMagicSandboxIPCDescriptor, reply_buf, sizeof(reply_buf), NULL,
337 request);
338 if (r == -1) {
339 LOG(ERROR) << "Failed to get child process's real PID";
340 goto error;
343 Pickle reply(reinterpret_cast<char*>(reply_buf), r);
344 PickleIterator iter(reply);
345 if (!reply.ReadInt(&iter, &real_pid))
346 goto error;
347 if (real_pid <= 0) {
348 // METHOD_GET_CHILD_WITH_INODE failed. Did the child die already?
349 LOG(ERROR) << "METHOD_GET_CHILD_WITH_INODE failed";
350 goto error;
352 real_pids_to_sandbox_pids[real_pid] = pid;
354 if (use_helper) {
355 real_pid = pid;
356 if (!helper_->AckChild(pipe_fds[1], channel_switch)) {
357 LOG(ERROR) << "Failed to synchronise with zygote fork helper";
358 goto error;
360 } else {
361 int written =
362 HANDLE_EINTR(write(pipe_fds[1], &real_pid, sizeof(real_pid)));
363 if (written != sizeof(real_pid)) {
364 LOG(ERROR) << "Failed to synchronise with child process";
365 goto error;
368 close(pipe_fds[1]);
369 return real_pid;
372 error:
373 if (pid > 0) {
374 if (waitpid(pid, NULL, WNOHANG) == -1)
375 LOG(ERROR) << "Failed to wait for process";
377 if (dummy_fd >= 0)
378 close(dummy_fd);
379 if (pipe_fds[0] >= 0)
380 close(pipe_fds[0]);
381 if (pipe_fds[1] >= 0)
382 close(pipe_fds[1]);
383 return -1;
386 base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle,
387 PickleIterator iter,
388 std::vector<int>& fds,
389 std::string* uma_name,
390 int* uma_sample,
391 int* uma_boundary_value) {
392 std::vector<std::string> args;
393 int argc = 0;
394 int numfds = 0;
395 base::GlobalDescriptors::Mapping mapping;
396 std::string process_type;
397 std::string channel_id;
398 const std::string channel_id_prefix = std::string("--")
399 + switches::kProcessChannelID + std::string("=");
401 if (!pickle.ReadString(&iter, &process_type))
402 return -1;
403 if (!pickle.ReadInt(&iter, &argc))
404 return -1;
406 for (int i = 0; i < argc; ++i) {
407 std::string arg;
408 if (!pickle.ReadString(&iter, &arg))
409 return -1;
410 args.push_back(arg);
411 if (arg.compare(0, channel_id_prefix.length(), channel_id_prefix) == 0)
412 channel_id = arg;
415 if (!pickle.ReadInt(&iter, &numfds))
416 return -1;
417 if (numfds != static_cast<int>(fds.size()))
418 return -1;
420 for (int i = 0; i < numfds; ++i) {
421 base::GlobalDescriptors::Key key;
422 if (!pickle.ReadUInt32(&iter, &key))
423 return -1;
424 mapping.push_back(std::make_pair(key, fds[i]));
427 mapping.push_back(std::make_pair(
428 static_cast<uint32_t>(kSandboxIPCChannel), kMagicSandboxIPCDescriptor));
430 // Returns twice, once per process.
431 base::ProcessId child_pid = ForkWithRealPid(process_type, fds, channel_id,
432 uma_name, uma_sample,
433 uma_boundary_value);
434 if (!child_pid) {
435 // This is the child process.
437 // At this point, we finally know our process type.
438 LinuxSandbox::GetInstance()->PreinitializeSandboxFinish(process_type);
440 close(kBrowserDescriptor); // Our socket from the browser.
441 if (UsingSUIDSandbox())
442 close(kZygoteIdFd); // Another socket from the browser.
443 base::GlobalDescriptors::GetInstance()->Reset(mapping);
445 #if defined(CHROMIUM_SELINUX)
446 SELinuxTransitionToTypeOrDie("chromium_renderer_t");
447 #endif
449 // Reset the process-wide command line to our new command line.
450 CommandLine::Reset();
451 CommandLine::Init(0, NULL);
452 CommandLine::ForCurrentProcess()->InitFromArgv(args);
454 // Update the process title. The argv was already cached by the call to
455 // SetProcessTitleFromCommandLine in ChromeMain, so we can pass NULL here
456 // (we don't have the original argv at this point).
457 SetProcessTitleFromCommandLine(NULL);
458 } else if (child_pid < 0) {
459 LOG(ERROR) << "Zygote could not fork: process_type " << process_type
460 << " numfds " << numfds << " child_pid " << child_pid;
462 return child_pid;
465 bool Zygote::HandleForkRequest(int fd,
466 const Pickle& pickle,
467 PickleIterator iter,
468 std::vector<int>& fds) {
469 std::string uma_name;
470 int uma_sample;
471 int uma_boundary_value;
472 base::ProcessId child_pid = ReadArgsAndFork(pickle, iter, fds,
473 &uma_name, &uma_sample,
474 &uma_boundary_value);
475 if (child_pid == 0)
476 return true;
477 for (std::vector<int>::const_iterator
478 i = fds.begin(); i != fds.end(); ++i)
479 close(*i);
480 if (uma_name.empty()) {
481 // There is no UMA report from this particular fork.
482 // Use the initial UMA report if any, and clear that record for next time.
483 // Note the swap method here is the efficient way to do this, since
484 // we know uma_name is empty.
485 uma_name.swap(initial_uma_name_);
486 uma_sample = initial_uma_sample_;
487 uma_boundary_value = initial_uma_boundary_value_;
489 // Must always send reply, as ZygoteHost blocks while waiting for it.
490 Pickle reply_pickle;
491 reply_pickle.WriteInt(child_pid);
492 reply_pickle.WriteString(uma_name);
493 if (!uma_name.empty()) {
494 reply_pickle.WriteInt(uma_sample);
495 reply_pickle.WriteInt(uma_boundary_value);
497 if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) !=
498 static_cast<ssize_t> (reply_pickle.size()))
499 PLOG(ERROR) << "write";
500 return false;
503 bool Zygote::HandleGetSandboxStatus(int fd,
504 const Pickle& pickle,
505 PickleIterator iter) {
506 if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) !=
507 sizeof(sandbox_flags_)) {
508 PLOG(ERROR) << "write";
511 return false;
514 } // namespace content