LCOV - code coverage report
Current view: top level - ipc/chromium/src/chrome/common - ipc_channel_posix.cc (source / functions) Hit Total Coverage
Test: output.info Lines: 306 398 76.9 %
Date: 2017-07-14 16:53:18 Functions: 34 40 85.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
       2             : /* vim: set ts=8 sts=2 et sw=2 tw=80: */
       3             : // Copyright (c) 2008 The Chromium Authors. All rights reserved.
       4             : // Use of this source code is governed by a BSD-style license that can be
       5             : // found in the LICENSE file.
       6             : 
       7             : #include "chrome/common/ipc_channel_posix.h"
       8             : 
       9             : #include <errno.h>
      10             : #include <fcntl.h>
      11             : #include <limits.h>
      12             : #if defined(OS_MACOSX)
      13             : #include <sched.h>
      14             : #endif
      15             : #include <stddef.h>
      16             : #include <unistd.h>
      17             : #include <sys/types.h>
      18             : #include <sys/socket.h>
      19             : #include <sys/stat.h>
      20             : #include <sys/un.h>
      21             : #include <sys/uio.h>
      22             : 
      23             : #include <string>
      24             : #include <map>
      25             : 
      26             : #include "base/command_line.h"
      27             : #include "base/eintr_wrapper.h"
      28             : #include "base/lock.h"
      29             : #include "base/logging.h"
      30             : #include "base/process_util.h"
      31             : #include "base/string_util.h"
      32             : #include "base/singleton.h"
      33             : #include "chrome/common/chrome_switches.h"
      34             : #include "chrome/common/file_descriptor_set_posix.h"
      35             : #include "chrome/common/ipc_message_utils.h"
      36             : #include "mozilla/ipc/ProtocolUtils.h"
      37             : #include "mozilla/UniquePtr.h"
      38             : 
      39             : #ifdef FUZZING
      40             : #include "mozilla/ipc/Faulty.h"
      41             : #endif
      42             : 
      43             : // Use OS specific iovec array limit where it's possible.
      44             : #if defined(IOV_MAX)
      45             : static const size_t kMaxIOVecSize = IOV_MAX;
      46             : #elif defined(ANDROID)
      47             : static const size_t kMaxIOVecSize = 256;
      48             : #else
      49             : static const size_t kMaxIOVecSize = 16;
      50             : #endif
      51             : 
      52             : #ifdef MOZ_TASK_TRACER
      53             : #include "GeckoTaskTracerImpl.h"
      54             : using namespace mozilla::tasktracer;
      55             : #endif
      56             : 
      57             : namespace IPC {
      58             : 
      59             : // IPC channels on Windows use named pipes (CreateNamedPipe()) with
      60             : // channel ids as the pipe names.  Channels on POSIX use anonymous
      61             : // Unix domain sockets created via socketpair() as pipes.  These don't
      62             : // quite line up.
      63             : //
      64             : // When creating a child subprocess, the parent side of the fork
      65             : // arranges it such that the initial control channel ends up on the
      66             : // magic file descriptor gClientChannelFd in the child.  Future
      67             : // connections (file descriptors) can then be passed via that
      68             : // connection via sendmsg().
      69             : //
      70             : // On Android, child processes are created as a service instead of
      71             : // forking the parent process. The Android Binder service is used to
      72             : // transport the IPC channel file descriptor to the child process.
      73             : // So rather than re-mapping the file descriptor to a known value,
      74             : // the received channel file descriptor is set by calling
      75             : // SetClientChannelFd before gecko has been initialized and started
      76             : // in the child process.
      77             : 
      78             : //------------------------------------------------------------------------------
      79             : namespace {
      80             : 
      81             : // The PipeMap class works around this quirk related to unit tests:
      82             : //
      83             : // When running as a server, we install the client socket in a
      84             : // specific file descriptor number (@gClientChannelFd). However, we
      85             : // also have to support the case where we are running unittests in the
      86             : // same process.  (We do not support forking without execing.)
      87             : //
      88             : // Case 1: normal running
      89             : //   The IPC server object will install a mapping in PipeMap from the
      90             : //   name which it was given to the client pipe. When forking the client, the
      91             : //   GetClientFileDescriptorMapping will ensure that the socket is installed in
      92             : //   the magic slot (@gClientChannelFd). The client will search for the
      93             : //   mapping, but it won't find any since we are in a new process. Thus the
      94             : //   magic fd number is returned. Once the client connects, the server will
      95             : //   close its copy of the client socket and remove the mapping.
      96             : //
      97             : // Case 2: unittests - client and server in the same process
      98             : //   The IPC server will install a mapping as before. The client will search
      99             : //   for a mapping and find out. It duplicates the file descriptor and
     100             : //   connects. Once the client connects, the server will close the original
     101             : //   copy of the client socket and remove the mapping. Thus, when the client
     102             : //   object closes, it will close the only remaining copy of the client socket
     103             : //   in the fd table and the server will see EOF on its side.
     104             : //
     105             : // TODO(port): a client process cannot connect to multiple IPC channels with
     106             : // this scheme.
     107             : 
     108           3 : class PipeMap {
     109             :  public:
     110             :   // Lookup a given channel id. Return -1 if not found.
     111           2 :   int Lookup(const std::string& channel_id) {
     112           4 :     AutoLock locked(lock_);
     113             : 
     114           2 :     ChannelToFDMap::const_iterator i = map_.find(channel_id);
     115           2 :     if (i == map_.end())
     116           2 :       return -1;
     117           0 :     return i->second;
     118             :   }
     119             : 
     120             :   // Remove the mapping for the given channel id. No error is signaled if the
     121             :   // channel_id doesn't exist
     122          15 :   void Remove(const std::string& channel_id) {
     123          30 :     AutoLock locked(lock_);
     124             : 
     125          15 :     ChannelToFDMap::iterator i = map_.find(channel_id);
     126          15 :     if (i != map_.end())
     127          15 :       map_.erase(i);
     128          15 :   }
     129             : 
     130             :   // Insert a mapping from @channel_id to @fd. It's a fatal error to insert a
     131             :   // mapping if one already exists for the given channel_id
     132          15 :   void Insert(const std::string& channel_id, int fd) {
     133          30 :     AutoLock locked(lock_);
     134          15 :     DCHECK(fd != -1);
     135             : 
     136          15 :     ChannelToFDMap::const_iterator i = map_.find(channel_id);
     137          15 :     CHECK(i == map_.end()) << "Creating second IPC server for '"
     138             :                            << channel_id
     139           0 :                            << "' while first still exists";
     140          15 :     map_[channel_id] = fd;
     141          15 :   }
     142             : 
     143             :  private:
     144             :   Lock lock_;
     145             :   typedef std::map<std::string, int> ChannelToFDMap;
     146             :   ChannelToFDMap map_;
     147             : };
     148             : 
     149             : // This is the file descriptor number that a client process expects to find its
     150             : // IPC socket.
     151             : static int gClientChannelFd =
     152             : #if defined(MOZ_WIDGET_ANDROID)
     153             : // On android the fd is set at the time of child creation.
     154             : -1
     155             : #else
     156             : 3
     157             : #endif // defined(MOZ_WIDGET_ANDROID)
     158             : ;
     159             : 
     160             : // Used to map a channel name to the equivalent FD # in the client process.
     161           2 : int ChannelNameToClientFD(const std::string& channel_id) {
     162             :   // See the large block comment above PipeMap for the reasoning here.
     163           2 :   const int fd = Singleton<PipeMap>()->Lookup(channel_id);
     164           2 :   if (fd != -1)
     165           0 :     return dup(fd);
     166             : 
     167             :   // If we don't find an entry, we assume that the correct value has been
     168             :   // inserted in the magic slot.
     169           2 :   return gClientChannelFd;
     170             : }
     171             : 
     172             : //------------------------------------------------------------------------------
     173             : const size_t kMaxPipeNameLength = sizeof(((sockaddr_un*)0)->sun_path);
     174             : 
     175          30 : bool SetCloseOnExec(int fd) {
     176          30 :   int flags = fcntl(fd, F_GETFD);
     177          30 :   if (flags == -1)
     178           0 :     return false;
     179             : 
     180          30 :   flags |= FD_CLOEXEC;
     181          30 :   if (fcntl(fd, F_SETFD, flags) == -1)
     182           0 :     return false;
     183             : 
     184          30 :   return true;
     185             : }
     186             : 
     187             : }  // namespace
     188             : //------------------------------------------------------------------------------
     189             : 
     190             : #if defined(MOZ_WIDGET_ANDROID)
     191             : void Channel::SetClientChannelFd(int fd) {
     192             :   gClientChannelFd = fd;
     193             : }
     194             : #endif // defined(MOZ_WIDGET_ANDROID)
     195             : 
     196          17 : Channel::ChannelImpl::ChannelImpl(const std::wstring& channel_id, Mode mode,
     197          17 :                                   Listener* listener)
     198          17 :     : factory_(this) {
     199          17 :   Init(mode, listener);
     200             : 
     201          17 :   if (!CreatePipe(channel_id, mode)) {
     202             :     // The pipe may have been closed already.
     203           0 :     CHROMIUM_LOG(WARNING) << "Unable to create pipe named \"" << channel_id <<
     204             :                              "\" in " << (mode == MODE_SERVER ? "server" : "client") <<
     205           0 :                              " mode error(" << strerror(errno) << ").";
     206           0 :     closed_ = true;
     207           0 :     return;
     208             :   }
     209             : 
     210          17 :   EnqueueHelloMessage();
     211             : }
     212             : 
     213          24 : Channel::ChannelImpl::ChannelImpl(int fd, Mode mode, Listener* listener)
     214          24 :     : factory_(this) {
     215          24 :   Init(mode, listener);
     216          24 :   pipe_ = fd;
     217          24 :   waiting_connect_ = (MODE_SERVER == mode);
     218             : 
     219          24 :   EnqueueHelloMessage();
     220          24 : }
     221             : 
     222          41 : void Channel::ChannelImpl::Init(Mode mode, Listener* listener) {
     223             :   DCHECK(kControlBufferSlopBytes >= CMSG_SPACE(0));
     224             : 
     225          41 :   mode_ = mode;
     226          41 :   is_blocked_on_write_ = false;
     227          41 :   partial_write_iter_.reset();
     228          41 :   input_buf_offset_ = 0;
     229          41 :   server_listen_pipe_ = -1;
     230          41 :   pipe_ = -1;
     231          41 :   client_pipe_ = -1;
     232          41 :   listener_ = listener;
     233          41 :   waiting_connect_ = true;
     234          41 :   processing_incoming_ = false;
     235          41 :   closed_ = false;
     236             : #if defined(OS_MACOSX)
     237             :   last_pending_fd_id_ = 0;
     238             : #endif
     239          41 :   output_queue_length_ = 0;
     240          41 : }
     241             : 
     242          17 : bool Channel::ChannelImpl::CreatePipe(const std::wstring& channel_id,
     243             :                                       Mode mode) {
     244          17 :   DCHECK(server_listen_pipe_ == -1 && pipe_ == -1);
     245             : 
     246             :   // socketpair()
     247          17 :   pipe_name_ = WideToASCII(channel_id);
     248          17 :   if (mode == MODE_SERVER) {
     249             :     int pipe_fds[2];
     250          15 :     if (socketpair(AF_UNIX, SOCK_STREAM, 0, pipe_fds) != 0) {
     251           0 :       mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeSocketPairErrno", errno);
     252           0 :       return false;
     253             :     }
     254             :     // Set both ends to be non-blocking.
     255          30 :     if (fcntl(pipe_fds[0], F_SETFL, O_NONBLOCK) == -1 ||
     256          15 :         fcntl(pipe_fds[1], F_SETFL, O_NONBLOCK) == -1) {
     257           0 :       mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeFcntlErrno", errno);
     258           0 :       HANDLE_EINTR(close(pipe_fds[0]));
     259           0 :       HANDLE_EINTR(close(pipe_fds[1]));
     260           0 :       return false;
     261             :     }
     262             : 
     263          30 :     if (!SetCloseOnExec(pipe_fds[0]) ||
     264          15 :         !SetCloseOnExec(pipe_fds[1])) {
     265           0 :       mozilla::ipc::AnnotateCrashReportWithErrno("IpcCreatePipeCloExecErrno", errno);
     266           0 :       HANDLE_EINTR(close(pipe_fds[0]));
     267           0 :       HANDLE_EINTR(close(pipe_fds[1]));
     268           0 :       return false;
     269             :     }
     270             : 
     271          15 :     pipe_ = pipe_fds[0];
     272          15 :     client_pipe_ = pipe_fds[1];
     273             : 
     274          15 :     if (pipe_name_.length()) {
     275          15 :       Singleton<PipeMap>()->Insert(pipe_name_, client_pipe_);
     276             :     }
     277             :   } else {
     278           2 :     pipe_ = ChannelNameToClientFD(pipe_name_);
     279           2 :     DCHECK(pipe_ > 0);
     280           2 :     waiting_connect_ = false;
     281             :   }
     282             : 
     283          17 :   return true;
     284             : }
     285             : 
     286             : /**
     287             :  * Reset the file descriptor for communication with the peer.
     288             :  */
     289           0 : void Channel::ChannelImpl::ResetFileDescriptor(int fd) {
     290           0 :   NS_ASSERTION(fd > 0 && fd == pipe_, "Invalid file descriptor");
     291             : 
     292           0 :   EnqueueHelloMessage();
     293           0 : }
     294             : 
     295          41 : bool Channel::ChannelImpl::EnqueueHelloMessage() {
     296             :   mozilla::UniquePtr<Message> msg(new Message(MSG_ROUTING_NONE,
     297          82 :                                               HELLO_MESSAGE_TYPE));
     298          41 :   if (!msg->WriteInt(base::GetCurrentProcId())) {
     299           0 :     Close();
     300           0 :     return false;
     301             :   }
     302             : 
     303          41 :   OutputQueuePush(msg.release());
     304          41 :   return true;
     305             : }
     306             : 
     307          28 : bool Channel::ChannelImpl::Connect() {
     308          28 :   if (pipe_ == -1) {
     309           0 :     return false;
     310             :   }
     311             : 
     312          28 :   MessageLoopForIO::current()->WatchFileDescriptor(
     313             :       pipe_,
     314             :       true,
     315             :       MessageLoopForIO::WATCH_READ,
     316             :       &read_watcher_,
     317          28 :       this);
     318          28 :   waiting_connect_ = false;
     319             : 
     320          28 :   if (!waiting_connect_)
     321          28 :     return ProcessOutgoingMessages();
     322           0 :   return true;
     323             : }
     324             : 
     325         252 : bool Channel::ChannelImpl::ProcessIncomingMessages() {
     326         252 :   struct msghdr msg = {0};
     327             :   struct iovec iov;
     328             : 
     329         252 :   msg.msg_iov = &iov;
     330         252 :   msg.msg_iovlen = 1;
     331         252 :   msg.msg_control = input_cmsg_buf_;
     332             : 
     333             :   for (;;) {
     334         961 :     msg.msg_controllen = sizeof(input_cmsg_buf_);
     335             : 
     336         961 :     if (pipe_ == -1)
     337         252 :       return false;
     338             : 
     339             :     // In some cases the beginning of a message will be stored in input_buf_. We
     340             :     // don't want to overwrite that, so we store the new data after it.
     341         961 :     iov.iov_base = input_buf_ + input_buf_offset_;
     342         961 :     iov.iov_len = Channel::kReadBufferSize - input_buf_offset_;
     343             : 
     344             :     // Read from pipe.
     345             :     // recvmsg() returns 0 if the connection has closed or EAGAIN if no data
     346             :     // is waiting on the pipe.
     347         961 :     ssize_t bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT));
     348             : 
     349         961 :     if (bytes_read < 0) {
     350         252 :       if (errno == EAGAIN) {
     351         252 :         return true;
     352             :       } else {
     353           0 :         CHROMIUM_LOG(ERROR) << "pipe error (" << pipe_ << "): " << strerror(errno);
     354           0 :         return false;
     355             :       }
     356         709 :     } else if (bytes_read == 0) {
     357             :       // The pipe has closed...
     358           0 :       Close();
     359           0 :       return false;
     360             :     }
     361         709 :     DCHECK(bytes_read);
     362             : 
     363         709 :     if (client_pipe_ != -1) {
     364           0 :       Singleton<PipeMap>()->Remove(pipe_name_);
     365           0 :       HANDLE_EINTR(close(client_pipe_));
     366           0 :       client_pipe_ = -1;
     367             :     }
     368             : 
     369             :     // a pointer to an array of |num_wire_fds| file descriptors from the read
     370         709 :     const int* wire_fds = NULL;
     371         709 :     unsigned num_wire_fds = 0;
     372             : 
     373             :     // walk the list of control messages and, if we find an array of file
     374             :     // descriptors, save a pointer to the array
     375             : 
     376             :     // This next if statement is to work around an OSX issue where
     377             :     // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0.
     378             :     // Here's a test case:
     379             :     //
     380             :     // int main() {
     381             :     // struct msghdr msg;
     382             :     //   msg.msg_control = &msg;
     383             :     //   msg.msg_controllen = 0;
     384             :     //   if (CMSG_FIRSTHDR(&msg))
     385             :     //     printf("Bug found!\n");
     386             :     // }
     387         709 :     if (msg.msg_controllen > 0) {
     388             :       // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0
     389             :       // and will return a pointer into nowhere.
     390          18 :       for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg;
     391             :            cmsg = CMSG_NXTHDR(&msg, cmsg)) {
     392          36 :         if (cmsg->cmsg_level == SOL_SOCKET &&
     393          18 :             cmsg->cmsg_type == SCM_RIGHTS) {
     394          18 :           const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0);
     395          18 :           DCHECK(payload_len % sizeof(int) == 0);
     396          18 :           wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg));
     397          18 :           num_wire_fds = payload_len / 4;
     398             : 
     399          18 :           if (msg.msg_flags & MSG_CTRUNC) {
     400           0 :             CHROMIUM_LOG(ERROR) << "SCM_RIGHTS message was truncated"
     401           0 :                                 << " cmsg_len:" << cmsg->cmsg_len
     402           0 :                                 << " fd:" << pipe_;
     403           0 :             for (unsigned i = 0; i < num_wire_fds; ++i)
     404           0 :               HANDLE_EINTR(close(wire_fds[i]));
     405           0 :             return false;
     406             :           }
     407          18 :           break;
     408             :         }
     409             :       }
     410             :     }
     411             : 
     412             :     // Process messages from input buffer.
     413         709 :     const char *p = input_buf_;
     414         709 :     const char *end = input_buf_ + input_buf_offset_ + bytes_read;
     415             : 
     416             :     // A pointer to an array of |num_fds| file descriptors which includes any
     417             :     // fds that have spilled over from a previous read.
     418             :     const int* fds;
     419             :     unsigned num_fds;
     420         709 :     unsigned fds_i = 0;  // the index of the first unused descriptor
     421             : 
     422         709 :     if (input_overflow_fds_.empty()) {
     423         709 :       fds = wire_fds;
     424         709 :       num_fds = num_wire_fds;
     425             :     } else {
     426           0 :       const size_t prev_size = input_overflow_fds_.size();
     427           0 :       input_overflow_fds_.resize(prev_size + num_wire_fds);
     428           0 :       memcpy(&input_overflow_fds_[prev_size], wire_fds,
     429           0 :              num_wire_fds * sizeof(int));
     430           0 :       fds = &input_overflow_fds_[0];
     431           0 :       num_fds = input_overflow_fds_.size();
     432             :     }
     433             : 
     434             :     // The data for the message we're currently reading consists of any data
     435             :     // stored in incoming_message_ followed by data in input_buf_ (followed by
     436             :     // other messages).
     437             : 
     438        1485 :     while (p < end) {
     439             :       // Try to figure out how big the message is. Size is 0 if we haven't read
     440             :       // enough of the header to know the size.
     441         807 :       uint32_t message_length = 0;
     442         807 :       if (incoming_message_.isSome()) {
     443         419 :         message_length = incoming_message_.ref().size();
     444             :       } else {
     445         388 :         message_length = Message::MessageSize(p, end);
     446             :       }
     447             : 
     448         807 :       if (!message_length) {
     449             :         // We haven't seen the full message header.
     450           0 :         MOZ_ASSERT(incoming_message_.isNothing());
     451             : 
     452             :         // Move everything we have to the start of the buffer. We'll finish
     453             :         // reading this message when we get more data. For now we leave it in
     454             :         // input_buf_.
     455           0 :         memmove(input_buf_, p, end - p);
     456           0 :         input_buf_offset_ = end - p;
     457             : 
     458         419 :         break;
     459             :       }
     460             : 
     461         807 :       input_buf_offset_ = 0;
     462             : 
     463             :       bool partial;
     464         807 :       if (incoming_message_.isSome()) {
     465             :         // We already have some data for this message stored in
     466             :         // incoming_message_. We want to append the new data there.
     467         419 :         Message& m = incoming_message_.ref();
     468             : 
     469             :         // How much data from this message remains to be added to
     470             :         // incoming_message_?
     471         419 :         MOZ_ASSERT(message_length > m.CurrentSize());
     472         419 :         uint32_t remaining = message_length - m.CurrentSize();
     473             : 
     474             :         // How much data from this message is stored in input_buf_?
     475         419 :         uint32_t in_buf = std::min(remaining, uint32_t(end - p));
     476             : 
     477         419 :         m.InputBytes(p, in_buf);
     478         419 :         p += in_buf;
     479             : 
     480             :         // Are we done reading this message?
     481         419 :         partial = in_buf != remaining;
     482             :       } else {
     483             :         // How much data from this message is stored in input_buf_?
     484         388 :         uint32_t in_buf = std::min(message_length, uint32_t(end - p));
     485             : 
     486         388 :         incoming_message_.emplace(p, in_buf);
     487         388 :         p += in_buf;
     488             : 
     489             :         // Are we done reading this message?
     490         388 :         partial = in_buf != message_length;
     491             :       }
     492             : 
     493         807 :       if (partial) {
     494         419 :         break;
     495             :       }
     496             : 
     497         388 :       Message& m = incoming_message_.ref();
     498             : 
     499         388 :       if (m.header()->num_fds) {
     500             :         // the message has file descriptors
     501          18 :         const char* error = NULL;
     502          18 :         if (m.header()->num_fds > num_fds - fds_i) {
     503             :           // the message has been completely received, but we didn't get
     504             :           // enough file descriptors.
     505           0 :           error = "Message needs unreceived descriptors";
     506             :         }
     507             : 
     508          18 :         if (m.header()->num_fds >
     509             :             FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
     510             :           // There are too many descriptors in this message
     511           0 :           error = "Message requires an excessive number of descriptors";
     512             :         }
     513             : 
     514          18 :         if (error) {
     515           0 :           CHROMIUM_LOG(WARNING) << error
     516             :                                 << " channel:" << this
     517           0 :                                 << " message-type:" << m.type()
     518           0 :                                 << " header()->num_fds:" << m.header()->num_fds
     519             :                                 << " num_fds:" << num_fds
     520           0 :                                 << " fds_i:" << fds_i;
     521             :           // close the existing file descriptors so that we don't leak them
     522           0 :           for (unsigned i = fds_i; i < num_fds; ++i)
     523           0 :             HANDLE_EINTR(close(fds[i]));
     524           0 :           input_overflow_fds_.clear();
     525             :           // abort the connection
     526           0 :           return false;
     527             :         }
     528             : 
     529             : #if defined(OS_MACOSX)
     530             :         // Send a message to the other side, indicating that we are now
     531             :         // responsible for closing the descriptor.
     532             :         Message *fdAck = new Message(MSG_ROUTING_NONE,
     533             :                                      RECEIVED_FDS_MESSAGE_TYPE);
     534             :         DCHECK(m.fd_cookie() != 0);
     535             :         fdAck->set_fd_cookie(m.fd_cookie());
     536             :         OutputQueuePush(fdAck);
     537             : #endif
     538             : 
     539          36 :         m.file_descriptor_set()->SetDescriptors(
     540          54 :                                                 &fds[fds_i], m.header()->num_fds);
     541          18 :         fds_i += m.header()->num_fds;
     542             :       }
     543             : #ifdef IPC_MESSAGE_DEBUG_EXTRA
     544             :       DLOG(INFO) << "received message on channel @" << this <<
     545             :         " with type " << m.type();
     546             : #endif
     547             : 
     548         413 :       if (m.routing_id() == MSG_ROUTING_NONE &&
     549          25 :           m.type() == HELLO_MESSAGE_TYPE) {
     550             :         // The Hello message contains only the process id.
     551          23 :         listener_->OnChannelConnected(MessageIterator(m).NextInt());
     552             : #if defined(OS_MACOSX)
     553             :       } else if (m.routing_id() == MSG_ROUTING_NONE &&
     554             :                  m.type() == RECEIVED_FDS_MESSAGE_TYPE) {
     555             :         DCHECK(m.fd_cookie() != 0);
     556             :         CloseDescriptors(m.fd_cookie());
     557             : #endif
     558             :       } else {
     559         365 :         listener_->OnMessageReceived(mozilla::Move(m));
     560             :       }
     561             : 
     562         388 :       incoming_message_.reset();
     563             :     }
     564             : 
     565         709 :     input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]);
     566             : 
     567             :     // When the input data buffer is empty, the overflow fds should be too. If
     568             :     // this is not the case, we probably have a rogue renderer which is trying
     569             :     // to fill our descriptor table.
     570         709 :     if (incoming_message_.isNothing() && input_buf_offset_ == 0 && !input_overflow_fds_.empty()) {
     571             :       // We close these descriptors in Close()
     572           0 :       return false;
     573             :     }
     574         709 :   }
     575             : 
     576             :   return true;
     577             : }
     578             : 
     579         343 : bool Channel::ChannelImpl::ProcessOutgoingMessages() {
     580         343 :   DCHECK(!waiting_connect_);  // Why are we trying to send messages if there's
     581             :                               // no connection?
     582         343 :   is_blocked_on_write_ = false;
     583             : 
     584         343 :   if (output_queue_.empty())
     585           0 :     return true;
     586             : 
     587         343 :   if (pipe_ == -1)
     588           0 :     return false;
     589             : 
     590             :   // Write out all the messages we can till the write blocks or there are no
     591             :   // more outgoing messages.
     592        1127 :   while (!output_queue_.empty()) {
     593             : #ifdef FUZZING
     594             :     Singleton<mozilla::ipc::Faulty>::get()->MaybeCollectAndClosePipe(pipe_);
     595             : #endif
     596         398 :     Message* msg = output_queue_.front();
     597             : 
     598         398 :     struct msghdr msgh = {0};
     599             : 
     600             :     static const int tmp = CMSG_SPACE(sizeof(
     601             :         int[FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE]));
     602             :     char buf[tmp];
     603             : 
     604         398 :     if (partial_write_iter_.isNothing()) {
     605         392 :       Pickle::BufferList::IterImpl iter(msg->Buffers());
     606         392 :       partial_write_iter_.emplace(iter);
     607             :     }
     608             : 
     609         790 :     if (partial_write_iter_.value().Data() == msg->Buffers().Start() &&
     610         392 :         !msg->file_descriptor_set()->empty()) {
     611             :       // This is the first chunk of a message which has descriptors to send
     612             :       struct cmsghdr *cmsg;
     613          19 :       const unsigned num_fds = msg->file_descriptor_set()->size();
     614             : 
     615          19 :       if (num_fds > FileDescriptorSet::MAX_DESCRIPTORS_PER_MESSAGE) {
     616           0 :         CHROMIUM_LOG(FATAL) << "Too many file descriptors!";
     617             :         // This should not be reached.
     618           6 :         return false;
     619             :       }
     620             : 
     621          19 :       msgh.msg_control = buf;
     622          19 :       msgh.msg_controllen = CMSG_SPACE(sizeof(int) * num_fds);
     623          19 :       cmsg = CMSG_FIRSTHDR(&msgh);
     624          19 :       cmsg->cmsg_level = SOL_SOCKET;
     625          19 :       cmsg->cmsg_type = SCM_RIGHTS;
     626          19 :       cmsg->cmsg_len = CMSG_LEN(sizeof(int) * num_fds);
     627          19 :       msg->file_descriptor_set()->GetDescriptors(
     628          19 :           reinterpret_cast<int*>(CMSG_DATA(cmsg)));
     629          19 :       msgh.msg_controllen = cmsg->cmsg_len;
     630             : 
     631          19 :       msg->header()->num_fds = num_fds;
     632             : #if defined(OS_MACOSX)
     633             :       msg->set_fd_cookie(++last_pending_fd_id_);
     634             : #endif
     635             :     }
     636             : 
     637             :     struct iovec iov[kMaxIOVecSize];
     638         398 :     size_t iov_count = 0;
     639         398 :     size_t amt_to_write = 0;
     640             : 
     641             :     // How much of this message have we written so far?
     642         398 :     Pickle::BufferList::IterImpl iter = partial_write_iter_.value();
     643             : 
     644             :     // Store the unwritten part of the first segment to write into the iovec.
     645         398 :     iov[0].iov_base = const_cast<char*>(iter.Data());
     646         398 :     iov[0].iov_len = iter.RemainingInSegment();
     647         398 :     amt_to_write += iov[0].iov_len;
     648         398 :     iter.Advance(msg->Buffers(), iov[0].iov_len);
     649         398 :     iov_count++;
     650             : 
     651             :     // Store remaining segments to write into iovec.
     652        2596 :     while (!iter.Done()) {
     653        1099 :       char* data = iter.Data();
     654        1099 :       size_t size = iter.RemainingInSegment();
     655             : 
     656             :       // Don't add more than kMaxIOVecSize to the iovec so that we avoid
     657             :       // OS-dependent limits.
     658        1099 :       if (iov_count < kMaxIOVecSize) {
     659        1099 :         iov[iov_count].iov_base = data;
     660        1099 :         iov[iov_count].iov_len = size;
     661        1099 :         iov_count++;
     662             :       }
     663        1099 :       amt_to_write += size;
     664        1099 :       iter.Advance(msg->Buffers(), size);
     665             :     }
     666             : 
     667         398 :     msgh.msg_iov = iov;
     668         398 :     msgh.msg_iovlen = iov_count;
     669             : 
     670         398 :     ssize_t bytes_written = HANDLE_EINTR(sendmsg(pipe_, &msgh, MSG_DONTWAIT));
     671             : 
     672             : #if !defined(OS_MACOSX)
     673             :     // On OSX CommitAll gets called later, once we get the RECEIVED_FDS_MESSAGE_TYPE
     674             :     // message.
     675         398 :     if (bytes_written > 0)
     676         398 :       msg->file_descriptor_set()->CommitAll();
     677             : #endif
     678             : 
     679         398 :     if (bytes_written < 0) {
     680           0 :       switch (errno) {
     681             :       case EAGAIN:
     682             :         // Not an error; the sendmsg would have blocked, so return to the
     683             :         // event loop and try again later.
     684           0 :         break;
     685             : #if defined(OS_MACOSX)
     686             :         // (Note: this comment is copied from https://crrev.com/86c3d9ef4fdf6;
     687             :         // see also bug 1142693 comment #73.)
     688             :         //
     689             :         // On OS X if sendmsg() is trying to send fds between processes and
     690             :         // there isn't enough room in the output buffer to send the fd
     691             :         // structure over atomically then EMSGSIZE is returned.
     692             :         //
     693             :         // EMSGSIZE presents a problem since the system APIs can only call us
     694             :         // when there's room in the socket buffer and not when there is
     695             :         // "enough" room.
     696             :         //
     697             :         // The current behavior is to return to the event loop when EMSGSIZE
     698             :         // is received and hopefull service another FD.  This is however still
     699             :         // technically a busy wait since the event loop will call us right
     700             :         // back until the receiver has read enough data to allow passing the
     701             :         // FD over atomically.
     702             :       case EMSGSIZE:
     703             :         // Because this is likely to result in a busy-wait, we'll try to make
     704             :         // it easier for the receiver to make progress.
     705             :         sched_yield();
     706             :         break;
     707             : #endif
     708             :       default:
     709           0 :         CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno);
     710           0 :         return false;
     711             :       }
     712             :     }
     713             : 
     714         398 :     if (static_cast<size_t>(bytes_written) != amt_to_write) {
     715             :       // If write() fails with EAGAIN then bytes_written will be -1.
     716           6 :       if (bytes_written > 0) {
     717           6 :         partial_write_iter_.ref().AdvanceAcrossSegments(msg->Buffers(), bytes_written);
     718             :       }
     719             : 
     720             :       // Tell libevent to call us back once things are unblocked.
     721           6 :       is_blocked_on_write_ = true;
     722           6 :       MessageLoopForIO::current()->WatchFileDescriptor(
     723             :           pipe_,
     724             :           false,  // One shot
     725             :           MessageLoopForIO::WATCH_WRITE,
     726             :           &write_watcher_,
     727           6 :           this);
     728           6 :       return true;
     729             :     } else {
     730         392 :       partial_write_iter_.reset();
     731             : 
     732             : #if defined(OS_MACOSX)
     733             :       if (!msg->file_descriptor_set()->empty())
     734             :         pending_fds_.push_back(PendingDescriptors(msg->fd_cookie(),
     735             :                                                   msg->file_descriptor_set()));
     736             : #endif
     737             : 
     738             :       // Message sent OK!
     739             : #ifdef IPC_MESSAGE_DEBUG_EXTRA
     740             :       DLOG(INFO) << "sent message @" << msg << " on channel @" << this <<
     741             :                     " with type " << msg->type();
     742             : #endif
     743         392 :       OutputQueuePop();
     744         392 :       delete msg;
     745             :     }
     746             :   }
     747         337 :   return true;
     748             : }
     749             : 
     750         364 : bool Channel::ChannelImpl::Send(Message* message) {
     751             : #ifdef IPC_MESSAGE_DEBUG_EXTRA
     752             :   DLOG(INFO) << "sending message @" << message << " on channel @" << this
     753             :              << " with type " << message->type()
     754             :              << " (" << output_queue_.size() << " in queue)";
     755             : #endif
     756             : 
     757             : 
     758             :   // If the channel has been closed, ProcessOutgoingMessages() is never going
     759             :   // to pop anything off output_queue; output_queue will only get emptied when
     760             :   // the channel is destructed.  We might as well delete message now, instead
     761             :   // of waiting for the channel to be destructed.
     762         364 :   if (closed_) {
     763           0 :     if (mozilla::ipc::LoggingEnabled()) {
     764           0 :       fprintf(stderr, "Can't send message %s, because this channel is closed.\n",
     765           0 :               message->name());
     766             :     }
     767           0 :     delete message;
     768           0 :     return false;
     769             :   }
     770             : 
     771         364 :   OutputQueuePush(message);
     772         364 :   if (!waiting_connect_) {
     773         364 :     if (!is_blocked_on_write_) {
     774         309 :       if (!ProcessOutgoingMessages())
     775           0 :         return false;
     776             :     }
     777             :   }
     778             : 
     779         364 :   return true;
     780             : }
     781             : 
     782          15 : void Channel::ChannelImpl::GetClientFileDescriptorMapping(int *src_fd,
     783             :                                                           int *dest_fd) const {
     784          15 :   DCHECK(mode_ == MODE_SERVER);
     785          15 :   *src_fd = client_pipe_;
     786          15 :   *dest_fd = gClientChannelFd;
     787          15 : }
     788             : 
     789           2 : void Channel::ChannelImpl::CloseClientFileDescriptor() {
     790           2 :   if (client_pipe_ != -1) {
     791           2 :     Singleton<PipeMap>()->Remove(pipe_name_);
     792           2 :     HANDLE_EINTR(close(client_pipe_));
     793           2 :     client_pipe_ = -1;
     794             :   }
     795           2 : }
     796             : 
     797             : // Called by libevent when we can read from th pipe without blocking.
     798         252 : void Channel::ChannelImpl::OnFileCanReadWithoutBlocking(int fd) {
     799         252 :   if (!waiting_connect_ && fd == pipe_) {
     800         252 :     if (!ProcessIncomingMessages()) {
     801           0 :       Close();
     802           0 :       listener_->OnChannelError();
     803             :       // The OnChannelError() call may delete this, so we need to exit now.
     804           0 :       return;
     805             :     }
     806             :   }
     807             : }
     808             : 
     809             : #if defined(OS_MACOSX)
     810             : void Channel::ChannelImpl::CloseDescriptors(uint32_t pending_fd_id)
     811             : {
     812             :   DCHECK(pending_fd_id != 0);
     813             :   for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin();
     814             :        i != pending_fds_.end();
     815             :        i++) {
     816             :     if ((*i).id == pending_fd_id) {
     817             :       (*i).fds->CommitAll();
     818             :       pending_fds_.erase(i);
     819             :       return;
     820             :     }
     821             :   }
     822             :   DCHECK(false) << "pending_fd_id not in our list!";
     823             : }
     824             : #endif
     825             : 
     826         405 : void Channel::ChannelImpl::OutputQueuePush(Message* msg)
     827             : {
     828         405 :   output_queue_.push(msg);
     829         405 :   output_queue_length_++;
     830         405 : }
     831             : 
     832         405 : void Channel::ChannelImpl::OutputQueuePop()
     833             : {
     834         405 :   output_queue_.pop();
     835         405 :   output_queue_length_--;
     836         405 : }
     837             : 
     838             : // Called by libevent when we can write to the pipe without blocking.
     839           6 : void Channel::ChannelImpl::OnFileCanWriteWithoutBlocking(int fd) {
     840           6 :   if (!ProcessOutgoingMessages()) {
     841           0 :     Close();
     842           0 :     listener_->OnChannelError();
     843             :   }
     844           6 : }
     845             : 
     846          13 : void Channel::ChannelImpl::Close() {
     847             :   // Close can be called multiple times, so we need to make sure we're
     848             :   // idempotent.
     849             : 
     850             :   // Unregister libevent for the listening socket and close it.
     851          13 :   server_listen_connection_watcher_.StopWatchingFileDescriptor();
     852             : 
     853          13 :   if (server_listen_pipe_ != -1) {
     854           0 :     HANDLE_EINTR(close(server_listen_pipe_));
     855           0 :     server_listen_pipe_ = -1;
     856             :   }
     857             : 
     858             :   // Unregister libevent for the FIFO and close it.
     859          13 :   read_watcher_.StopWatchingFileDescriptor();
     860          13 :   write_watcher_.StopWatchingFileDescriptor();
     861          13 :   if (pipe_ != -1) {
     862          13 :     HANDLE_EINTR(close(pipe_));
     863          13 :     pipe_ = -1;
     864             :   }
     865          13 :   if (client_pipe_ != -1) {
     866          13 :     Singleton<PipeMap>()->Remove(pipe_name_);
     867          13 :     HANDLE_EINTR(close(client_pipe_));
     868          13 :     client_pipe_ = -1;
     869             :   }
     870             : 
     871          39 :   while (!output_queue_.empty()) {
     872          13 :     Message* m = output_queue_.front();
     873          13 :     OutputQueuePop();
     874          13 :     delete m;
     875             :   }
     876             : 
     877             :   // Close any outstanding, received file descriptors
     878          26 :   for (std::vector<int>::iterator
     879          26 :        i = input_overflow_fds_.begin(); i != input_overflow_fds_.end(); ++i) {
     880           0 :     HANDLE_EINTR(close(*i));
     881             :   }
     882          13 :   input_overflow_fds_.clear();
     883             : 
     884             : #if defined(OS_MACOSX)
     885             :   for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin();
     886             :        i != pending_fds_.end();
     887             :        i++) {
     888             :     (*i).fds->CommitAll();
     889             :   }
     890             :   pending_fds_.clear();
     891             : #endif
     892             : 
     893          13 :   closed_ = true;
     894          13 : }
     895             : 
     896          28 : bool Channel::ChannelImpl::Unsound_IsClosed() const
     897             : {
     898          28 :   return closed_;
     899             : }
     900             : 
     901           0 : uint32_t Channel::ChannelImpl::Unsound_NumQueuedMessages() const
     902             : {
     903           0 :   return output_queue_length_;
     904             : }
     905             : 
     906             : //------------------------------------------------------------------------------
     907             : // Channel's methods simply call through to ChannelImpl.
     908          17 : Channel::Channel(const std::wstring& channel_id, Mode mode,
     909          17 :                  Listener* listener)
     910          17 :     : channel_impl_(new ChannelImpl(channel_id, mode, listener)) {
     911          17 :   MOZ_COUNT_CTOR(IPC::Channel);
     912          17 : }
     913             : 
     914          24 : Channel::Channel(int fd, Mode mode, Listener* listener)
     915          24 :     : channel_impl_(new ChannelImpl(fd, mode, listener)) {
     916          24 :   MOZ_COUNT_CTOR(IPC::Channel);
     917          24 : }
     918             : 
     919          26 : Channel::~Channel() {
     920          13 :   MOZ_COUNT_DTOR(IPC::Channel);
     921          13 :   delete channel_impl_;
     922          13 : }
     923             : 
     924          28 : bool Channel::Connect() {
     925          28 :   return channel_impl_->Connect();
     926             : }
     927             : 
     928           0 : void Channel::Close() {
     929           0 :   channel_impl_->Close();
     930           0 : }
     931             : 
     932          28 : Channel::Listener* Channel::set_listener(Listener* listener) {
     933          28 :   return channel_impl_->set_listener(listener);
     934             : }
     935             : 
     936         364 : bool Channel::Send(Message* message) {
     937         364 :   return channel_impl_->Send(message);
     938             : }
     939             : 
     940          15 : void Channel::GetClientFileDescriptorMapping(int *src_fd, int *dest_fd) const {
     941          15 :   return channel_impl_->GetClientFileDescriptorMapping(src_fd, dest_fd);
     942             : }
     943             : 
     944           0 : void Channel::ResetFileDescriptor(int fd) {
     945           0 :   channel_impl_->ResetFileDescriptor(fd);
     946           0 : }
     947             : 
     948          13 : int Channel::GetFileDescriptor() const {
     949          13 :     return channel_impl_->GetFileDescriptor();
     950             : }
     951             : 
     952           2 : void Channel::CloseClientFileDescriptor() {
     953           2 :   channel_impl_->CloseClientFileDescriptor();
     954           2 : }
     955             : 
     956          28 : bool Channel::Unsound_IsClosed() const {
     957          28 :   return channel_impl_->Unsound_IsClosed();
     958             : }
     959             : 
     960           0 : uint32_t Channel::Unsound_NumQueuedMessages() const {
     961           0 :   return channel_impl_->Unsound_NumQueuedMessages();
     962             : }
     963             : 
     964             : // static
     965          15 : std::wstring Channel::GenerateVerifiedChannelID(const std::wstring& prefix) {
     966             :   // A random name is sufficient validation on posix systems, so we don't need
     967             :   // an additional shared secret.
     968             : 
     969          30 :   std::wstring id = prefix;
     970          15 :   if (!id.empty())
     971           0 :     id.append(L".");
     972             : 
     973          30 :   return id.append(GenerateUniqueRandomChannelID());
     974             : }
     975             : 
     976             : }  // namespace IPC

Generated by: LCOV version 1.13