ipc_channel_posix.cc (41981B)
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 #include "mozilla/Mutex.h" 13 #if defined(XP_DARWIN) 14 # include <mach/message.h> 15 # include <mach/port.h> 16 # include "mozilla/UniquePtrExtensions.h" 17 # include "chrome/common/mach_ipc_mac.h" 18 #endif 19 #if defined(XP_DARWIN) || defined(XP_NETBSD) 20 # include <sched.h> 21 #endif 22 #include <stddef.h> 23 #include <unistd.h> 24 #include <sys/types.h> 25 #include <sys/socket.h> 26 #include <sys/stat.h> 27 #include <sys/un.h> 28 #include <sys/uio.h> 29 30 #include "base/command_line.h" 31 #include "base/eintr_wrapper.h" 32 #include "base/logging.h" 33 #include "base/process.h" 34 #include "base/process_util.h" 35 #include "base/string_util.h" 36 #include "chrome/common/chrome_switches.h" 37 #include "chrome/common/ipc_channel_utils.h" 38 #include "chrome/common/ipc_message_utils.h" 39 #include "mozilla/ipc/Endpoint.h" 40 #include "mozilla/ipc/ProtocolUtils.h" 41 #include "mozilla/StaticMutex.h" 42 #include "mozilla/UniquePtr.h" 43 44 // Use OS specific iovec array limit where it's possible. 45 #if defined(IOV_MAX) 46 static const size_t kMaxIOVecSize = IOV_MAX; 47 #elif defined(ANDROID) 48 static const size_t kMaxIOVecSize = 256; 49 #else 50 static const size_t kMaxIOVecSize = 16; 51 #endif 52 53 using namespace mozilla::ipc; 54 55 namespace IPC { 56 57 //------------------------------------------------------------------------------ 58 namespace { 59 60 bool ErrorIsBrokenPipe(int err) { return err == EPIPE || err == ECONNRESET; } 61 62 // Some Android ARM64 devices appear to have a bug where sendmsg 63 // sometimes returns 0xFFFFFFFF, which we're assuming is a -1 that was 64 // incorrectly truncated to 32-bit and then zero-extended. 65 // See bug 1660826 for details. 66 // 67 // This is a workaround to detect that value and replace it with -1 68 // (and check that there really was an error), because the largest 69 // amount we'll ever write is Channel::kMaximumMessageSize (256MiB). 70 // 71 // The workaround is also enabled on x86_64 Android on debug builds, 72 // although the bug isn't known to manifest there, so that there will 73 // be some CI coverage of this code. 74 75 static inline ssize_t corrected_sendmsg(int socket, 76 const struct msghdr* message, 77 int flags) { 78 #if defined(ANDROID) && \ 79 (defined(__aarch64__) || (defined(DEBUG) && defined(__x86_64__))) 80 static constexpr auto kBadValue = static_cast<ssize_t>(0xFFFFFFFF); 81 static_assert(kBadValue > 0); 82 83 # ifdef MOZ_DIAGNOSTIC_ASSERT_ENABLED 84 errno = 0; 85 # endif 86 ssize_t bytes_written = sendmsg(socket, message, flags); 87 if (bytes_written == kBadValue) { 88 MOZ_DIAGNOSTIC_ASSERT(errno != 0); 89 bytes_written = -1; 90 } 91 MOZ_DIAGNOSTIC_ASSERT(bytes_written < kBadValue); 92 return bytes_written; 93 #else 94 return sendmsg(socket, message, flags); 95 #endif 96 } 97 98 } // namespace 99 //------------------------------------------------------------------------------ 100 101 const Channel::ChannelKind ChannelPosix::sKind{ 102 .create_raw_pipe = &ChannelPosix::CreateRawPipe, 103 .num_relayed_attachments = &ChannelPosix::NumRelayedAttachments, 104 .is_valid_handle = &ChannelPosix::IsValidHandle, 105 }; 106 107 ChannelPosix::ChannelPosix(mozilla::UniqueFileHandle pipe, Mode mode, 108 base::ProcessId other_pid) 109 : other_pid_(other_pid) { 110 Init(mode); 111 SetPipe(pipe.release()); 112 113 EnqueueHelloMessage(); 114 } 115 116 void ChannelPosix::SetPipe(int fd) { 117 chan_cap_.NoteExclusiveAccess(); 118 119 pipe_ = fd; 120 pipe_buf_len_ = 0; 121 if (fd >= 0) { 122 int buf_len; 123 socklen_t optlen = sizeof(buf_len); 124 if (getsockopt(fd, SOL_SOCKET, SO_SNDBUF, &buf_len, &optlen) != 0) { 125 CHROMIUM_LOG(WARNING) 126 << "Unable to determine pipe buffer size: " << strerror(errno); 127 return; 128 } 129 CHECK(optlen == sizeof(buf_len)); 130 CHECK(buf_len > 0); 131 pipe_buf_len_ = static_cast<unsigned>(buf_len); 132 } 133 } 134 135 bool ChannelPosix::PipeBufHasSpaceAfter(size_t already_written) { 136 // If the OS didn't tell us the buffer size for some reason, then 137 // don't apply this limitation on the amount we try to write. 138 return pipe_buf_len_ == 0 || 139 static_cast<size_t>(pipe_buf_len_) > already_written; 140 } 141 142 void ChannelPosix::Init(Mode mode) { 143 // Verify that we fit in a "quantum-spaced" jemalloc bucket. 144 static_assert(sizeof(*this) <= 512, "Exceeded expected size class"); 145 146 MOZ_RELEASE_ASSERT(kControlBufferHeaderSize >= CMSG_SPACE(0)); 147 MOZ_RELEASE_ASSERT(kControlBufferSize >= 148 CMSG_SPACE(sizeof(int) * kControlBufferMaxFds)); 149 150 chan_cap_.NoteExclusiveAccess(); 151 152 mode_ = mode; 153 is_blocked_on_write_ = false; 154 partial_write_.reset(); 155 input_buf_offset_ = 0; 156 input_buf_ = mozilla::MakeUnique<char[]>(Channel::kReadBufferSize); 157 input_cmsg_buf_ = mozilla::MakeUnique<char[]>(kControlBufferSize); 158 SetPipe(-1); 159 waiting_connect_ = true; 160 #if defined(XP_DARWIN) 161 last_pending_fd_id_ = 0; 162 other_task_ = nullptr; 163 #endif 164 } 165 166 bool ChannelPosix::EnqueueHelloMessage() { 167 mozilla::UniquePtr<Message> msg( 168 new Message(MSG_ROUTING_NONE, HELLO_MESSAGE_TYPE)); 169 if (!msg->WriteInt(base::GetCurrentProcId())) { 170 CloseLocked(); 171 return false; 172 } 173 174 OutputQueuePush(std::move(msg)); 175 return true; 176 } 177 178 bool ChannelPosix::Connect(Listener* listener) { 179 IOThread().AssertOnCurrentThread(); 180 mozilla::MutexAutoLock lock(SendMutex()); 181 chan_cap_.NoteExclusiveAccess(); 182 183 if (pipe_ == -1) { 184 return false; 185 } 186 187 listener_ = listener; 188 189 return ContinueConnect(); 190 } 191 192 bool ChannelPosix::ContinueConnect() { 193 chan_cap_.NoteExclusiveAccess(); 194 MOZ_ASSERT(pipe_ != -1); 195 196 #if defined(XP_DARWIN) 197 // If we're still waiting for our peer task to be provided, don't start 198 // listening yet. We'll start receiving messages once the task_t is set. 199 if (mode_ == MODE_BROKER_SERVER && !other_task_) { 200 MOZ_ASSERT(waiting_connect_); 201 return true; 202 } 203 #endif 204 205 MessageLoopForIO::current()->WatchFileDescriptor( 206 pipe_, true, MessageLoopForIO::WATCH_READ, &read_watcher_, this); 207 waiting_connect_ = false; 208 209 return ProcessOutgoingMessages(); 210 } 211 212 void ChannelPosix::SetOtherPid(base::ProcessId other_pid) { 213 IOThread().AssertOnCurrentThread(); 214 mozilla::MutexAutoLock lock(SendMutex()); 215 chan_cap_.NoteExclusiveAccess(); 216 MOZ_RELEASE_ASSERT( 217 other_pid_ == base::kInvalidProcessId || other_pid_ == other_pid, 218 "Multiple sources of SetOtherPid disagree!"); 219 other_pid_ = other_pid; 220 } 221 222 bool ChannelPosix::ProcessIncomingMessages() { 223 chan_cap_.NoteOnTarget(); 224 225 struct msghdr msg = {0}; 226 struct iovec iov; 227 228 msg.msg_iov = &iov; 229 msg.msg_iovlen = 1; 230 msg.msg_control = input_cmsg_buf_.get(); 231 232 for (;;) { 233 msg.msg_controllen = kControlBufferSize; 234 235 if (pipe_ == -1) return false; 236 237 // In some cases the beginning of a message will be stored in input_buf_. We 238 // don't want to overwrite that, so we store the new data after it. 239 iov.iov_base = input_buf_.get() + input_buf_offset_; 240 iov.iov_len = Channel::kReadBufferSize - input_buf_offset_; 241 242 // Read from pipe. 243 // recvmsg() returns 0 if the connection has closed or EAGAIN if no data 244 // is waiting on the pipe. 245 ssize_t bytes_read = HANDLE_EINTR(recvmsg(pipe_, &msg, MSG_DONTWAIT)); 246 247 if (bytes_read < 0) { 248 if (errno == EAGAIN) { 249 return true; 250 } else { 251 if (!ErrorIsBrokenPipe(errno)) { 252 CHROMIUM_LOG(ERROR) 253 << "pipe error (fd " << pipe_ << "): " << strerror(errno); 254 } 255 return false; 256 } 257 } else if (bytes_read == 0) { 258 // The pipe has closed... 259 Close(); 260 return false; 261 } 262 DCHECK(bytes_read); 263 264 // a pointer to an array of |num_wire_fds| file descriptors from the read 265 const int* wire_fds = NULL; 266 unsigned num_wire_fds = 0; 267 268 // walk the list of control messages and, if we find an array of file 269 // descriptors, save a pointer to the array 270 271 // This next if statement is to work around an OSX issue where 272 // CMSG_FIRSTHDR will return non-NULL in the case that controllen == 0. 273 // Here's a test case: 274 // 275 // int main() { 276 // struct msghdr msg; 277 // msg.msg_control = &msg; 278 // msg.msg_controllen = 0; 279 // if (CMSG_FIRSTHDR(&msg)) 280 // printf("Bug found!\n"); 281 // } 282 if (msg.msg_controllen > 0) { 283 // On OSX, CMSG_FIRSTHDR doesn't handle the case where controllen is 0 284 // and will return a pointer into nowhere. 285 for (struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msg); cmsg; 286 cmsg = CMSG_NXTHDR(&msg, cmsg)) { 287 if (cmsg->cmsg_level == SOL_SOCKET && cmsg->cmsg_type == SCM_RIGHTS) { 288 const unsigned payload_len = cmsg->cmsg_len - CMSG_LEN(0); 289 DCHECK(payload_len % sizeof(int) == 0); 290 wire_fds = reinterpret_cast<int*>(CMSG_DATA(cmsg)); 291 num_wire_fds = payload_len / 4; 292 293 if (msg.msg_flags & MSG_CTRUNC) { 294 CHROMIUM_LOG(ERROR) 295 << "SCM_RIGHTS message was truncated" 296 << " cmsg_len:" << cmsg->cmsg_len << " fd:" << pipe_; 297 for (unsigned i = 0; i < num_wire_fds; ++i) 298 IGNORE_EINTR(close(wire_fds[i])); 299 return false; 300 } 301 break; 302 } 303 } 304 } 305 306 // Process messages from input buffer. 307 const char* p = input_buf_.get(); 308 const char* end = input_buf_.get() + input_buf_offset_ + bytes_read; 309 310 // A pointer to an array of |num_fds| file descriptors which includes any 311 // fds that have spilled over from a previous read. 312 const int* fds; 313 unsigned num_fds; 314 unsigned fds_i = 0; // the index of the first unused descriptor 315 316 if (input_overflow_fds_.empty()) { 317 fds = wire_fds; 318 num_fds = num_wire_fds; 319 } else { 320 // This code may look like a no-op in the case where 321 // num_wire_fds == 0, but in fact: 322 // 323 // 1. wire_fds will be nullptr, so passing it to memcpy is 324 // undefined behavior according to the C standard, even though 325 // the memcpy length is 0. 326 // 327 // 2. prev_size will be an out-of-bounds index for 328 // input_overflow_fds_; this is undefined behavior according to 329 // the C++ standard, even though the element only has its 330 // pointer taken and isn't accessed (and the corresponding 331 // operation on a C array would be defined). 332 // 333 // UBSan makes #1 a fatal error, and assertions in libstdc++ do 334 // the same for #2 if enabled. 335 if (num_wire_fds > 0) { 336 const size_t prev_size = input_overflow_fds_.size(); 337 input_overflow_fds_.resize(prev_size + num_wire_fds); 338 memcpy(&input_overflow_fds_[prev_size], wire_fds, 339 num_wire_fds * sizeof(int)); 340 } 341 fds = &input_overflow_fds_[0]; 342 num_fds = input_overflow_fds_.size(); 343 } 344 345 // The data for the message we're currently reading consists of any data 346 // stored in incoming_message_ followed by data in input_buf_ (followed by 347 // other messages). 348 349 // NOTE: We re-check `pipe_` after each message to make sure we weren't 350 // closed while calling `OnMessageReceived` or `OnChannelConnected`. 351 while (p < end && pipe_ != -1) { 352 // Try to figure out how big the message is. Size is 0 if we haven't read 353 // enough of the header to know the size. 354 uint32_t message_length = 0; 355 if (incoming_message_) { 356 message_length = incoming_message_->size(); 357 } else { 358 message_length = Message::MessageSize(p, end); 359 } 360 361 if (!message_length) { 362 // We haven't seen the full message header. 363 MOZ_ASSERT(!incoming_message_); 364 365 // Move everything we have to the start of the buffer. We'll finish 366 // reading this message when we get more data. For now we leave it in 367 // input_buf_. 368 memmove(input_buf_.get(), p, end - p); 369 input_buf_offset_ = end - p; 370 371 break; 372 } 373 374 input_buf_offset_ = 0; 375 376 bool partial; 377 if (incoming_message_) { 378 // We already have some data for this message stored in 379 // incoming_message_. We want to append the new data there. 380 Message& m = *incoming_message_; 381 382 // How much data from this message remains to be added to 383 // incoming_message_? 384 MOZ_DIAGNOSTIC_ASSERT(message_length > m.CurrentSize()); 385 uint32_t remaining = message_length - m.CurrentSize(); 386 387 // How much data from this message is stored in input_buf_? 388 uint32_t in_buf = std::min(remaining, uint32_t(end - p)); 389 390 m.InputBytes(p, in_buf); 391 p += in_buf; 392 393 // Are we done reading this message? 394 partial = in_buf != remaining; 395 } else { 396 // How much data from this message is stored in input_buf_? 397 uint32_t in_buf = std::min(message_length, uint32_t(end - p)); 398 399 incoming_message_ = mozilla::MakeUnique<Message>(p, in_buf); 400 p += in_buf; 401 402 // Are we done reading this message? 403 partial = in_buf != message_length; 404 } 405 406 if (partial) { 407 break; 408 } 409 410 Message& m = *incoming_message_; 411 412 if (m.header()->num_handles) { 413 // the message has file descriptors 414 const char* error = NULL; 415 if (m.header()->num_handles > num_fds - fds_i) { 416 // the message has been completely received, but we didn't get 417 // enough file descriptors. 418 error = "Message needs unreceived descriptors"; 419 } 420 421 size_t maxHandles = std::min<size_t>( 422 m.size(), IPC::Message::MAX_DESCRIPTORS_PER_MESSAGE); 423 if (m.header()->num_handles > maxHandles) { 424 // There are too many descriptors in this message 425 error = "Message requires an excessive number of descriptors"; 426 } 427 428 if (error) { 429 CHROMIUM_LOG(WARNING) 430 << error << " channel:" << this << " message-type:" << m.type() 431 << " header()->num_handles:" << m.header()->num_handles 432 << " num_fds:" << num_fds << " fds_i:" << fds_i; 433 // close the existing file descriptors so that we don't leak them 434 for (unsigned i = fds_i; i < num_fds; ++i) 435 IGNORE_EINTR(close(fds[i])); 436 input_overflow_fds_.clear(); 437 // abort the connection 438 return false; 439 } 440 441 #if defined(XP_DARWIN) 442 // Send a message to the other side, indicating that we are now 443 // responsible for closing the descriptor. 444 auto fdAck = mozilla::MakeUnique<Message>(MSG_ROUTING_NONE, 445 RECEIVED_FDS_MESSAGE_TYPE); 446 DCHECK(m.fd_cookie() != 0); 447 fdAck->set_fd_cookie(m.fd_cookie()); 448 { 449 mozilla::MutexAutoLock lock(SendMutex()); 450 OutputQueuePush(std::move(fdAck)); 451 } 452 #endif 453 454 nsTArray<mozilla::UniqueFileHandle> handles(m.header()->num_handles); 455 for (unsigned end_i = fds_i + m.header()->num_handles; fds_i < end_i; 456 ++fds_i) { 457 handles.AppendElement(mozilla::UniqueFileHandle(fds[fds_i])); 458 } 459 m.SetAttachedFileHandles(std::move(handles)); 460 } 461 462 // Note: We set other_pid_ below when we receive a Hello message (which 463 // has no routing ID), but we only emit a profiler marker for messages 464 // with a routing ID, so there's no conflict here. 465 AddIPCProfilerMarker(m, other_pid_, MessageDirection::eReceiving, 466 MessagePhase::TransferEnd); 467 468 #ifdef IPC_MESSAGE_DEBUG_EXTRA 469 DLOG(INFO) << "received message on channel @" << this << " with type " 470 << m.type(); 471 #endif 472 473 if (m.routing_id() == MSG_ROUTING_NONE && 474 m.type() == HELLO_MESSAGE_TYPE) { 475 // The Hello message contains only the process id. 476 int32_t other_pid = MessageIterator(m).NextInt(); 477 SetOtherPid(other_pid); 478 listener_->OnChannelConnected(other_pid); 479 #if defined(XP_DARWIN) 480 } else if (m.routing_id() == MSG_ROUTING_NONE && 481 m.type() == RECEIVED_FDS_MESSAGE_TYPE) { 482 DCHECK(m.fd_cookie() != 0); 483 CloseDescriptors(m.fd_cookie()); 484 #endif 485 } else { 486 mozilla::LogIPCMessage::Run run(&m); 487 #if defined(XP_DARWIN) 488 if (!AcceptMachPorts(m)) { 489 return false; 490 } 491 #endif 492 listener_->OnMessageReceived(std::move(incoming_message_)); 493 } 494 495 incoming_message_ = nullptr; 496 } 497 498 input_overflow_fds_ = std::vector<int>(&fds[fds_i], &fds[num_fds]); 499 500 // When the input data buffer is empty, the overflow fds should be too. If 501 // this is not the case, we probably have a rogue renderer which is trying 502 // to fill our descriptor table. 503 if (!incoming_message_ && input_buf_offset_ == 0 && 504 !input_overflow_fds_.empty()) { 505 // We close these descriptors in Close() 506 return false; 507 } 508 } 509 } 510 511 bool ChannelPosix::ProcessOutgoingMessages() { 512 // NOTE: This method may be called on threads other than `IOThread()`. 513 chan_cap_.NoteLockHeld(); 514 515 DCHECK(!waiting_connect_); // Why are we trying to send messages if there's 516 // no connection? 517 is_blocked_on_write_ = false; 518 519 if (output_queue_.IsEmpty()) return true; 520 521 if (pipe_ == -1) return false; 522 523 // Write out all the messages we can till the write blocks or there are no 524 // more outgoing messages. 525 while (!output_queue_.IsEmpty()) { 526 Message* msg = output_queue_.FirstElement().get(); 527 528 struct msghdr msgh = {0}; 529 530 char cmsgBuf[kControlBufferSize]; 531 532 if (partial_write_.isNothing()) { 533 #if defined(XP_DARWIN) 534 if (!TransferMachPorts(*msg)) { 535 return false; 536 } 537 #endif 538 539 size_t maxHandles = std::min<size_t>( 540 msg->size(), IPC::Message::MAX_DESCRIPTORS_PER_MESSAGE); 541 if (msg->attached_handles_.Length() > maxHandles) { 542 MOZ_DIAGNOSTIC_CRASH("Too many file descriptors!"); 543 CHROMIUM_LOG(FATAL) << "Too many file descriptors!"; 544 // This should not be reached. 545 return false; 546 } 547 548 msg->header()->num_handles = msg->attached_handles_.Length(); 549 #if defined(XP_DARWIN) 550 if (!msg->attached_handles_.IsEmpty()) { 551 msg->set_fd_cookie(++last_pending_fd_id_); 552 } 553 #endif 554 555 Pickle::BufferList::IterImpl iter(msg->Buffers()); 556 MOZ_DIAGNOSTIC_ASSERT(!iter.Done(), "empty message"); 557 partial_write_.emplace(PartialWrite{iter, msg->attached_handles_}); 558 559 AddIPCProfilerMarker(*msg, other_pid_, MessageDirection::eSending, 560 MessagePhase::TransferStart); 561 } 562 563 if (partial_write_->iter_.Done()) { 564 MOZ_DIAGNOSTIC_CRASH("partial_write_->iter_ should not be done"); 565 // report a send error to our caller, which will close the channel. 566 return false; 567 } 568 569 // How much of this message have we written so far? 570 Pickle::BufferList::IterImpl iter = partial_write_->iter_; 571 auto handles = partial_write_->handles_; 572 573 // Serialize attached file descriptors into the cmsg header. Only up to 574 // kControlBufferMaxFds can be serialized at once, so messages with more 575 // attachments must be sent over multiple `sendmsg` calls. 576 const size_t num_fds = std::min(handles.Length(), kControlBufferMaxFds); 577 size_t max_amt_to_write = iter.TotalBytesAvailable(msg->Buffers()); 578 if (num_fds > 0) { 579 msgh.msg_control = cmsgBuf; 580 msgh.msg_controllen = CMSG_LEN(sizeof(int) * num_fds); 581 struct cmsghdr* cmsg = CMSG_FIRSTHDR(&msgh); 582 cmsg->cmsg_level = SOL_SOCKET; 583 cmsg->cmsg_type = SCM_RIGHTS; 584 cmsg->cmsg_len = msgh.msg_controllen; 585 for (size_t i = 0; i < num_fds; ++i) { 586 reinterpret_cast<int*>(CMSG_DATA(cmsg))[i] = handles[i].get(); 587 } 588 589 // Avoid writing one byte per remaining handle in excess of 590 // kControlBufferMaxFds. Each handle written will consume a minimum of 4 591 // bytes in the message (to store it's index), so we can depend on there 592 // being enough data to send every handle. 593 size_t remaining = handles.Length() - num_fds; 594 MOZ_ASSERT(max_amt_to_write > remaining, 595 "must be at least one byte in the message for each handle"); 596 max_amt_to_write -= remaining; 597 } 598 599 // Store remaining segments to write into iovec. 600 // 601 // Don't add more than kMaxIOVecSize iovecs so that we avoid 602 // OS-dependent limits. Also, stop adding iovecs if we've already 603 // prepared to write at least the full buffer size. 604 struct iovec iov[kMaxIOVecSize]; 605 size_t iov_count = 0; 606 size_t amt_to_write = 0; 607 while (!iter.Done() && iov_count < kMaxIOVecSize && 608 PipeBufHasSpaceAfter(amt_to_write) && 609 amt_to_write < max_amt_to_write) { 610 char* data = iter.Data(); 611 size_t size = 612 std::min(iter.RemainingInSegment(), max_amt_to_write - amt_to_write); 613 614 iov[iov_count].iov_base = data; 615 iov[iov_count].iov_len = size; 616 iov_count++; 617 amt_to_write += size; 618 iter.Advance(msg->Buffers(), size); 619 } 620 MOZ_ASSERT(amt_to_write <= max_amt_to_write); 621 MOZ_ASSERT(amt_to_write > 0); 622 623 const bool intentional_short_write = !iter.Done(); 624 msgh.msg_iov = iov; 625 msgh.msg_iovlen = iov_count; 626 627 ssize_t bytes_written = 628 HANDLE_EINTR(corrected_sendmsg(pipe_, &msgh, MSG_DONTWAIT)); 629 630 if (bytes_written < 0) { 631 switch (errno) { 632 case EAGAIN: 633 // Not an error; the sendmsg would have blocked, so return to the 634 // event loop and try again later. 635 break; 636 #if defined(XP_DARWIN) || defined(XP_NETBSD) 637 // (Note: this comment is copied from https://crrev.com/86c3d9ef4fdf6; 638 // see also bug 1142693 comment #73.) 639 // 640 // On OS X if sendmsg() is trying to send fds between processes and 641 // there isn't enough room in the output buffer to send the fd 642 // structure over atomically then EMSGSIZE is returned. The same 643 // applies to NetBSD as well. 644 // 645 // EMSGSIZE presents a problem since the system APIs can only call us 646 // when there's room in the socket buffer and not when there is 647 // "enough" room. 648 // 649 // The current behavior is to return to the event loop when EMSGSIZE 650 // is received and hopefull service another FD. This is however still 651 // technically a busy wait since the event loop will call us right 652 // back until the receiver has read enough data to allow passing the 653 // FD over atomically. 654 case EMSGSIZE: 655 // Because this is likely to result in a busy-wait, we'll try to make 656 // it easier for the receiver to make progress, but only if we're on 657 // the I/O thread already. 658 if (IOThread().IsOnCurrentThread()) { 659 sched_yield(); 660 } 661 break; 662 #endif 663 default: 664 if (!ErrorIsBrokenPipe(errno)) { 665 CHROMIUM_LOG(ERROR) << "pipe error: " << strerror(errno); 666 } 667 return false; 668 } 669 } 670 671 if (intentional_short_write || 672 static_cast<size_t>(bytes_written) != amt_to_write) { 673 // If write() fails with EAGAIN or EMSGSIZE then bytes_written will be -1. 674 if (bytes_written > 0) { 675 MOZ_DIAGNOSTIC_ASSERT(intentional_short_write || 676 static_cast<size_t>(bytes_written) < 677 amt_to_write); 678 partial_write_->iter_.AdvanceAcrossSegments(msg->Buffers(), 679 bytes_written); 680 partial_write_->handles_ = handles.From(num_fds); 681 // We should not hit the end of the buffer. 682 MOZ_DIAGNOSTIC_ASSERT(!partial_write_->iter_.Done()); 683 } 684 685 is_blocked_on_write_ = true; 686 if (IOThread().IsOnCurrentThread()) { 687 // If we're on the I/O thread already, tell libevent to call us back 688 // when things are unblocked. 689 MessageLoopForIO::current()->WatchFileDescriptor( 690 pipe_, 691 false, // One shot 692 MessageLoopForIO::WATCH_WRITE, &write_watcher_, this); 693 } else { 694 // Otherwise, emulate being called back from libevent on the I/O thread, 695 // which will re-try the write, and then potentially start watching if 696 // still necessary. 697 IOThread().Dispatch(mozilla::NewRunnableMethod<int>( 698 "ChannelPosix::ContinueProcessOutgoing", this, 699 &ChannelPosix::OnFileCanWriteWithoutBlocking, -1)); 700 } 701 return true; 702 } else { 703 MOZ_ASSERT(partial_write_->handles_.Length() == num_fds, 704 "not all handles were sent"); 705 partial_write_.reset(); 706 707 #if defined(XP_DARWIN) 708 if (!msg->attached_handles_.IsEmpty()) { 709 pending_fds_.push_back(PendingDescriptors{ 710 msg->fd_cookie(), std::move(msg->attached_handles_)}); 711 } 712 #else 713 if (bytes_written > 0) { 714 msg->attached_handles_.Clear(); 715 } 716 #endif 717 718 // Message sent OK! 719 720 AddIPCProfilerMarker(*msg, other_pid_, MessageDirection::eSending, 721 MessagePhase::TransferEnd); 722 723 #ifdef IPC_MESSAGE_DEBUG_EXTRA 724 DLOG(INFO) << "sent message @" << msg << " on channel @" << this 725 << " with type " << msg->type(); 726 #endif 727 OutputQueuePop(); 728 // msg has been destroyed, so clear the dangling reference. 729 msg = nullptr; 730 } 731 } 732 return true; 733 } 734 735 bool ChannelPosix::Send(mozilla::UniquePtr<Message> message) { 736 // NOTE: This method may be called on threads other than `IOThread()`. 737 mozilla::MutexAutoLock lock(SendMutex()); 738 chan_cap_.NoteLockHeld(); 739 740 #ifdef IPC_MESSAGE_DEBUG_EXTRA 741 DLOG(INFO) << "sending message @" << message.get() << " on channel @" << this 742 << " with type " << message->type() << " (" 743 << output_queue_.Count() << " in queue)"; 744 #endif 745 746 // If the channel has been closed, ProcessOutgoingMessages() is never going 747 // to pop anything off output_queue; output_queue will only get emptied when 748 // the channel is destructed. We might as well delete message now, instead 749 // of waiting for the channel to be destructed. 750 if (pipe_ == -1) { 751 if (mozilla::ipc::LoggingEnabled()) { 752 fprintf(stderr, 753 "Can't send message %s, because this channel is closed.\n", 754 message->name()); 755 } 756 return false; 757 } 758 759 OutputQueuePush(std::move(message)); 760 if (!waiting_connect_) { 761 if (!is_blocked_on_write_) { 762 if (!ProcessOutgoingMessages()) return false; 763 } 764 } 765 766 return true; 767 } 768 769 // Called by libevent when we can read from th pipe without blocking. 770 void ChannelPosix::OnFileCanReadWithoutBlocking(int fd) { 771 IOThread().AssertOnCurrentThread(); 772 chan_cap_.NoteOnTarget(); 773 774 if (!waiting_connect_ && fd == pipe_ && pipe_ != -1) { 775 if (!ProcessIncomingMessages()) { 776 Close(); 777 listener_->OnChannelError(); 778 // The OnChannelError() call may delete this, so we need to exit now. 779 return; 780 } 781 } 782 } 783 784 #if defined(XP_DARWIN) 785 void ChannelPosix::CloseDescriptors(uint32_t pending_fd_id) { 786 mozilla::MutexAutoLock lock(SendMutex()); 787 chan_cap_.NoteExclusiveAccess(); 788 789 DCHECK(pending_fd_id != 0); 790 for (std::list<PendingDescriptors>::iterator i = pending_fds_.begin(); 791 i != pending_fds_.end(); i++) { 792 if ((*i).id == pending_fd_id) { 793 pending_fds_.erase(i); 794 return; 795 } 796 } 797 DCHECK(false) << "pending_fd_id not in our list!"; 798 } 799 #endif 800 801 void ChannelPosix::OutputQueuePush(mozilla::UniquePtr<Message> msg) { 802 chan_cap_.NoteLockHeld(); 803 804 mozilla::LogIPCMessage::LogDispatchWithPid(msg.get(), other_pid_); 805 806 MOZ_DIAGNOSTIC_ASSERT(pipe_ != -1); 807 msg->AssertAsLargeAsHeader(); 808 output_queue_.Push(std::move(msg)); 809 } 810 811 void ChannelPosix::OutputQueuePop() { 812 // Clear any reference to the front of output_queue_ before we destroy it. 813 partial_write_.reset(); 814 815 mozilla::UniquePtr<Message> message = output_queue_.Pop(); 816 } 817 818 // Called by libevent when we can write to the pipe without blocking. 819 void ChannelPosix::OnFileCanWriteWithoutBlocking(int fd) { 820 RefPtr<ChannelPosix> grip(this); 821 IOThread().AssertOnCurrentThread(); 822 mozilla::ReleasableMutexAutoLock lock(SendMutex()); 823 chan_cap_.NoteExclusiveAccess(); 824 if (pipe_ != -1 && !ProcessOutgoingMessages()) { 825 CloseLocked(); 826 lock.Unlock(); 827 listener_->OnChannelError(); 828 } 829 } 830 831 void ChannelPosix::Close() { 832 IOThread().AssertOnCurrentThread(); 833 mozilla::MutexAutoLock lock(SendMutex()); 834 CloseLocked(); 835 } 836 837 void ChannelPosix::CloseLocked() { 838 chan_cap_.NoteExclusiveAccess(); 839 840 // Close can be called multiple times, so we need to make sure we're 841 // idempotent. 842 843 // Unregister libevent for the FIFO and close it. 844 read_watcher_.StopWatchingFileDescriptor(); 845 write_watcher_.StopWatchingFileDescriptor(); 846 if (pipe_ != -1) { 847 IGNORE_EINTR(close(pipe_)); 848 SetPipe(-1); 849 } 850 851 while (!output_queue_.IsEmpty()) { 852 OutputQueuePop(); 853 } 854 855 // Close any outstanding, received file descriptors 856 for (std::vector<int>::iterator i = input_overflow_fds_.begin(); 857 i != input_overflow_fds_.end(); ++i) { 858 IGNORE_EINTR(close(*i)); 859 } 860 input_overflow_fds_.clear(); 861 862 #if defined(XP_DARWIN) 863 pending_fds_.clear(); 864 865 other_task_ = nullptr; 866 #endif 867 } 868 869 #if defined(XP_DARWIN) 870 void ChannelPosix::SetOtherMachTask(task_t task) { 871 IOThread().AssertOnCurrentThread(); 872 mozilla::MutexAutoLock lock(SendMutex()); 873 chan_cap_.NoteExclusiveAccess(); 874 875 if (NS_WARN_IF(pipe_ == -1)) { 876 return; 877 } 878 879 MOZ_ASSERT(mode_ == MODE_BROKER_SERVER && waiting_connect_); 880 other_task_ = mozilla::RetainMachSendRight(task); 881 // Now that `other_task_` is provided, we can continue connecting. 882 ContinueConnect(); 883 } 884 885 //------------------------------------------------------------------------------ 886 // Mach port transferring logic 887 // 888 // It is currently not possible to directly transfer a mach send right between 889 // two content processes using SCM_RIGHTS, unlike how we can handle file 890 // descriptors. This means that mach ports need to be transferred through a 891 // separate mechanism. This file only implements support for transferring mach 892 // ports between a (potentially sandboxed) child process and the parent process. 893 // Support for transferring mach ports between other process pairs is handled by 894 // `NodeController`, which is responsible for relaying messages which carry 895 // handles via the parent process. 896 // 897 // The logic which we use for doing this is based on the following from 898 // Chromium, which pioneered this technique. As of this writing, chromium no 899 // longer uses this strategy, as all IPC messages are sent using mach ports on 900 // macOS. 901 // https://source.chromium.org/chromium/chromium/src/+/9f707e5e04598d8303fa99ca29eb507c839767d8:mojo/core/mach_port_relay.cc 902 // https://source.chromium.org/chromium/chromium/src/+/9f707e5e04598d8303fa99ca29eb507c839767d8:base/mac/mach_port_util.cc. 903 // 904 // As we only need to consider messages between the privileged (parent) and 905 // unprivileged (child) processes in this code, there are 2 relevant cases which 906 // we need to handle: 907 // 908 // # Unprivileged (child) to Privileged (parent) 909 // 910 // As the privileged process has access to the unprivileged process' `task_t`, 911 // it is possible to directly extract the mach port from the target process' 912 // address space, given its name, using `mach_port_extract_right`. 913 // 914 // To transfer the port, the unprivileged process will leak a reference to the 915 // send right, and include the port's name in the message footer. The privileged 916 // process will extract that port right (and drop the reference in the old 917 // process) using `mach_port_extract_right` with `MACH_MSG_TYPE_MOVE_SEND`. The 918 // call to `mach_port_extract_right` is handled by `BrokerExtractSendRight` 919 // 920 // # Privileged (parent) to Unprivileged (child) 921 // 922 // Unfortunately, the process of transferring a right into a target process is 923 // more complex. The only well-supported way to transfer a right into a process 924 // is by sending it with `mach_msg`, and receiving it on the other side [1]. 925 // 926 // To work around this, the privileged process uses `mach_port_allocate` to 927 // create a new receive right in the target process using its `task_t`, and 928 // `mach_port_extract_right` to extract a send-once right to that port. It then 929 // sends a message to the port with port we're intending to send as an 930 // attachment. This is handled by `BrokerTransferSendRight`, which returns the 931 // name of the newly created receive right in the target process to be sent in 932 // the message footer. 933 // 934 // In the unprivileged process, `mach_msg` is used to receive a single message 935 // from the receive right, which will have the actual port we were trying to 936 // transfer as an attachment. This is handled by the `MachReceivePortSendRight` 937 // function. 938 // 939 // [1] We cannot use `mach_port_insert_right` to transfer the right into the 940 // target process, as that method requires explicitly specifying the remote 941 // port's name, and we do not control the port name allocator. 942 943 // Extract a send right from the given peer task. A reference to the remote 944 // right will be dropped. See comment above for details. 945 static mozilla::UniqueMachSendRight BrokerExtractSendRight( 946 task_t task, mach_port_name_t name) { 947 mach_port_t extractedRight = MACH_PORT_NULL; 948 mach_msg_type_name_t extractedRightType; 949 kern_return_t kr = 950 mach_port_extract_right(task, name, MACH_MSG_TYPE_MOVE_SEND, 951 &extractedRight, &extractedRightType); 952 if (kr != KERN_SUCCESS) { 953 CHROMIUM_LOG(ERROR) << "failed to extract port right from other process. " 954 << mach_error_string(kr); 955 return nullptr; 956 } 957 MOZ_ASSERT(extractedRightType == MACH_MSG_TYPE_PORT_SEND, 958 "We asked the OS for a send port"); 959 return mozilla::UniqueMachSendRight(extractedRight); 960 } 961 962 // Transfer a send right to the given peer task. The name of a receive right in 963 // the remote process will be returned if successful. The sent port can be 964 // obtained from that port in the peer task using `MachReceivePortSendRight`. 965 // See comment above for details. 966 static mozilla::Maybe<mach_port_name_t> BrokerTransferSendRight( 967 task_t task, mozilla::UniqueMachSendRight port_to_send) { 968 mach_port_name_t endpoint; 969 kern_return_t kr = 970 mach_port_allocate(task, MACH_PORT_RIGHT_RECEIVE, &endpoint); 971 if (kr != KERN_SUCCESS) { 972 CHROMIUM_LOG(ERROR) 973 << "Unable to create receive right in TransferMachPorts. " 974 << mach_error_string(kr); 975 return mozilla::Nothing(); 976 } 977 978 // Clean up the endpoint on error. 979 auto destroyEndpoint = 980 mozilla::MakeScopeExit([&] { mach_port_deallocate(task, endpoint); }); 981 982 // Change its message queue limit so that it accepts one message. 983 mach_port_limits limits = {}; 984 limits.mpl_qlimit = 1; 985 kr = mach_port_set_attributes(task, endpoint, MACH_PORT_LIMITS_INFO, 986 reinterpret_cast<mach_port_info_t>(&limits), 987 MACH_PORT_LIMITS_INFO_COUNT); 988 if (kr != KERN_SUCCESS) { 989 CHROMIUM_LOG(ERROR) 990 << "Unable configure receive right in TransferMachPorts. " 991 << mach_error_string(kr); 992 return mozilla::Nothing(); 993 } 994 995 // Get a send right. 996 mach_port_t send_once_right; 997 mach_msg_type_name_t send_right_type; 998 kr = mach_port_extract_right(task, endpoint, MACH_MSG_TYPE_MAKE_SEND_ONCE, 999 &send_once_right, &send_right_type); 1000 if (kr != KERN_SUCCESS) { 1001 CHROMIUM_LOG(ERROR) << "Unable extract send right in TransferMachPorts. " 1002 << mach_error_string(kr); 1003 return mozilla::Nothing(); 1004 } 1005 MOZ_ASSERT(MACH_MSG_TYPE_PORT_SEND_ONCE == send_right_type); 1006 1007 kr = MachSendPortSendRight(send_once_right, port_to_send.get(), 1008 mozilla::Some(0), MACH_MSG_TYPE_MOVE_SEND_ONCE); 1009 if (kr != KERN_SUCCESS) { 1010 // This right will be destroyed due to being a SEND_ONCE right if we 1011 // succeed. 1012 mach_port_deallocate(mach_task_self(), send_once_right); 1013 CHROMIUM_LOG(ERROR) << "Unable to transfer right in TransferMachPorts. " 1014 << mach_error_string(kr); 1015 return mozilla::Nothing(); 1016 } 1017 1018 destroyEndpoint.release(); 1019 return mozilla::Some(endpoint); 1020 } 1021 1022 // Process footer information attached to the message, and acquire owning 1023 // references to any transferred mach ports. See comment above for details. 1024 bool ChannelPosix::AcceptMachPorts(Message& msg) { 1025 chan_cap_.NoteOnTarget(); 1026 1027 uint32_t num_send_rights = msg.header()->num_send_rights; 1028 if (num_send_rights == 0) { 1029 return true; 1030 } 1031 1032 // Read in the payload from the footer, truncating the message. 1033 nsTArray<uint32_t> payload; 1034 payload.AppendElements(num_send_rights); 1035 if (!msg.ReadFooter(payload.Elements(), num_send_rights * sizeof(uint32_t), 1036 /* truncate */ true)) { 1037 CHROMIUM_LOG(ERROR) << "failed to read mach port payload from message"; 1038 return false; 1039 } 1040 msg.header()->num_send_rights = 0; 1041 1042 // Read in the handles themselves, transferring ownership as required. 1043 nsTArray<mozilla::UniqueMachSendRight> rights(num_send_rights); 1044 for (uint32_t name : payload) { 1045 mozilla::UniqueMachSendRight right; 1046 switch (mode_) { 1047 case MODE_BROKER_SERVER: 1048 if (!other_task_) { 1049 CHROMIUM_LOG(ERROR) << "other_task_ is invalid in AcceptMachPorts"; 1050 return false; 1051 } 1052 right = BrokerExtractSendRight(other_task_.get(), name); 1053 break; 1054 case MODE_BROKER_CLIENT: { 1055 kern_return_t kr = MachReceivePortSendRight( 1056 mozilla::UniqueMachReceiveRight(name), mozilla::Some(0), &right); 1057 if (kr != KERN_SUCCESS) { 1058 CHROMIUM_LOG(ERROR) 1059 << "failed to receive mach send right. " << mach_error_string(kr); 1060 return false; 1061 } 1062 break; 1063 } 1064 default: 1065 CHROMIUM_LOG(ERROR) 1066 << "invalid message: " << msg.name() 1067 << ". channel is not configured to accept mach ports"; 1068 return false; 1069 } 1070 if (!right) { 1071 return false; 1072 } 1073 rights.AppendElement(std::move(right)); 1074 } 1075 1076 // We're done with the handle footer, truncate the message at that point. 1077 msg.attached_send_rights_ = std::move(rights); 1078 MOZ_ASSERT(msg.num_send_rights() == num_send_rights); 1079 return true; 1080 } 1081 1082 // Transfer ownership of any attached mach ports to the peer task, and add the 1083 // required information for AcceptMachPorts to the message footer. See comment 1084 // above for details. 1085 bool ChannelPosix::TransferMachPorts(Message& msg) { 1086 uint32_t num_receive_rights = msg.num_receive_rights(); 1087 if (num_receive_rights != 0) { 1088 CHROMIUM_LOG(ERROR) << "ChannelPosix does not support receive rights"; 1089 return false; 1090 } 1091 1092 uint32_t num_send_rights = msg.num_send_rights(); 1093 if (num_send_rights == 0) { 1094 return true; 1095 } 1096 1097 # ifdef DEBUG 1098 uint32_t rights_offset = msg.header()->payload_size; 1099 # endif 1100 1101 nsTArray<uint32_t> payload(num_send_rights); 1102 for (auto& port_to_send : msg.attached_send_rights_) { 1103 switch (mode_) { 1104 case MODE_BROKER_SERVER: { 1105 if (!other_task_) { 1106 CHROMIUM_LOG(ERROR) << "other_task_ is invalid in TransferMachPorts"; 1107 return false; 1108 } 1109 mozilla::Maybe<mach_port_name_t> endpoint = 1110 BrokerTransferSendRight(other_task_.get(), std::move(port_to_send)); 1111 if (!endpoint) { 1112 return false; 1113 } 1114 payload.AppendElement(*endpoint); 1115 break; 1116 } 1117 case MODE_BROKER_CLIENT: 1118 payload.AppendElement(port_to_send.release()); 1119 break; 1120 default: 1121 CHROMIUM_LOG(ERROR) 1122 << "cannot send message: " << msg.name() 1123 << ". channel is not configured to accept mach ports"; 1124 return false; 1125 } 1126 } 1127 msg.attached_send_rights_.Clear(); 1128 1129 msg.WriteFooter(payload.Elements(), payload.Length() * sizeof(uint32_t)); 1130 msg.header()->num_send_rights = num_send_rights; 1131 1132 MOZ_ASSERT(msg.header()->payload_size == 1133 rights_offset + (sizeof(uint32_t) * num_send_rights), 1134 "Unexpected number of bytes written for send rights footer?"); 1135 return true; 1136 } 1137 #endif 1138 1139 // static 1140 bool ChannelPosix::CreateRawPipe(ChannelHandle* server, ChannelHandle* client) { 1141 int fds[2]; 1142 if (socketpair(AF_UNIX, SOCK_STREAM, 0, fds) < 0) { 1143 mozilla::ipc::AnnotateCrashReportWithErrno( 1144 CrashReporter::Annotation::IpcCreatePipeSocketPairErrno, errno); 1145 return false; 1146 } 1147 1148 auto configureFd = [](int fd) -> bool { 1149 // Mark the endpoints as non-blocking 1150 if (fcntl(fd, F_SETFL, O_NONBLOCK) == -1) { 1151 mozilla::ipc::AnnotateCrashReportWithErrno( 1152 CrashReporter::Annotation::IpcCreatePipeFcntlErrno, errno); 1153 return false; 1154 } 1155 1156 // Mark the pipes as FD_CLOEXEC 1157 int flags = fcntl(fd, F_GETFD); 1158 if (flags == -1) { 1159 mozilla::ipc::AnnotateCrashReportWithErrno( 1160 CrashReporter::Annotation::IpcCreatePipeCloExecErrno, errno); 1161 return false; 1162 } 1163 flags |= FD_CLOEXEC; 1164 if (fcntl(fd, F_SETFD, flags) == -1) { 1165 mozilla::ipc::AnnotateCrashReportWithErrno( 1166 CrashReporter::Annotation::IpcCreatePipeCloExecErrno, errno); 1167 return false; 1168 } 1169 return true; 1170 }; 1171 1172 if (!configureFd(fds[0]) || !configureFd(fds[1])) { 1173 IGNORE_EINTR(close(fds[0])); 1174 IGNORE_EINTR(close(fds[1])); 1175 return false; 1176 } 1177 1178 server->emplace<mozilla::UniqueFileHandle>(fds[0]); 1179 client->emplace<mozilla::UniqueFileHandle>(fds[1]); 1180 return true; 1181 } 1182 1183 // static 1184 uint32_t ChannelPosix::NumRelayedAttachments(const Message& message) { 1185 #ifdef XP_DARWIN 1186 return message.num_send_rights(); 1187 #else 1188 return 0; 1189 #endif 1190 } 1191 1192 // static 1193 bool ChannelPosix::IsValidHandle(const ChannelHandle& handle) { 1194 const auto* fileHandle = std::get_if<mozilla::UniqueFileHandle>(&handle); 1195 return fileHandle && *fileHandle; 1196 } 1197 1198 } // namespace IPC