1 // Copyright 2016 The Chromium Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #include "mojo/edk/system/channel.h" 6 7 #include <string.h> 8 9 #include <algorithm> 10 #include <limits> 11 #include <utility> 12 13 #include "base/macros.h" 14 #include "base/memory/aligned_memory.h" 15 #include "base/process/process_handle.h" 16 #include "mojo/edk/embedder/platform_handle.h" 17 18 #if defined(OS_MACOSX) && !defined(OS_IOS) 19 #include "base/mac/mach_logging.h" 20 #elif defined(OS_WIN) 21 #include "base/win/win_util.h" 22 #endif 23 24 namespace mojo { 25 namespace edk { 26 27 namespace { 28 29 static_assert(sizeof(Channel::Message::Header) % kChannelMessageAlignment == 0, 30 "Invalid Header size."); 31 32 #if defined(MOJO_EDK_LEGACY_PROTOCOL) 33 static_assert(sizeof(Channel::Message::Header) == 8, 34 "Header must be 8 bytes on ChromeOS and Android"); 35 #endif 36 37 } // namespace 38 39 const size_t kReadBufferSize = 4096; 40 const size_t kMaxUnusedReadBufferCapacity = 64 * 1024; 41 const size_t kMaxChannelMessageSize = 256 * 1024 * 1024; 42 const size_t kMaxAttachedHandles = 128; 43 44 Channel::Message::Message(size_t payload_size, 45 size_t max_handles, 46 Header::MessageType message_type) 47 : max_handles_(max_handles) { 48 DCHECK_LE(max_handles_, kMaxAttachedHandles); 49 50 size_t extra_header_size = 0; 51 #if defined(OS_WIN) 52 // On Windows we serialize HANDLEs into the extra header space. 53 extra_header_size = max_handles_ * sizeof(HandleEntry); 54 #elif defined(OS_MACOSX) && !defined(OS_IOS) 55 // On OSX, some of the platform handles may be mach ports, which are 56 // serialised into the message buffer. Since there could be a mix of fds and 57 // mach ports, we store the mach ports as an <index, port> pair (of uint32_t), 58 // so that the original ordering of handles can be re-created. 59 if (max_handles) { 60 extra_header_size = 61 sizeof(MachPortsExtraHeader) + (max_handles * sizeof(MachPortsEntry)); 62 } 63 #endif 64 // Pad extra header data to be aliged to |kChannelMessageAlignment| bytes. 65 if (extra_header_size % kChannelMessageAlignment) { 66 extra_header_size += kChannelMessageAlignment - 67 (extra_header_size % kChannelMessageAlignment); 68 } 69 DCHECK_EQ(0u, extra_header_size % kChannelMessageAlignment); 70 #if defined(MOJO_EDK_LEGACY_PROTOCOL) 71 DCHECK_EQ(0u, extra_header_size); 72 #endif 73 74 size_ = sizeof(Header) + extra_header_size + payload_size; 75 data_ = static_cast<char*>(base::AlignedAlloc(size_, 76 kChannelMessageAlignment)); 77 // Only zero out the header and not the payload. Since the payload is going to 78 // be memcpy'd, zeroing the payload is unnecessary work and a significant 79 // performance issue when dealing with large messages. Any sanitizer errors 80 // complaining about an uninitialized read in the payload area should be 81 // treated as an error and fixed. 82 memset(data_, 0, sizeof(Header) + extra_header_size); 83 header_ = reinterpret_cast<Header*>(data_); 84 85 DCHECK_LE(size_, std::numeric_limits<uint32_t>::max()); 86 header_->num_bytes = static_cast<uint32_t>(size_); 87 88 DCHECK_LE(sizeof(Header) + extra_header_size, 89 std::numeric_limits<uint16_t>::max()); 90 header_->message_type = message_type; 91 #if defined(MOJO_EDK_LEGACY_PROTOCOL) 92 header_->num_handles = static_cast<uint16_t>(max_handles); 93 #else 94 header_->num_header_bytes = 95 static_cast<uint16_t>(sizeof(Header) + extra_header_size); 96 #endif 97 98 if (max_handles_ > 0) { 99 #if defined(OS_WIN) 100 handles_ = reinterpret_cast<HandleEntry*>(mutable_extra_header()); 101 // Initialize all handles to invalid values. 102 for (size_t i = 0; i < max_handles_; ++i) 103 handles_[i].handle = base::win::HandleToUint32(INVALID_HANDLE_VALUE); 104 #elif defined(OS_MACOSX) && !defined(OS_IOS) 105 mach_ports_header_ = 106 reinterpret_cast<MachPortsExtraHeader*>(mutable_extra_header()); 107 mach_ports_header_->num_ports = 0; 108 // Initialize all handles to invalid values. 109 for (size_t i = 0; i < max_handles_; ++i) { 110 mach_ports_header_->entries[i] = 111 {0, static_cast<uint32_t>(MACH_PORT_NULL)}; 112 } 113 #endif 114 } 115 } 116 117 Channel::Message::~Message() { 118 base::AlignedFree(data_); 119 } 120 121 // static 122 Channel::MessagePtr Channel::Message::Deserialize(const void* data, 123 size_t data_num_bytes) { 124 if (data_num_bytes < sizeof(Header)) 125 return nullptr; 126 127 const Header* header = reinterpret_cast<const Header*>(data); 128 if (header->num_bytes != data_num_bytes) { 129 DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes 130 << " != " << data_num_bytes; 131 return nullptr; 132 } 133 134 #if defined(MOJO_EDK_LEGACY_PROTOCOL) 135 size_t payload_size = data_num_bytes - sizeof(Header); 136 const char* payload = static_cast<const char*>(data) + sizeof(Header); 137 #else 138 if (header->num_bytes < header->num_header_bytes || 139 header->num_header_bytes < sizeof(Header)) { 140 DLOG(ERROR) << "Decoding invalid message: " << header->num_bytes << " < " 141 << header->num_header_bytes; 142 return nullptr; 143 } 144 145 uint32_t extra_header_size = header->num_header_bytes - sizeof(Header); 146 size_t payload_size = data_num_bytes - header->num_header_bytes; 147 const char* payload = 148 static_cast<const char*>(data) + header->num_header_bytes; 149 #endif // defined(MOJO_EDK_LEGACY_PROTOCOL) 150 151 #if defined(OS_WIN) 152 uint32_t max_handles = extra_header_size / sizeof(HandleEntry); 153 #elif defined(OS_MACOSX) && !defined(OS_IOS) 154 if (extra_header_size < sizeof(MachPortsExtraHeader)) { 155 DLOG(ERROR) << "Decoding invalid message: " << extra_header_size << " < " 156 << sizeof(MachPortsExtraHeader); 157 return nullptr; 158 } 159 uint32_t max_handles = (extra_header_size - sizeof(MachPortsExtraHeader)) / 160 sizeof(MachPortsEntry); 161 #else 162 const uint32_t max_handles = 0; 163 #endif // defined(OS_WIN) 164 165 if (header->num_handles > max_handles || max_handles > kMaxAttachedHandles) { 166 DLOG(ERROR) << "Decoding invalid message:" << header->num_handles 167 << " > " << max_handles; 168 return nullptr; 169 } 170 171 MessagePtr message(new Message(payload_size, max_handles)); 172 DCHECK_EQ(message->data_num_bytes(), data_num_bytes); 173 174 // Copy all payload bytes. 175 if (payload_size) 176 memcpy(message->mutable_payload(), payload, payload_size); 177 178 #if !defined(MOJO_EDK_LEGACY_PROTOCOL) 179 DCHECK_EQ(message->extra_header_size(), extra_header_size); 180 DCHECK_EQ(message->header_->num_header_bytes, header->num_header_bytes); 181 182 if (message->extra_header_size()) { 183 // Copy extra header bytes. 184 memcpy(message->mutable_extra_header(), 185 static_cast<const char*>(data) + sizeof(Header), 186 message->extra_header_size()); 187 } 188 #endif 189 190 message->header_->num_handles = header->num_handles; 191 #if defined(OS_WIN) 192 ScopedPlatformHandleVectorPtr handles( 193 new PlatformHandleVector(header->num_handles)); 194 for (size_t i = 0; i < header->num_handles; i++) { 195 (*handles)[i].handle = reinterpret_cast<HANDLE>( 196 static_cast<uintptr_t>(message->handles_[i].handle)); 197 } 198 message->SetHandles(std::move(handles)); 199 #endif 200 201 return message; 202 } 203 204 size_t Channel::Message::payload_size() const { 205 #if defined(MOJO_EDK_LEGACY_PROTOCOL) 206 return header_->num_bytes - sizeof(Header); 207 #else 208 return size_ - header_->num_header_bytes; 209 #endif 210 } 211 212 #if defined(OS_MACOSX) && !defined(OS_IOS) 213 bool Channel::Message::has_mach_ports() const { 214 if (!has_handles()) 215 return false; 216 217 for (const auto& handle : (*handle_vector_)) { 218 if (handle.type == PlatformHandle::Type::MACH || 219 handle.type == PlatformHandle::Type::MACH_NAME) { 220 return true; 221 } 222 } 223 return false; 224 } 225 #endif 226 227 void Channel::Message::SetHandles(ScopedPlatformHandleVectorPtr new_handles) { 228 #if defined(MOJO_EDK_LEGACY_PROTOCOL) 229 // Old semantics for ChromeOS and Android 230 if (header_->num_handles == 0) { 231 CHECK(!new_handles || new_handles->size() == 0); 232 return; 233 } 234 CHECK(new_handles && new_handles->size() == header_->num_handles); 235 std::swap(handle_vector_, new_handles); 236 237 #else 238 if (max_handles_ == 0) { 239 CHECK(!new_handles || new_handles->size() == 0); 240 return; 241 } 242 243 CHECK(new_handles && new_handles->size() <= max_handles_); 244 header_->num_handles = static_cast<uint16_t>(new_handles->size()); 245 std::swap(handle_vector_, new_handles); 246 #if defined(OS_WIN) 247 memset(handles_, 0, extra_header_size()); 248 for (size_t i = 0; i < handle_vector_->size(); i++) 249 handles_[i].handle = base::win::HandleToUint32((*handle_vector_)[i].handle); 250 #endif // defined(OS_WIN) 251 #endif // defined(MOJO_EDK_LEGACY_PROTOCOL) 252 253 #if defined(OS_MACOSX) && !defined(OS_IOS) 254 size_t mach_port_index = 0; 255 if (mach_ports_header_) { 256 for (size_t i = 0; i < max_handles_; ++i) { 257 mach_ports_header_->entries[i] = 258 {0, static_cast<uint32_t>(MACH_PORT_NULL)}; 259 } 260 for (size_t i = 0; i < handle_vector_->size(); i++) { 261 if ((*handle_vector_)[i].type == PlatformHandle::Type::MACH || 262 (*handle_vector_)[i].type == PlatformHandle::Type::MACH_NAME) { 263 mach_port_t port = (*handle_vector_)[i].port; 264 mach_ports_header_->entries[mach_port_index].index = i; 265 mach_ports_header_->entries[mach_port_index].mach_port = port; 266 mach_port_index++; 267 } 268 } 269 mach_ports_header_->num_ports = static_cast<uint16_t>(mach_port_index); 270 } 271 #endif 272 } 273 274 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandles() { 275 #if defined(OS_MACOSX) && !defined(OS_IOS) 276 if (mach_ports_header_) { 277 for (size_t i = 0; i < max_handles_; ++i) { 278 mach_ports_header_->entries[i] = 279 {0, static_cast<uint32_t>(MACH_PORT_NULL)}; 280 } 281 mach_ports_header_->num_ports = 0; 282 } 283 header_->num_handles = 0; 284 return std::move(handle_vector_); 285 #else 286 header_->num_handles = 0; 287 return std::move(handle_vector_); 288 #endif 289 } 290 291 ScopedPlatformHandleVectorPtr Channel::Message::TakeHandlesForTransport() { 292 #if defined(OS_WIN) 293 // Not necessary on Windows. 294 NOTREACHED(); 295 return nullptr; 296 #elif defined(OS_MACOSX) && !defined(OS_IOS) 297 if (handle_vector_) { 298 for (auto it = handle_vector_->begin(); it != handle_vector_->end(); ) { 299 if (it->type == PlatformHandle::Type::MACH || 300 it->type == PlatformHandle::Type::MACH_NAME) { 301 // For Mach port names, we can can just leak them. They're not real 302 // ports anyways. For real ports, they're leaked because this is a child 303 // process and the remote process will take ownership. 304 it = handle_vector_->erase(it); 305 } else { 306 ++it; 307 } 308 } 309 } 310 return std::move(handle_vector_); 311 #else 312 return std::move(handle_vector_); 313 #endif 314 } 315 316 #if defined(OS_WIN) 317 // static 318 bool Channel::Message::RewriteHandles(base::ProcessHandle from_process, 319 base::ProcessHandle to_process, 320 PlatformHandleVector* handles) { 321 bool success = true; 322 for (size_t i = 0; i < handles->size(); ++i) { 323 if (!(*handles)[i].is_valid()) { 324 DLOG(ERROR) << "Refusing to duplicate invalid handle."; 325 continue; 326 } 327 DCHECK_EQ((*handles)[i].owning_process, from_process); 328 BOOL result = DuplicateHandle( 329 from_process, (*handles)[i].handle, to_process, 330 &(*handles)[i].handle, 0, FALSE, 331 DUPLICATE_SAME_ACCESS | DUPLICATE_CLOSE_SOURCE); 332 if (result) { 333 (*handles)[i].owning_process = to_process; 334 } else { 335 success = false; 336 337 // If handle duplication fails, the source handle will already be closed 338 // due to DUPLICATE_CLOSE_SOURCE. Replace the handle in the message with 339 // an invalid handle. 340 (*handles)[i].handle = INVALID_HANDLE_VALUE; 341 (*handles)[i].owning_process = base::GetCurrentProcessHandle(); 342 } 343 } 344 return success; 345 } 346 #endif 347 348 // Helper class for managing a Channel's read buffer allocations. This maintains 349 // a single contiguous buffer with the layout: 350 // 351 // [discarded bytes][occupied bytes][unoccupied bytes] 352 // 353 // The Reserve() method ensures that a certain capacity of unoccupied bytes are 354 // available. It does not claim that capacity and only allocates new capacity 355 // when strictly necessary. 356 // 357 // Claim() marks unoccupied bytes as occupied. 358 // 359 // Discard() marks occupied bytes as discarded, signifying that their contents 360 // can be forgotten or overwritten. 361 // 362 // Realign() moves occupied bytes to the front of the buffer so that those 363 // occupied bytes are properly aligned. 364 // 365 // The most common Channel behavior in practice should result in very few 366 // allocations and copies, as memory is claimed and discarded shortly after 367 // being reserved, and future reservations will immediately reuse discarded 368 // memory. 369 class Channel::ReadBuffer { 370 public: 371 ReadBuffer() { 372 size_ = kReadBufferSize; 373 data_ = static_cast<char*>(base::AlignedAlloc(size_, 374 kChannelMessageAlignment)); 375 } 376 377 ~ReadBuffer() { 378 DCHECK(data_); 379 base::AlignedFree(data_); 380 } 381 382 const char* occupied_bytes() const { return data_ + num_discarded_bytes_; } 383 384 size_t num_occupied_bytes() const { 385 return num_occupied_bytes_ - num_discarded_bytes_; 386 } 387 388 // Ensures the ReadBuffer has enough contiguous space allocated to hold 389 // |num_bytes| more bytes; returns the address of the first available byte. 390 char* Reserve(size_t num_bytes) { 391 if (num_occupied_bytes_ + num_bytes > size_) { 392 size_ = std::max(size_ * 2, num_occupied_bytes_ + num_bytes); 393 void* new_data = base::AlignedAlloc(size_, kChannelMessageAlignment); 394 memcpy(new_data, data_, num_occupied_bytes_); 395 base::AlignedFree(data_); 396 data_ = static_cast<char*>(new_data); 397 } 398 399 return data_ + num_occupied_bytes_; 400 } 401 402 // Marks the first |num_bytes| unoccupied bytes as occupied. 403 void Claim(size_t num_bytes) { 404 DCHECK_LE(num_occupied_bytes_ + num_bytes, size_); 405 num_occupied_bytes_ += num_bytes; 406 } 407 408 // Marks the first |num_bytes| occupied bytes as discarded. This may result in 409 // shrinkage of the internal buffer, and it is not safe to assume the result 410 // of a previous Reserve() call is still valid after this. 411 void Discard(size_t num_bytes) { 412 DCHECK_LE(num_discarded_bytes_ + num_bytes, num_occupied_bytes_); 413 num_discarded_bytes_ += num_bytes; 414 415 if (num_discarded_bytes_ == num_occupied_bytes_) { 416 // We can just reuse the buffer from the beginning in this common case. 417 num_discarded_bytes_ = 0; 418 num_occupied_bytes_ = 0; 419 } 420 421 if (num_discarded_bytes_ > kMaxUnusedReadBufferCapacity) { 422 // In the uncommon case that we have a lot of discarded data at the 423 // front of the buffer, simply move remaining data to a smaller buffer. 424 size_t num_preserved_bytes = num_occupied_bytes_ - num_discarded_bytes_; 425 size_ = std::max(num_preserved_bytes, kReadBufferSize); 426 char* new_data = static_cast<char*>( 427 base::AlignedAlloc(size_, kChannelMessageAlignment)); 428 memcpy(new_data, data_ + num_discarded_bytes_, num_preserved_bytes); 429 base::AlignedFree(data_); 430 data_ = new_data; 431 num_discarded_bytes_ = 0; 432 num_occupied_bytes_ = num_preserved_bytes; 433 } 434 435 if (num_occupied_bytes_ == 0 && size_ > kMaxUnusedReadBufferCapacity) { 436 // Opportunistically shrink the read buffer back down to a small size if 437 // it's grown very large. We only do this if there are no remaining 438 // unconsumed bytes in the buffer to avoid copies in most the common 439 // cases. 440 size_ = kMaxUnusedReadBufferCapacity; 441 base::AlignedFree(data_); 442 data_ = static_cast<char*>( 443 base::AlignedAlloc(size_, kChannelMessageAlignment)); 444 } 445 } 446 447 void Realign() { 448 size_t num_bytes = num_occupied_bytes(); 449 memmove(data_, occupied_bytes(), num_bytes); 450 num_discarded_bytes_ = 0; 451 num_occupied_bytes_ = num_bytes; 452 } 453 454 private: 455 char* data_ = nullptr; 456 457 // The total size of the allocated buffer. 458 size_t size_ = 0; 459 460 // The number of discarded bytes at the beginning of the allocated buffer. 461 size_t num_discarded_bytes_ = 0; 462 463 // The total number of occupied bytes, including discarded bytes. 464 size_t num_occupied_bytes_ = 0; 465 466 DISALLOW_COPY_AND_ASSIGN(ReadBuffer); 467 }; 468 469 Channel::Channel(Delegate* delegate) 470 : delegate_(delegate), read_buffer_(new ReadBuffer) { 471 } 472 473 Channel::~Channel() { 474 } 475 476 void Channel::ShutDown() { 477 delegate_ = nullptr; 478 ShutDownImpl(); 479 } 480 481 char* Channel::GetReadBuffer(size_t *buffer_capacity) { 482 DCHECK(read_buffer_); 483 size_t required_capacity = *buffer_capacity; 484 if (!required_capacity) 485 required_capacity = kReadBufferSize; 486 487 *buffer_capacity = required_capacity; 488 return read_buffer_->Reserve(required_capacity); 489 } 490 491 bool Channel::OnReadComplete(size_t bytes_read, size_t *next_read_size_hint) { 492 bool did_dispatch_message = false; 493 read_buffer_->Claim(bytes_read); 494 while (read_buffer_->num_occupied_bytes() >= sizeof(Message::Header)) { 495 // Ensure the occupied data is properly aligned. If it isn't, a SIGBUS could 496 // happen on architectures that don't allow misaligned words access (i.e. 497 // anything other than x86). Only re-align when necessary to avoid copies. 498 if (reinterpret_cast<uintptr_t>(read_buffer_->occupied_bytes()) % 499 kChannelMessageAlignment != 0) 500 read_buffer_->Realign(); 501 502 // We have at least enough data available for a MessageHeader. 503 const Message::Header* header = reinterpret_cast<const Message::Header*>( 504 read_buffer_->occupied_bytes()); 505 if (header->num_bytes < sizeof(Message::Header) || 506 header->num_bytes > kMaxChannelMessageSize) { 507 LOG(ERROR) << "Invalid message size: " << header->num_bytes; 508 return false; 509 } 510 511 if (read_buffer_->num_occupied_bytes() < header->num_bytes) { 512 // Not enough data available to read the full message. Hint to the 513 // implementation that it should try reading the full size of the message. 514 *next_read_size_hint = 515 header->num_bytes - read_buffer_->num_occupied_bytes(); 516 return true; 517 } 518 519 #if defined(MOJO_EDK_LEGACY_PROTOCOL) 520 size_t extra_header_size = 0; 521 const void* extra_header = nullptr; 522 size_t payload_size = header->num_bytes - sizeof(Message::Header); 523 void* payload = payload_size ? const_cast<Message::Header*>(&header[1]) 524 : nullptr; 525 #else 526 if (header->num_header_bytes < sizeof(Message::Header) || 527 header->num_header_bytes > header->num_bytes) { 528 LOG(ERROR) << "Invalid message header size: " << header->num_header_bytes; 529 return false; 530 } 531 size_t extra_header_size = 532 header->num_header_bytes - sizeof(Message::Header); 533 const void* extra_header = extra_header_size ? header + 1 : nullptr; 534 size_t payload_size = header->num_bytes - header->num_header_bytes; 535 void* payload = 536 payload_size ? reinterpret_cast<Message::Header*>( 537 const_cast<char*>(read_buffer_->occupied_bytes()) + 538 header->num_header_bytes) 539 : nullptr; 540 #endif // defined(MOJO_EDK_LEGACY_PROTOCOL) 541 542 ScopedPlatformHandleVectorPtr handles; 543 if (header->num_handles > 0) { 544 if (!GetReadPlatformHandles(header->num_handles, extra_header, 545 extra_header_size, &handles)) { 546 return false; 547 } 548 549 if (!handles) { 550 // Not enough handles available for this message. 551 break; 552 } 553 } 554 555 // We've got a complete message! Dispatch it and try another. 556 if (header->message_type != Message::Header::MessageType::NORMAL) { 557 if (!OnControlMessage(header->message_type, payload, payload_size, 558 std::move(handles))) { 559 return false; 560 } 561 did_dispatch_message = true; 562 } else if (delegate_) { 563 delegate_->OnChannelMessage(payload, payload_size, std::move(handles)); 564 did_dispatch_message = true; 565 } 566 567 read_buffer_->Discard(header->num_bytes); 568 } 569 570 *next_read_size_hint = did_dispatch_message ? 0 : kReadBufferSize; 571 return true; 572 } 573 574 void Channel::OnError() { 575 if (delegate_) 576 delegate_->OnChannelError(); 577 } 578 579 bool Channel::OnControlMessage(Message::Header::MessageType message_type, 580 const void* payload, 581 size_t payload_size, 582 ScopedPlatformHandleVectorPtr handles) { 583 return false; 584 } 585 586 } // namespace edk 587 } // namespace mojo 588