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