• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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/macros.h"
19 #include "base/memory/scoped_vector.h"
20 #include "base/pickle.h"
21 #include "base/posix/eintr_wrapper.h"
22 #include "base/posix/global_descriptors.h"
23 #include "base/posix/unix_domain_socket_linux.h"
24 #include "base/process/kill.h"
25 #include "content/common/child_process_sandbox_support_impl_linux.h"
26 #include "content/common/sandbox_linux/sandbox_linux.h"
27 #include "content/common/set_process_title.h"
28 #include "content/common/zygote_commands_linux.h"
29 #include "content/public/common/content_descriptors.h"
30 #include "content/public/common/result_codes.h"
31 #include "content/public/common/sandbox_linux.h"
32 #include "content/public/common/zygote_fork_delegate_linux.h"
33 #include "ipc/ipc_channel.h"
34 #include "ipc/ipc_switches.h"
35 
36 #if defined(ADDRESS_SANITIZER)
37 #include <sanitizer/asan_interface.h>
38 #endif
39 
40 // See http://code.google.com/p/chromium/wiki/LinuxZygote
41 
42 namespace content {
43 
44 namespace {
45 
46 // NOP function. See below where this handler is installed.
SIGCHLDHandler(int signal)47 void SIGCHLDHandler(int signal) {
48 }
49 
LookUpFd(const base::GlobalDescriptors::Mapping & fd_mapping,uint32_t key)50 int LookUpFd(const base::GlobalDescriptors::Mapping& fd_mapping, uint32_t key) {
51   for (size_t index = 0; index < fd_mapping.size(); ++index) {
52     if (fd_mapping[index].first == key)
53       return fd_mapping[index].second;
54   }
55   return -1;
56 }
57 
CreatePipe(base::ScopedFD * read_pipe,base::ScopedFD * write_pipe)58 void CreatePipe(base::ScopedFD* read_pipe, base::ScopedFD* write_pipe) {
59   int raw_pipe[2];
60   PCHECK(0 == pipe(raw_pipe));
61   read_pipe->reset(raw_pipe[0]);
62   write_pipe->reset(raw_pipe[1]);
63 }
64 
KillAndReap(pid_t pid,ZygoteForkDelegate * helper)65 void KillAndReap(pid_t pid, ZygoteForkDelegate* helper) {
66   if (helper) {
67     // Helper children may be forked in another PID namespace, so |pid| might
68     // be meaningless to us; or we just might not be able to directly send it
69     // signals.  So we can't kill it.
70     // Additionally, we're not its parent, so we can't reap it anyway.
71     // TODO(mdempsky): Extend the ZygoteForkDelegate API to handle this.
72     LOG(WARNING) << "Unable to kill or reap helper children";
73     return;
74   }
75 
76   // Kill the child process in case it's not already dead, so we can safely
77   // perform a blocking wait.
78   PCHECK(0 == kill(pid, SIGKILL));
79   PCHECK(pid == HANDLE_EINTR(waitpid(pid, NULL, 0)));
80 }
81 
82 }  // namespace
83 
Zygote(int sandbox_flags,ScopedVector<ZygoteForkDelegate> helpers,const std::vector<base::ProcessHandle> & extra_children,const std::vector<int> & extra_fds)84 Zygote::Zygote(int sandbox_flags, ScopedVector<ZygoteForkDelegate> helpers,
85                const std::vector<base::ProcessHandle>& extra_children,
86                const std::vector<int>& extra_fds)
87     : sandbox_flags_(sandbox_flags),
88       helpers_(helpers.Pass()),
89       initial_uma_index_(0),
90       extra_children_(extra_children),
91       extra_fds_(extra_fds) {}
92 
~Zygote()93 Zygote::~Zygote() {
94 }
95 
ProcessRequests()96 bool Zygote::ProcessRequests() {
97   // A SOCK_SEQPACKET socket is installed in fd 3. We get commands from the
98   // browser on it.
99   // A SOCK_DGRAM is installed in fd 5. This is the sandbox IPC channel.
100   // See http://code.google.com/p/chromium/wiki/LinuxSandboxIPC
101 
102   // We need to accept SIGCHLD, even though our handler is a no-op because
103   // otherwise we cannot wait on children. (According to POSIX 2001.)
104   struct sigaction action;
105   memset(&action, 0, sizeof(action));
106   action.sa_handler = &SIGCHLDHandler;
107   CHECK(sigaction(SIGCHLD, &action, NULL) == 0);
108 
109   if (UsingSUIDSandbox()) {
110     // Let the ZygoteHost know we are ready to go.
111     // The receiving code is in content/browser/zygote_host_linux.cc.
112     bool r = UnixDomainSocket::SendMsg(kZygoteSocketPairFd,
113                                        kZygoteHelloMessage,
114                                        sizeof(kZygoteHelloMessage),
115                                        std::vector<int>());
116 #if defined(OS_CHROMEOS)
117     LOG_IF(WARNING, !r) << "Sending zygote magic failed";
118     // Exit normally on chromeos because session manager may send SIGTERM
119     // right after the process starts and it may fail to send zygote magic
120     // number to browser process.
121     if (!r)
122       _exit(RESULT_CODE_NORMAL_EXIT);
123 #else
124     CHECK(r) << "Sending zygote magic failed";
125 #endif
126   }
127 
128   for (;;) {
129     // This function call can return multiple times, once per fork().
130     if (HandleRequestFromBrowser(kZygoteSocketPairFd))
131       return true;
132   }
133 }
134 
GetProcessInfo(base::ProcessHandle pid,ZygoteProcessInfo * process_info)135 bool Zygote::GetProcessInfo(base::ProcessHandle pid,
136                             ZygoteProcessInfo* process_info) {
137   DCHECK(process_info);
138   const ZygoteProcessMap::const_iterator it = process_info_map_.find(pid);
139   if (it == process_info_map_.end()) {
140     return false;
141   }
142   *process_info = it->second;
143   return true;
144 }
145 
UsingSUIDSandbox() const146 bool Zygote::UsingSUIDSandbox() const {
147   return sandbox_flags_ & kSandboxLinuxSUID;
148 }
149 
HandleRequestFromBrowser(int fd)150 bool Zygote::HandleRequestFromBrowser(int fd) {
151   ScopedVector<base::ScopedFD> fds;
152   char buf[kZygoteMaxMessageLength];
153   const ssize_t len = UnixDomainSocket::RecvMsg(fd, buf, sizeof(buf), &fds);
154 
155   if (len == 0 || (len == -1 && errno == ECONNRESET)) {
156     // EOF from the browser. We should die.
157     // TODO(earthdok): call __sanititizer_cov_dump() here to obtain code
158     // coverage  for the Zygote. Currently it's not possible because of
159     // confusion over who is responsible for closing the file descriptor.
160     for (std::vector<int>::iterator it = extra_fds_.begin();
161          it < extra_fds_.end(); ++it) {
162       PCHECK(0 == IGNORE_EINTR(close(*it)));
163     }
164 #if !defined(ADDRESS_SANITIZER)
165     // TODO(earthdok): add watchdog thread before using this in non-ASAN builds.
166     CHECK(extra_children_.empty());
167 #endif
168     for (std::vector<base::ProcessHandle>::iterator it =
169              extra_children_.begin();
170          it < extra_children_.end(); ++it) {
171       PCHECK(*it == HANDLE_EINTR(waitpid(*it, NULL, 0)));
172     }
173     _exit(0);
174     return false;
175   }
176 
177   if (len == -1) {
178     PLOG(ERROR) << "Error reading message from browser";
179     return false;
180   }
181 
182   Pickle pickle(buf, len);
183   PickleIterator iter(pickle);
184 
185   int kind;
186   if (pickle.ReadInt(&iter, &kind)) {
187     switch (kind) {
188       case kZygoteCommandFork:
189         // This function call can return multiple times, once per fork().
190         return HandleForkRequest(fd, pickle, iter, fds.Pass());
191 
192       case kZygoteCommandReap:
193         if (!fds.empty())
194           break;
195         HandleReapRequest(fd, pickle, iter);
196         return false;
197       case kZygoteCommandGetTerminationStatus:
198         if (!fds.empty())
199           break;
200         HandleGetTerminationStatus(fd, pickle, iter);
201         return false;
202       case kZygoteCommandGetSandboxStatus:
203         HandleGetSandboxStatus(fd, pickle, iter);
204         return false;
205       case kZygoteCommandForkRealPID:
206         // This shouldn't happen in practice, but some failure paths in
207         // HandleForkRequest (e.g., if ReadArgsAndFork fails during depickling)
208         // could leave this command pending on the socket.
209         LOG(ERROR) << "Unexpected real PID message from browser";
210         NOTREACHED();
211         return false;
212       default:
213         NOTREACHED();
214         break;
215     }
216   }
217 
218   LOG(WARNING) << "Error parsing message from browser";
219   return false;
220 }
221 
222 // TODO(jln): remove callers to this broken API. See crbug.com/274855.
HandleReapRequest(int fd,const Pickle & pickle,PickleIterator iter)223 void Zygote::HandleReapRequest(int fd,
224                                const Pickle& pickle,
225                                PickleIterator iter) {
226   base::ProcessId child;
227 
228   if (!pickle.ReadInt(&iter, &child)) {
229     LOG(WARNING) << "Error parsing reap request from browser";
230     return;
231   }
232 
233   ZygoteProcessInfo child_info;
234   if (!GetProcessInfo(child, &child_info)) {
235     LOG(ERROR) << "Child not found!";
236     NOTREACHED();
237     return;
238   }
239 
240   if (!child_info.started_from_helper) {
241     // Do not call base::EnsureProcessTerminated() under ThreadSanitizer, as it
242     // spawns a separate thread which may live until the call to fork() in the
243     // zygote. As a result, ThreadSanitizer will report an error and almost
244     // disable race detection in the child process.
245     // Not calling EnsureProcessTerminated() may result in zombie processes
246     // sticking around. This will only happen during testing, so we can live
247     // with this for now.
248 #if !defined(THREAD_SANITIZER)
249     // TODO(jln): this old code is completely broken. See crbug.com/274855.
250     base::EnsureProcessTerminated(child_info.internal_pid);
251 #else
252     LOG(WARNING) << "Zygote process omitting a call to "
253         << "base::EnsureProcessTerminated() for child pid " << child
254         << " under ThreadSanitizer. See http://crbug.com/274855.";
255 #endif
256   } else {
257     // For processes from the helper, send a GetTerminationStatus request
258     // with known_dead set to true.
259     // This is not perfect, as the process may be killed instantly, but is
260     // better than ignoring the request.
261     base::TerminationStatus status;
262     int exit_code;
263     bool got_termination_status =
264         GetTerminationStatus(child, true /* known_dead */, &status, &exit_code);
265     DCHECK(got_termination_status);
266   }
267   process_info_map_.erase(child);
268 }
269 
GetTerminationStatus(base::ProcessHandle real_pid,bool known_dead,base::TerminationStatus * status,int * exit_code)270 bool Zygote::GetTerminationStatus(base::ProcessHandle real_pid,
271                                   bool known_dead,
272                                   base::TerminationStatus* status,
273                                   int* exit_code) {
274 
275   ZygoteProcessInfo child_info;
276   if (!GetProcessInfo(real_pid, &child_info)) {
277     LOG(ERROR) << "Zygote::GetTerminationStatus for unknown PID "
278                << real_pid;
279     NOTREACHED();
280     return false;
281   }
282   // We know about |real_pid|.
283   const base::ProcessHandle child = child_info.internal_pid;
284   if (child_info.started_from_helper) {
285     if (!child_info.started_from_helper->GetTerminationStatus(
286             child, known_dead, status, exit_code)) {
287       return false;
288     }
289   } else {
290     // Handle the request directly.
291     if (known_dead) {
292       *status = base::GetKnownDeadTerminationStatus(child, exit_code);
293     } else {
294       // We don't know if the process is dying, so get its status but don't
295       // wait.
296       *status = base::GetTerminationStatus(child, exit_code);
297     }
298   }
299   // Successfully got a status for |real_pid|.
300   if (*status != base::TERMINATION_STATUS_STILL_RUNNING) {
301     // Time to forget about this process.
302     process_info_map_.erase(real_pid);
303   }
304   return true;
305 }
306 
HandleGetTerminationStatus(int fd,const Pickle & pickle,PickleIterator iter)307 void Zygote::HandleGetTerminationStatus(int fd,
308                                         const Pickle& pickle,
309                                         PickleIterator iter) {
310   bool known_dead;
311   base::ProcessHandle child_requested;
312 
313   if (!pickle.ReadBool(&iter, &known_dead) ||
314       !pickle.ReadInt(&iter, &child_requested)) {
315     LOG(WARNING) << "Error parsing GetTerminationStatus request "
316                  << "from browser";
317     return;
318   }
319 
320   base::TerminationStatus status;
321   int exit_code;
322 
323   bool got_termination_status =
324       GetTerminationStatus(child_requested, known_dead, &status, &exit_code);
325   if (!got_termination_status) {
326     // Assume that if we can't find the child in the sandbox, then
327     // it terminated normally.
328     NOTREACHED();
329     status = base::TERMINATION_STATUS_NORMAL_TERMINATION;
330     exit_code = RESULT_CODE_NORMAL_EXIT;
331   }
332 
333   Pickle write_pickle;
334   write_pickle.WriteInt(static_cast<int>(status));
335   write_pickle.WriteInt(exit_code);
336   ssize_t written =
337       HANDLE_EINTR(write(fd, write_pickle.data(), write_pickle.size()));
338   if (written != static_cast<ssize_t>(write_pickle.size()))
339     PLOG(ERROR) << "write";
340 }
341 
ForkWithRealPid(const std::string & process_type,const base::GlobalDescriptors::Mapping & fd_mapping,const std::string & channel_id,base::ScopedFD pid_oracle,std::string * uma_name,int * uma_sample,int * uma_boundary_value)342 int Zygote::ForkWithRealPid(const std::string& process_type,
343                             const base::GlobalDescriptors::Mapping& fd_mapping,
344                             const std::string& channel_id,
345                             base::ScopedFD pid_oracle,
346                             std::string* uma_name,
347                             int* uma_sample,
348                             int* uma_boundary_value) {
349   ZygoteForkDelegate* helper = NULL;
350   for (ScopedVector<ZygoteForkDelegate>::iterator i = helpers_.begin();
351        i != helpers_.end();
352        ++i) {
353     if ((*i)->CanHelp(process_type, uma_name, uma_sample, uma_boundary_value)) {
354       helper = *i;
355       break;
356     }
357   }
358 
359   base::ScopedFD read_pipe, write_pipe;
360   base::ProcessId pid = 0;
361   if (helper) {
362     int ipc_channel_fd = LookUpFd(fd_mapping, kPrimaryIPCChannel);
363     if (ipc_channel_fd < 0) {
364       DLOG(ERROR) << "Failed to find kPrimaryIPCChannel in FD mapping";
365       return -1;
366     }
367     std::vector<int> fds;
368     fds.push_back(ipc_channel_fd);  // kBrowserFDIndex
369     fds.push_back(pid_oracle.get());  // kPIDOracleFDIndex
370     pid = helper->Fork(process_type, fds, channel_id);
371 
372     // Helpers should never return in the child process.
373     CHECK_NE(pid, 0);
374   } else {
375     CreatePipe(&read_pipe, &write_pipe);
376     pid = fork();
377   }
378 
379   if (pid == 0) {
380     // In the child process.
381     write_pipe.reset();
382 
383     // Ping the PID oracle socket so the browser can find our PID.
384     CHECK(SendZygoteChildPing(pid_oracle.get()));
385 
386     // Now read back our real PID from the zygote.
387     base::ProcessId real_pid;
388     if (!base::ReadFromFD(read_pipe.get(),
389                           reinterpret_cast<char*>(&real_pid),
390                           sizeof(real_pid))) {
391       LOG(FATAL) << "Failed to synchronise with parent zygote process";
392     }
393     if (real_pid <= 0) {
394       LOG(FATAL) << "Invalid pid from parent zygote";
395     }
396 #if defined(OS_LINUX)
397     // Sandboxed processes need to send the global, non-namespaced PID when
398     // setting up an IPC channel to their parent.
399     IPC::Channel::SetGlobalPid(real_pid);
400     // Force the real PID so chrome event data have a PID that corresponds
401     // to system trace event data.
402     base::debug::TraceLog::GetInstance()->SetProcessID(
403         static_cast<int>(real_pid));
404 #endif
405     return 0;
406   }
407 
408   // In the parent process.
409   read_pipe.reset();
410   pid_oracle.reset();
411 
412   // Always receive a real PID from the zygote host, though it might
413   // be invalid (see below).
414   base::ProcessId real_pid;
415   {
416     ScopedVector<base::ScopedFD> recv_fds;
417     char buf[kZygoteMaxMessageLength];
418     const ssize_t len = UnixDomainSocket::RecvMsg(
419         kZygoteSocketPairFd, buf, sizeof(buf), &recv_fds);
420     CHECK_GT(len, 0);
421     CHECK(recv_fds.empty());
422 
423     Pickle pickle(buf, len);
424     PickleIterator iter(pickle);
425 
426     int kind;
427     CHECK(pickle.ReadInt(&iter, &kind));
428     CHECK(kind == kZygoteCommandForkRealPID);
429     CHECK(pickle.ReadInt(&iter, &real_pid));
430   }
431 
432   // Fork failed.
433   if (pid < 0) {
434     return -1;
435   }
436 
437   // If we successfully forked a child, but it crashed without sending
438   // a message to the browser, the browser won't have found its PID.
439   if (real_pid < 0) {
440     KillAndReap(pid, helper);
441     return -1;
442   }
443 
444   // If we're not using a helper, send the PID back to the child process.
445   if (!helper) {
446     ssize_t written =
447         HANDLE_EINTR(write(write_pipe.get(), &real_pid, sizeof(real_pid)));
448     if (written != sizeof(real_pid)) {
449       KillAndReap(pid, helper);
450       return -1;
451     }
452   }
453 
454   // Now set-up this process to be tracked by the Zygote.
455   if (process_info_map_.find(real_pid) != process_info_map_.end()) {
456     LOG(ERROR) << "Already tracking PID " << real_pid;
457     NOTREACHED();
458   }
459   process_info_map_[real_pid].internal_pid = pid;
460   process_info_map_[real_pid].started_from_helper = helper;
461 
462   return real_pid;
463 }
464 
ReadArgsAndFork(const Pickle & pickle,PickleIterator iter,ScopedVector<base::ScopedFD> fds,std::string * uma_name,int * uma_sample,int * uma_boundary_value)465 base::ProcessId Zygote::ReadArgsAndFork(const Pickle& pickle,
466                                         PickleIterator iter,
467                                         ScopedVector<base::ScopedFD> fds,
468                                         std::string* uma_name,
469                                         int* uma_sample,
470                                         int* uma_boundary_value) {
471   std::vector<std::string> args;
472   int argc = 0;
473   int numfds = 0;
474   base::GlobalDescriptors::Mapping mapping;
475   std::string process_type;
476   std::string channel_id;
477   const std::string channel_id_prefix = std::string("--")
478       + switches::kProcessChannelID + std::string("=");
479 
480   if (!pickle.ReadString(&iter, &process_type))
481     return -1;
482   if (!pickle.ReadInt(&iter, &argc))
483     return -1;
484 
485   for (int i = 0; i < argc; ++i) {
486     std::string arg;
487     if (!pickle.ReadString(&iter, &arg))
488       return -1;
489     args.push_back(arg);
490     if (arg.compare(0, channel_id_prefix.length(), channel_id_prefix) == 0)
491       channel_id = arg.substr(channel_id_prefix.length());
492   }
493 
494   if (!pickle.ReadInt(&iter, &numfds))
495     return -1;
496   if (numfds != static_cast<int>(fds.size()))
497     return -1;
498 
499   // First FD is the PID oracle socket.
500   if (fds.size() < 1)
501     return -1;
502   base::ScopedFD pid_oracle(fds[0]->Pass());
503 
504   // Remaining FDs are for the global descriptor mapping.
505   for (int i = 1; i < numfds; ++i) {
506     base::GlobalDescriptors::Key key;
507     if (!pickle.ReadUInt32(&iter, &key))
508       return -1;
509     mapping.push_back(std::make_pair(key, fds[i]->get()));
510   }
511 
512   mapping.push_back(std::make_pair(
513       static_cast<uint32_t>(kSandboxIPCChannel), GetSandboxFD()));
514 
515   // Returns twice, once per process.
516   base::ProcessId child_pid = ForkWithRealPid(process_type,
517                                               mapping,
518                                               channel_id,
519                                               pid_oracle.Pass(),
520                                               uma_name,
521                                               uma_sample,
522                                               uma_boundary_value);
523   if (!child_pid) {
524     // This is the child process.
525 
526     // Our socket from the browser.
527     PCHECK(0 == IGNORE_EINTR(close(kZygoteSocketPairFd)));
528 
529     // Pass ownership of file descriptors from fds to GlobalDescriptors.
530     for (ScopedVector<base::ScopedFD>::iterator i = fds.begin(); i != fds.end();
531          ++i)
532       ignore_result((*i)->release());
533     base::GlobalDescriptors::GetInstance()->Reset(mapping);
534 
535     // Reset the process-wide command line to our new command line.
536     CommandLine::Reset();
537     CommandLine::Init(0, NULL);
538     CommandLine::ForCurrentProcess()->InitFromArgv(args);
539 
540     // Update the process title. The argv was already cached by the call to
541     // SetProcessTitleFromCommandLine in ChromeMain, so we can pass NULL here
542     // (we don't have the original argv at this point).
543     SetProcessTitleFromCommandLine(NULL);
544   } else if (child_pid < 0) {
545     LOG(ERROR) << "Zygote could not fork: process_type " << process_type
546         << " numfds " << numfds << " child_pid " << child_pid;
547   }
548   return child_pid;
549 }
550 
HandleForkRequest(int fd,const Pickle & pickle,PickleIterator iter,ScopedVector<base::ScopedFD> fds)551 bool Zygote::HandleForkRequest(int fd,
552                                const Pickle& pickle,
553                                PickleIterator iter,
554                                ScopedVector<base::ScopedFD> fds) {
555   std::string uma_name;
556   int uma_sample;
557   int uma_boundary_value;
558   base::ProcessId child_pid = ReadArgsAndFork(
559       pickle, iter, fds.Pass(), &uma_name, &uma_sample, &uma_boundary_value);
560   if (child_pid == 0)
561     return true;
562   // If there's no UMA report for this particular fork, then check if any
563   // helpers have an initial UMA report for us to send instead.
564   while (uma_name.empty() && initial_uma_index_ < helpers_.size()) {
565     helpers_[initial_uma_index_++]->InitialUMA(
566         &uma_name, &uma_sample, &uma_boundary_value);
567   }
568   // Must always send reply, as ZygoteHost blocks while waiting for it.
569   Pickle reply_pickle;
570   reply_pickle.WriteInt(child_pid);
571   reply_pickle.WriteString(uma_name);
572   if (!uma_name.empty()) {
573     reply_pickle.WriteInt(uma_sample);
574     reply_pickle.WriteInt(uma_boundary_value);
575   }
576   if (HANDLE_EINTR(write(fd, reply_pickle.data(), reply_pickle.size())) !=
577       static_cast<ssize_t> (reply_pickle.size()))
578     PLOG(ERROR) << "write";
579   return false;
580 }
581 
HandleGetSandboxStatus(int fd,const Pickle & pickle,PickleIterator iter)582 bool Zygote::HandleGetSandboxStatus(int fd,
583                                     const Pickle& pickle,
584                                     PickleIterator iter) {
585   if (HANDLE_EINTR(write(fd, &sandbox_flags_, sizeof(sandbox_flags_))) !=
586                    sizeof(sandbox_flags_)) {
587     PLOG(ERROR) << "write";
588   }
589 
590   return false;
591 }
592 
593 }  // namespace content
594