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
|