1 // Copyright 2013 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/core/core.h" 6 7 #include <string.h> 8 9 #include <algorithm> 10 #include <utility> 11 12 #include "base/bind.h" 13 #include "base/containers/stack_container.h" 14 #include "base/location.h" 15 #include "base/logging.h" 16 #include "base/macros.h" 17 #include "base/memory/ptr_util.h" 18 #include "base/memory/writable_shared_memory_region.h" 19 #include "base/rand_util.h" 20 #include "base/strings/string_number_conversions.h" 21 #include "base/strings/string_piece.h" 22 #include "base/threading/thread_task_runner_handle.h" 23 #include "base/time/time.h" 24 // #include "base/trace_event/memory_dump_manager.h" 25 #include "build/build_config.h" 26 #include "mojo/core/channel.h" 27 #include "mojo/core/configuration.h" 28 #include "mojo/core/data_pipe_consumer_dispatcher.h" 29 #include "mojo/core/data_pipe_producer_dispatcher.h" 30 #include "mojo/core/embedder/process_error_callback.h" 31 #include "mojo/core/handle_signals_state.h" 32 #include "mojo/core/invitation_dispatcher.h" 33 #include "mojo/core/message_pipe_dispatcher.h" 34 #include "mojo/core/platform_handle_dispatcher.h" 35 #include "mojo/core/platform_handle_utils.h" 36 #include "mojo/core/platform_shared_memory_mapping.h" 37 #include "mojo/core/ports/event.h" 38 #include "mojo/core/ports/name.h" 39 #include "mojo/core/ports/node.h" 40 #include "mojo/core/request_context.h" 41 #include "mojo/core/shared_buffer_dispatcher.h" 42 #include "mojo/core/user_message_impl.h" 43 #include "mojo/core/watcher_dispatcher.h" 44 45 namespace mojo { 46 namespace core { 47 48 namespace { 49 50 // This is an unnecessarily large limit that is relatively easy to enforce. 51 const uint32_t kMaxHandlesPerMessage = 1024 * 1024; 52 53 // TODO(rockot): Maybe we could negotiate a debugging pipe ID for cross-process 54 // pipes too; for now we just use a constant. This only affects bootstrap pipes. 55 const uint64_t kUnknownPipeIdForDebug = 0x7f7f7f7f7f7f7f7fUL; 56 57 // The pipe name which must be used for the sole pipe attachment on any isolated 58 // invitation. 59 constexpr base::StringPiece kIsolatedInvitationPipeName = {"\0\0\0\0", 4}; 60 61 void InvokeProcessErrorCallbackOnTaskRunner( 62 scoped_refptr<base::TaskRunner> task_runner, 63 MojoProcessErrorHandler handler, 64 uintptr_t context, 65 const std::string& error, 66 MojoProcessErrorFlags flags) { 67 // We always run the handler asynchronously to ensure no Mojo core reentrancy. 68 task_runner->PostTask( 69 FROM_HERE, 70 base::BindOnce( 71 [](MojoProcessErrorHandler handler, uintptr_t context, 72 const std::string& error, MojoProcessErrorFlags flags) { 73 MojoProcessErrorDetails details; 74 details.struct_size = sizeof(details); 75 DCHECK(base::IsValueInRangeForNumericType<uint32_t>(error.size())); 76 details.error_message_length = static_cast<uint32_t>(error.size()); 77 if (!error.empty()) 78 details.error_message = error.data(); 79 else 80 details.error_message = nullptr; 81 details.flags = flags; 82 handler(context, &details); 83 }, 84 handler, context, error, flags)); 85 } 86 87 // Helper class which is bound to the lifetime of a 88 // ProcessErrorCallback generated by the |MojoSendInvitation()| 89 // API. When the last reference to the error callback is lost within the EDK, 90 // which will happen shortly after a connection to the process is lost, that 91 // obviously guarantees that no more invocations of the callback will occur. At 92 // that point, the corresponding instance of this object (owned by the callback 93 // -- see Core::SendInvitation) will be destroyed. 94 class ProcessDisconnectHandler { 95 public: 96 ProcessDisconnectHandler(scoped_refptr<base::TaskRunner> task_runner, 97 MojoProcessErrorHandler handler, 98 uintptr_t context) 99 : task_runner_(std::move(task_runner)), 100 handler_(handler), 101 context_(context) {} 102 103 ~ProcessDisconnectHandler() { 104 InvokeProcessErrorCallbackOnTaskRunner( 105 task_runner_, handler_, context_, std::string(), 106 MOJO_PROCESS_ERROR_FLAG_DISCONNECTED); 107 } 108 109 private: 110 const scoped_refptr<base::TaskRunner> task_runner_; 111 const MojoProcessErrorHandler handler_; 112 const uintptr_t context_; 113 114 DISALLOW_COPY_AND_ASSIGN(ProcessDisconnectHandler); 115 }; 116 117 void RunMojoProcessErrorHandler(ProcessDisconnectHandler* disconnect_handler, 118 scoped_refptr<base::TaskRunner> task_runner, 119 MojoProcessErrorHandler handler, 120 uintptr_t context, 121 const std::string& error) { 122 InvokeProcessErrorCallbackOnTaskRunner(task_runner, handler, context, error, 123 MOJO_PROCESS_ERROR_FLAG_NONE); 124 } 125 126 } // namespace 127 128 Core::Core() { 129 handles_.reset(new HandleTable); 130 // base::trace_event::MemoryDumpManager::GetInstance()->RegisterDumpProvider( 131 // handles_.get(), "MojoHandleTable", nullptr); 132 } 133 134 Core::~Core() { 135 if (node_controller_ && node_controller_->io_task_runner()) { 136 // If this races with IO thread shutdown the callback will be dropped and 137 // the NodeController will be shutdown on this thread anyway, which is also 138 // just fine. 139 scoped_refptr<base::TaskRunner> io_task_runner = 140 node_controller_->io_task_runner(); 141 io_task_runner->PostTask(FROM_HERE, 142 base::BindOnce(&Core::PassNodeControllerToIOThread, 143 base::Passed(&node_controller_))); 144 } 145 // base::trace_event::MemoryDumpManager::GetInstance() 146 // ->UnregisterAndDeleteDumpProviderSoon(std::move(handles_)); 147 } 148 149 void Core::SetIOTaskRunner(scoped_refptr<base::TaskRunner> io_task_runner) { 150 GetNodeController()->SetIOTaskRunner(io_task_runner); 151 } 152 153 NodeController* Core::GetNodeController() { 154 base::AutoLock lock(node_controller_lock_); 155 if (!node_controller_) 156 node_controller_.reset(new NodeController(this)); 157 return node_controller_.get(); 158 } 159 160 scoped_refptr<Dispatcher> Core::GetDispatcher(MojoHandle handle) { 161 base::AutoLock lock(handles_->GetLock()); 162 return handles_->GetDispatcher(handle); 163 } 164 165 scoped_refptr<Dispatcher> Core::GetAndRemoveDispatcher(MojoHandle handle) { 166 scoped_refptr<Dispatcher> dispatcher; 167 base::AutoLock lock(handles_->GetLock()); 168 handles_->GetAndRemoveDispatcher(handle, &dispatcher); 169 return dispatcher; 170 } 171 172 void Core::SetDefaultProcessErrorCallback( 173 const ProcessErrorCallback& callback) { 174 default_process_error_callback_ = callback; 175 } 176 177 MojoHandle Core::CreatePartialMessagePipe(ports::PortRef* peer) { 178 RequestContext request_context; 179 ports::PortRef local_port; 180 GetNodeController()->node()->CreatePortPair(&local_port, peer); 181 return AddDispatcher(new MessagePipeDispatcher( 182 GetNodeController(), local_port, kUnknownPipeIdForDebug, 0)); 183 } 184 185 MojoHandle Core::CreatePartialMessagePipe(const ports::PortRef& port) { 186 RequestContext request_context; 187 return AddDispatcher(new MessagePipeDispatcher(GetNodeController(), port, 188 kUnknownPipeIdForDebug, 1)); 189 } 190 191 void Core::SendBrokerClientInvitation( 192 base::ProcessHandle target_process, 193 ConnectionParams connection_params, 194 const std::vector<std::pair<std::string, ports::PortRef>>& attached_ports, 195 const ProcessErrorCallback& process_error_callback) { 196 RequestContext request_context; 197 GetNodeController()->SendBrokerClientInvitation( 198 target_process, std::move(connection_params), attached_ports, 199 process_error_callback); 200 } 201 202 void Core::AcceptBrokerClientInvitation(ConnectionParams connection_params) { 203 RequestContext request_context; 204 GetNodeController()->AcceptBrokerClientInvitation( 205 std::move(connection_params)); 206 } 207 208 void Core::ConnectIsolated(ConnectionParams connection_params, 209 const ports::PortRef& port, 210 base::StringPiece connection_name) { 211 RequestContext request_context; 212 GetNodeController()->ConnectIsolated(std::move(connection_params), port, 213 connection_name); 214 } 215 216 void Core::SetMachPortProvider(base::PortProvider* port_provider) { 217 #if defined(OS_MACOSX) && !defined(OS_IOS) 218 GetNodeController()->CreateMachPortRelay(port_provider); 219 #endif 220 } 221 222 #if defined(OS_MACOSX) && !defined(OS_IOS) 223 MachPortRelay* Core::GetMachPortRelay() { 224 return GetNodeController()->GetMachPortRelay(); 225 } 226 #endif 227 228 MojoHandle Core::AddDispatcher(scoped_refptr<Dispatcher> dispatcher) { 229 base::AutoLock lock(handles_->GetLock()); 230 return handles_->AddDispatcher(dispatcher); 231 } 232 233 bool Core::AddDispatchersFromTransit( 234 const std::vector<Dispatcher::DispatcherInTransit>& dispatchers, 235 MojoHandle* handles) { 236 bool failed = false; 237 { 238 base::AutoLock lock(handles_->GetLock()); 239 if (!handles_->AddDispatchersFromTransit(dispatchers, handles)) 240 failed = true; 241 } 242 if (failed) { 243 for (auto d : dispatchers) { 244 if (d.dispatcher) 245 d.dispatcher->Close(); 246 } 247 return false; 248 } 249 return true; 250 } 251 252 MojoResult Core::AcquireDispatchersForTransit( 253 const MojoHandle* handles, 254 size_t num_handles, 255 std::vector<Dispatcher::DispatcherInTransit>* dispatchers) { 256 base::AutoLock lock(handles_->GetLock()); 257 MojoResult rv = handles_->BeginTransit(handles, num_handles, dispatchers); 258 if (rv != MOJO_RESULT_OK) 259 handles_->CancelTransit(*dispatchers); 260 return rv; 261 } 262 263 void Core::ReleaseDispatchersForTransit( 264 const std::vector<Dispatcher::DispatcherInTransit>& dispatchers, 265 bool in_transit) { 266 base::AutoLock lock(handles_->GetLock()); 267 if (in_transit) 268 handles_->CompleteTransitAndClose(dispatchers); 269 else 270 handles_->CancelTransit(dispatchers); 271 } 272 273 void Core::RequestShutdown(const base::Closure& callback) { 274 GetNodeController()->RequestShutdown(callback); 275 } 276 277 MojoHandle Core::ExtractMessagePipeFromInvitation(const std::string& name) { 278 RequestContext request_context; 279 ports::PortRef port0, port1; 280 GetNodeController()->node()->CreatePortPair(&port0, &port1); 281 MojoHandle handle = AddDispatcher(new MessagePipeDispatcher( 282 GetNodeController(), port0, kUnknownPipeIdForDebug, 1)); 283 GetNodeController()->MergePortIntoInviter(name, port1); 284 return handle; 285 } 286 287 MojoTimeTicks Core::GetTimeTicksNow() { 288 return base::TimeTicks::Now().ToInternalValue(); 289 } 290 291 MojoResult Core::Close(MojoHandle handle) { 292 RequestContext request_context; 293 scoped_refptr<Dispatcher> dispatcher; 294 { 295 base::AutoLock lock(handles_->GetLock()); 296 MojoResult rv = handles_->GetAndRemoveDispatcher(handle, &dispatcher); 297 if (rv != MOJO_RESULT_OK) 298 return rv; 299 } 300 dispatcher->Close(); 301 return MOJO_RESULT_OK; 302 } 303 304 MojoResult Core::QueryHandleSignalsState( 305 MojoHandle handle, 306 MojoHandleSignalsState* signals_state) { 307 RequestContext request_context; 308 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle); 309 if (!dispatcher || !signals_state) 310 return MOJO_RESULT_INVALID_ARGUMENT; 311 *signals_state = dispatcher->GetHandleSignalsState(); 312 return MOJO_RESULT_OK; 313 } 314 315 MojoResult Core::CreateTrap(MojoTrapEventHandler handler, 316 const MojoCreateTrapOptions* options, 317 MojoHandle* trap_handle) { 318 if (options && options->struct_size < sizeof(*options)) 319 return MOJO_RESULT_INVALID_ARGUMENT; 320 321 RequestContext request_context; 322 if (!trap_handle) 323 return MOJO_RESULT_INVALID_ARGUMENT; 324 *trap_handle = AddDispatcher(new WatcherDispatcher(handler)); 325 if (*trap_handle == MOJO_HANDLE_INVALID) 326 return MOJO_RESULT_RESOURCE_EXHAUSTED; 327 return MOJO_RESULT_OK; 328 } 329 330 MojoResult Core::AddTrigger(MojoHandle trap_handle, 331 MojoHandle handle, 332 MojoHandleSignals signals, 333 MojoTriggerCondition condition, 334 uintptr_t context, 335 const MojoAddTriggerOptions* options) { 336 if (options && options->struct_size < sizeof(*options)) 337 return MOJO_RESULT_INVALID_ARGUMENT; 338 339 RequestContext request_context; 340 scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle); 341 if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER) 342 return MOJO_RESULT_INVALID_ARGUMENT; 343 344 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(handle); 345 if (!dispatcher) 346 return MOJO_RESULT_INVALID_ARGUMENT; 347 348 return watcher->WatchDispatcher(std::move(dispatcher), signals, condition, 349 context); 350 } 351 352 MojoResult Core::RemoveTrigger(MojoHandle trap_handle, 353 uintptr_t context, 354 const MojoRemoveTriggerOptions* options) { 355 if (options && options->struct_size < sizeof(*options)) 356 return MOJO_RESULT_INVALID_ARGUMENT; 357 358 RequestContext request_context; 359 scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle); 360 if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER) 361 return MOJO_RESULT_INVALID_ARGUMENT; 362 return watcher->CancelWatch(context); 363 } 364 365 MojoResult Core::ArmTrap(MojoHandle trap_handle, 366 const MojoArmTrapOptions* options, 367 uint32_t* num_blocking_events, 368 MojoTrapEvent* blocking_events) { 369 if (options && options->struct_size < sizeof(*options)) 370 return MOJO_RESULT_INVALID_ARGUMENT; 371 372 RequestContext request_context; 373 scoped_refptr<Dispatcher> watcher = GetDispatcher(trap_handle); 374 if (!watcher || watcher->GetType() != Dispatcher::Type::WATCHER) 375 return MOJO_RESULT_INVALID_ARGUMENT; 376 return watcher->Arm(num_blocking_events, blocking_events); 377 } 378 379 MojoResult Core::CreateMessage(const MojoCreateMessageOptions* options, 380 MojoMessageHandle* message_handle) { 381 if (!message_handle) 382 return MOJO_RESULT_INVALID_ARGUMENT; 383 if (options && options->struct_size < sizeof(*options)) 384 return MOJO_RESULT_INVALID_ARGUMENT; 385 *message_handle = reinterpret_cast<MojoMessageHandle>( 386 UserMessageImpl::CreateEventForNewMessage().release()); 387 return MOJO_RESULT_OK; 388 } 389 390 MojoResult Core::DestroyMessage(MojoMessageHandle message_handle) { 391 if (!message_handle) 392 return MOJO_RESULT_INVALID_ARGUMENT; 393 394 RequestContext request_context; 395 delete reinterpret_cast<ports::UserMessageEvent*>(message_handle); 396 return MOJO_RESULT_OK; 397 } 398 399 MojoResult Core::SerializeMessage(MojoMessageHandle message_handle, 400 const MojoSerializeMessageOptions* options) { 401 if (!message_handle) 402 return MOJO_RESULT_INVALID_ARGUMENT; 403 if (options && options->struct_size < sizeof(*options)) 404 return MOJO_RESULT_INVALID_ARGUMENT; 405 RequestContext request_context; 406 return reinterpret_cast<ports::UserMessageEvent*>(message_handle) 407 ->GetMessage<UserMessageImpl>() 408 ->SerializeIfNecessary(); 409 } 410 411 MojoResult Core::AppendMessageData(MojoMessageHandle message_handle, 412 uint32_t additional_payload_size, 413 const MojoHandle* handles, 414 uint32_t num_handles, 415 const MojoAppendMessageDataOptions* options, 416 void** buffer, 417 uint32_t* buffer_size) { 418 if (!message_handle || (num_handles && !handles)) 419 return MOJO_RESULT_INVALID_ARGUMENT; 420 if (options && options->struct_size < sizeof(*options)) 421 return MOJO_RESULT_INVALID_ARGUMENT; 422 423 RequestContext request_context; 424 auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) 425 ->GetMessage<UserMessageImpl>(); 426 MojoResult rv = 427 message->AppendData(additional_payload_size, handles, num_handles); 428 if (rv != MOJO_RESULT_OK) 429 return rv; 430 431 if (options && (options->flags & MOJO_APPEND_MESSAGE_DATA_FLAG_COMMIT_SIZE)) { 432 RequestContext request_context; 433 message->CommitSize(); 434 } 435 436 if (buffer) 437 *buffer = message->user_payload(); 438 if (buffer_size) { 439 *buffer_size = 440 base::checked_cast<uint32_t>(message->user_payload_capacity()); 441 } 442 return MOJO_RESULT_OK; 443 } 444 445 MojoResult Core::GetMessageData(MojoMessageHandle message_handle, 446 const MojoGetMessageDataOptions* options, 447 void** buffer, 448 uint32_t* num_bytes, 449 MojoHandle* handles, 450 uint32_t* num_handles) { 451 if (!message_handle || (num_handles && *num_handles && !handles)) 452 return MOJO_RESULT_INVALID_ARGUMENT; 453 if (options && options->struct_size < sizeof(*options)) 454 return MOJO_RESULT_INVALID_ARGUMENT; 455 456 auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) 457 ->GetMessage<UserMessageImpl>(); 458 if (!message->IsSerialized() || !message->IsTransmittable()) 459 return MOJO_RESULT_FAILED_PRECONDITION; 460 461 if (num_bytes) { 462 base::CheckedNumeric<uint32_t> payload_size = message->user_payload_size(); 463 *num_bytes = payload_size.ValueOrDie(); 464 } 465 466 if (message->user_payload_size() > 0) { 467 if (!num_bytes || !buffer) 468 return MOJO_RESULT_RESOURCE_EXHAUSTED; 469 470 *buffer = message->user_payload(); 471 } else if (buffer) { 472 *buffer = nullptr; 473 } 474 475 if (options && (options->flags & MOJO_GET_MESSAGE_DATA_FLAG_IGNORE_HANDLES)) 476 return MOJO_RESULT_OK; 477 478 uint32_t max_num_handles = 0; 479 if (num_handles) { 480 max_num_handles = *num_handles; 481 *num_handles = static_cast<uint32_t>(message->num_handles()); 482 } 483 484 if (message->num_handles() > max_num_handles || 485 message->num_handles() > kMaxHandlesPerMessage) { 486 return MOJO_RESULT_RESOURCE_EXHAUSTED; 487 } 488 489 RequestContext request_context; 490 return message->ExtractSerializedHandles( 491 UserMessageImpl::ExtractBadHandlePolicy::kAbort, handles); 492 } 493 494 MojoResult Core::SetMessageContext( 495 MojoMessageHandle message_handle, 496 uintptr_t context, 497 MojoMessageContextSerializer serializer, 498 MojoMessageContextDestructor destructor, 499 const MojoSetMessageContextOptions* options) { 500 if (!message_handle) 501 return MOJO_RESULT_INVALID_ARGUMENT; 502 if (options && options->struct_size < sizeof(*options)) 503 return MOJO_RESULT_INVALID_ARGUMENT; 504 auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) 505 ->GetMessage<UserMessageImpl>(); 506 return message->SetContext(context, serializer, destructor); 507 } 508 509 MojoResult Core::GetMessageContext(MojoMessageHandle message_handle, 510 const MojoGetMessageContextOptions* options, 511 uintptr_t* context) { 512 if (!message_handle) 513 return MOJO_RESULT_INVALID_ARGUMENT; 514 if (options && options->struct_size < sizeof(*options)) 515 return MOJO_RESULT_INVALID_ARGUMENT; 516 517 auto* message = reinterpret_cast<ports::UserMessageEvent*>(message_handle) 518 ->GetMessage<UserMessageImpl>(); 519 if (!message->HasContext()) 520 return MOJO_RESULT_NOT_FOUND; 521 522 *context = message->context(); 523 return MOJO_RESULT_OK; 524 } 525 526 MojoResult Core::CreateMessagePipe(const MojoCreateMessagePipeOptions* options, 527 MojoHandle* message_pipe_handle0, 528 MojoHandle* message_pipe_handle1) { 529 RequestContext request_context; 530 ports::PortRef port0, port1; 531 GetNodeController()->node()->CreatePortPair(&port0, &port1); 532 533 DCHECK(message_pipe_handle0); 534 DCHECK(message_pipe_handle1); 535 536 uint64_t pipe_id = base::RandUint64(); 537 538 *message_pipe_handle0 = AddDispatcher( 539 new MessagePipeDispatcher(GetNodeController(), port0, pipe_id, 0)); 540 if (*message_pipe_handle0 == MOJO_HANDLE_INVALID) 541 return MOJO_RESULT_RESOURCE_EXHAUSTED; 542 543 *message_pipe_handle1 = AddDispatcher( 544 new MessagePipeDispatcher(GetNodeController(), port1, pipe_id, 1)); 545 if (*message_pipe_handle1 == MOJO_HANDLE_INVALID) { 546 scoped_refptr<Dispatcher> dispatcher0; 547 { 548 base::AutoLock lock(handles_->GetLock()); 549 handles_->GetAndRemoveDispatcher(*message_pipe_handle0, &dispatcher0); 550 } 551 dispatcher0->Close(); 552 return MOJO_RESULT_RESOURCE_EXHAUSTED; 553 } 554 555 return MOJO_RESULT_OK; 556 } 557 558 MojoResult Core::WriteMessage(MojoHandle message_pipe_handle, 559 MojoMessageHandle message_handle, 560 const MojoWriteMessageOptions* options) { 561 RequestContext request_context; 562 if (!message_handle) 563 return MOJO_RESULT_INVALID_ARGUMENT; 564 auto message_event = base::WrapUnique( 565 reinterpret_cast<ports::UserMessageEvent*>(message_handle)); 566 auto* message = message_event->GetMessage<UserMessageImpl>(); 567 if (!message || !message->IsTransmittable()) 568 return MOJO_RESULT_INVALID_ARGUMENT; 569 auto dispatcher = GetDispatcher(message_pipe_handle); 570 if (!dispatcher) 571 return MOJO_RESULT_INVALID_ARGUMENT; 572 return dispatcher->WriteMessage(std::move(message_event)); 573 } 574 575 MojoResult Core::ReadMessage(MojoHandle message_pipe_handle, 576 const MojoReadMessageOptions* options, 577 MojoMessageHandle* message_handle) { 578 RequestContext request_context; 579 auto dispatcher = GetDispatcher(message_pipe_handle); 580 if (!dispatcher || !message_handle) 581 return MOJO_RESULT_INVALID_ARGUMENT; 582 583 std::unique_ptr<ports::UserMessageEvent> message_event; 584 MojoResult rv = dispatcher->ReadMessage(&message_event); 585 if (rv != MOJO_RESULT_OK) 586 return rv; 587 588 *message_handle = 589 reinterpret_cast<MojoMessageHandle>(message_event.release()); 590 return MOJO_RESULT_OK; 591 } 592 593 MojoResult Core::FuseMessagePipes(MojoHandle handle0, 594 MojoHandle handle1, 595 const MojoFuseMessagePipesOptions* options) { 596 RequestContext request_context; 597 scoped_refptr<Dispatcher> dispatcher0; 598 scoped_refptr<Dispatcher> dispatcher1; 599 600 bool valid_handles = true; 601 { 602 base::AutoLock lock(handles_->GetLock()); 603 MojoResult result0 = 604 handles_->GetAndRemoveDispatcher(handle0, &dispatcher0); 605 MojoResult result1 = 606 handles_->GetAndRemoveDispatcher(handle1, &dispatcher1); 607 if (result0 != MOJO_RESULT_OK || result1 != MOJO_RESULT_OK || 608 dispatcher0->GetType() != Dispatcher::Type::MESSAGE_PIPE || 609 dispatcher1->GetType() != Dispatcher::Type::MESSAGE_PIPE) 610 valid_handles = false; 611 } 612 613 if (!valid_handles) { 614 if (dispatcher0) 615 dispatcher0->Close(); 616 if (dispatcher1) 617 dispatcher1->Close(); 618 return MOJO_RESULT_INVALID_ARGUMENT; 619 } 620 621 MessagePipeDispatcher* mpd0 = 622 static_cast<MessagePipeDispatcher*>(dispatcher0.get()); 623 MessagePipeDispatcher* mpd1 = 624 static_cast<MessagePipeDispatcher*>(dispatcher1.get()); 625 626 if (!mpd0->Fuse(mpd1)) 627 return MOJO_RESULT_FAILED_PRECONDITION; 628 629 return MOJO_RESULT_OK; 630 } 631 632 MojoResult Core::NotifyBadMessage(MojoMessageHandle message_handle, 633 const char* error, 634 size_t error_num_bytes, 635 const MojoNotifyBadMessageOptions* options) { 636 if (!message_handle) 637 return MOJO_RESULT_INVALID_ARGUMENT; 638 639 auto* message_event = 640 reinterpret_cast<ports::UserMessageEvent*>(message_handle); 641 auto* message = message_event->GetMessage<UserMessageImpl>(); 642 if (message->source_node() == ports::kInvalidNodeName) { 643 DVLOG(1) << "Received invalid message from unknown node."; 644 if (!default_process_error_callback_.is_null()) 645 default_process_error_callback_.Run(std::string(error, error_num_bytes)); 646 return MOJO_RESULT_OK; 647 } 648 649 GetNodeController()->NotifyBadMessageFrom( 650 message->source_node(), std::string(error, error_num_bytes)); 651 return MOJO_RESULT_OK; 652 } 653 654 MojoResult Core::CreateDataPipe(const MojoCreateDataPipeOptions* options, 655 MojoHandle* data_pipe_producer_handle, 656 MojoHandle* data_pipe_consumer_handle) { 657 RequestContext request_context; 658 if (options && options->struct_size < sizeof(MojoCreateDataPipeOptions)) 659 return MOJO_RESULT_INVALID_ARGUMENT; 660 661 MojoCreateDataPipeOptions create_options; 662 create_options.struct_size = sizeof(MojoCreateDataPipeOptions); 663 create_options.flags = options ? options->flags : 0; 664 create_options.element_num_bytes = options ? options->element_num_bytes : 1; 665 // TODO(rockot): Use Configuration to get default data pipe capacity. 666 create_options.capacity_num_bytes = options && options->capacity_num_bytes 667 ? options->capacity_num_bytes 668 : 64 * 1024; 669 if (!create_options.element_num_bytes || !create_options.capacity_num_bytes || 670 create_options.capacity_num_bytes < create_options.element_num_bytes) { 671 return MOJO_RESULT_INVALID_ARGUMENT; 672 } 673 674 base::subtle::PlatformSharedMemoryRegion ring_buffer_region = 675 base::WritableSharedMemoryRegion::TakeHandleForSerialization( 676 GetNodeController()->CreateSharedBuffer( 677 create_options.capacity_num_bytes)); 678 679 // NOTE: We demote the writable region to an unsafe region so that the 680 // producer handle can be transferred freely. There is no compelling reason 681 // to restrict access rights of consumers since they are the exclusive 682 // consumer of this pipe, and it would be impossible to support such access 683 // control on Android anyway. 684 auto writable_region_handle = ring_buffer_region.PassPlatformHandle(); 685 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \ 686 (!defined(OS_MACOSX) || defined(OS_IOS)) 687 // This isn't strictly necessary, but it does make the handle configuration 688 // consistent with regular UnsafeSharedMemoryRegions. 689 writable_region_handle.readonly_fd.reset(); 690 #endif 691 base::UnsafeSharedMemoryRegion producer_region = 692 base::UnsafeSharedMemoryRegion::Deserialize( 693 base::subtle::PlatformSharedMemoryRegion::Take( 694 std::move(writable_region_handle), 695 base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe, 696 create_options.capacity_num_bytes, ring_buffer_region.GetGUID())); 697 if (!producer_region.IsValid()) 698 return MOJO_RESULT_RESOURCE_EXHAUSTED; 699 700 ports::PortRef port0, port1; 701 GetNodeController()->node()->CreatePortPair(&port0, &port1); 702 703 DCHECK(data_pipe_producer_handle); 704 DCHECK(data_pipe_consumer_handle); 705 706 base::UnsafeSharedMemoryRegion consumer_region = producer_region.Duplicate(); 707 uint64_t pipe_id = base::RandUint64(); 708 scoped_refptr<Dispatcher> producer = DataPipeProducerDispatcher::Create( 709 GetNodeController(), port0, std::move(producer_region), create_options, 710 pipe_id); 711 if (!producer) 712 return MOJO_RESULT_RESOURCE_EXHAUSTED; 713 714 scoped_refptr<Dispatcher> consumer = DataPipeConsumerDispatcher::Create( 715 GetNodeController(), port1, std::move(consumer_region), create_options, 716 pipe_id); 717 if (!consumer) { 718 producer->Close(); 719 return MOJO_RESULT_RESOURCE_EXHAUSTED; 720 } 721 722 *data_pipe_producer_handle = AddDispatcher(producer); 723 *data_pipe_consumer_handle = AddDispatcher(consumer); 724 if (*data_pipe_producer_handle == MOJO_HANDLE_INVALID || 725 *data_pipe_consumer_handle == MOJO_HANDLE_INVALID) { 726 if (*data_pipe_producer_handle != MOJO_HANDLE_INVALID) { 727 scoped_refptr<Dispatcher> unused; 728 base::AutoLock lock(handles_->GetLock()); 729 handles_->GetAndRemoveDispatcher(*data_pipe_producer_handle, &unused); 730 } 731 producer->Close(); 732 consumer->Close(); 733 return MOJO_RESULT_RESOURCE_EXHAUSTED; 734 } 735 736 return MOJO_RESULT_OK; 737 } 738 739 MojoResult Core::WriteData(MojoHandle data_pipe_producer_handle, 740 const void* elements, 741 uint32_t* num_bytes, 742 const MojoWriteDataOptions* options) { 743 RequestContext request_context; 744 scoped_refptr<Dispatcher> dispatcher( 745 GetDispatcher(data_pipe_producer_handle)); 746 if (!dispatcher) 747 return MOJO_RESULT_INVALID_ARGUMENT; 748 749 MojoWriteDataOptions validated_options; 750 if (options) { 751 if (options->struct_size < sizeof(*options)) 752 return MOJO_RESULT_INVALID_ARGUMENT; 753 754 constexpr MojoWriteDataFlags kSupportedFlags = 755 MOJO_WRITE_DATA_FLAG_NONE | MOJO_WRITE_DATA_FLAG_ALL_OR_NONE; 756 if (options->flags & ~kSupportedFlags) 757 return MOJO_RESULT_UNIMPLEMENTED; 758 validated_options.flags = options->flags; 759 } else { 760 validated_options.flags = MOJO_WRITE_DATA_FLAG_NONE; 761 } 762 return dispatcher->WriteData(elements, num_bytes, validated_options); 763 } 764 765 MojoResult Core::BeginWriteData(MojoHandle data_pipe_producer_handle, 766 const MojoBeginWriteDataOptions* options, 767 void** buffer, 768 uint32_t* buffer_num_bytes) { 769 RequestContext request_context; 770 scoped_refptr<Dispatcher> dispatcher( 771 GetDispatcher(data_pipe_producer_handle)); 772 if (!dispatcher) 773 return MOJO_RESULT_INVALID_ARGUMENT; 774 if (options) { 775 if (options->struct_size < sizeof(*options)) 776 return MOJO_RESULT_INVALID_ARGUMENT; 777 if (options->flags != MOJO_BEGIN_WRITE_DATA_FLAG_NONE) 778 return MOJO_RESULT_UNIMPLEMENTED; 779 } 780 return dispatcher->BeginWriteData(buffer, buffer_num_bytes); 781 } 782 783 MojoResult Core::EndWriteData(MojoHandle data_pipe_producer_handle, 784 uint32_t num_bytes_written, 785 const MojoEndWriteDataOptions* options) { 786 RequestContext request_context; 787 scoped_refptr<Dispatcher> dispatcher( 788 GetDispatcher(data_pipe_producer_handle)); 789 if (!dispatcher) 790 return MOJO_RESULT_INVALID_ARGUMENT; 791 if (options) { 792 if (options->struct_size < sizeof(*options)) 793 return MOJO_RESULT_INVALID_ARGUMENT; 794 if (options->flags != MOJO_END_WRITE_DATA_FLAG_NONE) 795 return MOJO_RESULT_UNIMPLEMENTED; 796 } 797 return dispatcher->EndWriteData(num_bytes_written); 798 } 799 800 MojoResult Core::ReadData(MojoHandle data_pipe_consumer_handle, 801 const MojoReadDataOptions* options, 802 void* elements, 803 uint32_t* num_bytes) { 804 RequestContext request_context; 805 scoped_refptr<Dispatcher> dispatcher( 806 GetDispatcher(data_pipe_consumer_handle)); 807 if (!dispatcher) 808 return MOJO_RESULT_INVALID_ARGUMENT; 809 810 MojoReadDataOptions validated_options; 811 if (options) { 812 if (options->struct_size < sizeof(*options)) 813 return MOJO_RESULT_INVALID_ARGUMENT; 814 815 constexpr MojoReadDataFlags kSupportedFlags = 816 MOJO_READ_DATA_FLAG_NONE | MOJO_READ_DATA_FLAG_ALL_OR_NONE | 817 MOJO_READ_DATA_FLAG_DISCARD | MOJO_READ_DATA_FLAG_QUERY | 818 MOJO_READ_DATA_FLAG_PEEK; 819 if (options->flags & ~kSupportedFlags) 820 return MOJO_RESULT_UNIMPLEMENTED; 821 validated_options.flags = options->flags; 822 } else { 823 validated_options.flags = MOJO_WRITE_DATA_FLAG_NONE; 824 } 825 return dispatcher->ReadData(validated_options, elements, num_bytes); 826 } 827 828 MojoResult Core::BeginReadData(MojoHandle data_pipe_consumer_handle, 829 const MojoBeginReadDataOptions* options, 830 const void** buffer, 831 uint32_t* buffer_num_bytes) { 832 RequestContext request_context; 833 scoped_refptr<Dispatcher> dispatcher( 834 GetDispatcher(data_pipe_consumer_handle)); 835 if (!dispatcher) 836 return MOJO_RESULT_INVALID_ARGUMENT; 837 838 if (options) { 839 if (options->struct_size < sizeof(*options)) 840 return MOJO_RESULT_INVALID_ARGUMENT; 841 if (options->flags != MOJO_BEGIN_READ_DATA_FLAG_NONE) 842 return MOJO_RESULT_UNIMPLEMENTED; 843 } 844 return dispatcher->BeginReadData(buffer, buffer_num_bytes); 845 } 846 847 MojoResult Core::EndReadData(MojoHandle data_pipe_consumer_handle, 848 uint32_t num_bytes_read, 849 const MojoEndReadDataOptions* options) { 850 RequestContext request_context; 851 scoped_refptr<Dispatcher> dispatcher( 852 GetDispatcher(data_pipe_consumer_handle)); 853 if (!dispatcher) 854 return MOJO_RESULT_INVALID_ARGUMENT; 855 if (options) { 856 if (options->struct_size < sizeof(*options)) 857 return MOJO_RESULT_INVALID_ARGUMENT; 858 if (options->flags != MOJO_END_READ_DATA_FLAG_NONE) 859 return MOJO_RESULT_UNIMPLEMENTED; 860 } 861 return dispatcher->EndReadData(num_bytes_read); 862 } 863 864 MojoResult Core::CreateSharedBuffer( 865 uint64_t num_bytes, 866 const MojoCreateSharedBufferOptions* options, 867 MojoHandle* shared_buffer_handle) { 868 RequestContext request_context; 869 MojoCreateSharedBufferOptions validated_options = {}; 870 MojoResult result = SharedBufferDispatcher::ValidateCreateOptions( 871 options, &validated_options); 872 if (result != MOJO_RESULT_OK) 873 return result; 874 875 scoped_refptr<SharedBufferDispatcher> dispatcher; 876 result = SharedBufferDispatcher::Create( 877 validated_options, GetNodeController(), num_bytes, &dispatcher); 878 if (result != MOJO_RESULT_OK) { 879 DCHECK(!dispatcher); 880 return result; 881 } 882 883 *shared_buffer_handle = AddDispatcher(dispatcher); 884 if (*shared_buffer_handle == MOJO_HANDLE_INVALID) { 885 LOG(ERROR) << "Handle table full"; 886 dispatcher->Close(); 887 return MOJO_RESULT_RESOURCE_EXHAUSTED; 888 } 889 890 return MOJO_RESULT_OK; 891 } 892 893 MojoResult Core::DuplicateBufferHandle( 894 MojoHandle buffer_handle, 895 const MojoDuplicateBufferHandleOptions* options, 896 MojoHandle* new_buffer_handle) { 897 RequestContext request_context; 898 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); 899 if (!dispatcher) 900 return MOJO_RESULT_INVALID_ARGUMENT; 901 902 // Don't verify |options| here; that's the dispatcher's job. 903 scoped_refptr<Dispatcher> new_dispatcher; 904 MojoResult result = 905 dispatcher->DuplicateBufferHandle(options, &new_dispatcher); 906 if (result != MOJO_RESULT_OK) 907 return result; 908 909 *new_buffer_handle = AddDispatcher(new_dispatcher); 910 if (*new_buffer_handle == MOJO_HANDLE_INVALID) { 911 LOG(ERROR) << "Handle table full"; 912 new_dispatcher->Close(); 913 return MOJO_RESULT_RESOURCE_EXHAUSTED; 914 } 915 916 return MOJO_RESULT_OK; 917 } 918 919 MojoResult Core::MapBuffer(MojoHandle buffer_handle, 920 uint64_t offset, 921 uint64_t num_bytes, 922 const MojoMapBufferOptions* options, 923 void** buffer) { 924 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); 925 if (!dispatcher) 926 return MOJO_RESULT_INVALID_ARGUMENT; 927 if (options) { 928 if (options->struct_size < sizeof(*options)) 929 return MOJO_RESULT_INVALID_ARGUMENT; 930 if (options->flags != MOJO_MAP_BUFFER_FLAG_NONE) 931 return MOJO_RESULT_UNIMPLEMENTED; 932 } 933 934 std::unique_ptr<PlatformSharedMemoryMapping> mapping; 935 MojoResult result = dispatcher->MapBuffer(offset, num_bytes, &mapping); 936 if (result != MOJO_RESULT_OK) 937 return result; 938 939 DCHECK(mapping); 940 void* address = mapping->GetBase(); 941 { 942 base::AutoLock locker(mapping_table_lock_); 943 if (mapping_table_.size() >= GetConfiguration().max_mapping_table_size) 944 return MOJO_RESULT_RESOURCE_EXHAUSTED; 945 auto emplace_result = mapping_table_.emplace(address, std::move(mapping)); 946 DCHECK(emplace_result.second); 947 } 948 949 *buffer = address; 950 return MOJO_RESULT_OK; 951 } 952 953 MojoResult Core::UnmapBuffer(void* buffer) { 954 std::unique_ptr<PlatformSharedMemoryMapping> mapping; 955 // Destroy |mapping| while not holding the lock. 956 { 957 base::AutoLock lock(mapping_table_lock_); 958 auto iter = mapping_table_.find(buffer); 959 if (iter == mapping_table_.end()) 960 return MOJO_RESULT_INVALID_ARGUMENT; 961 962 // Grab a reference so that it gets unmapped outside of this lock. 963 mapping = std::move(iter->second); 964 mapping_table_.erase(iter); 965 } 966 return MOJO_RESULT_OK; 967 } 968 969 MojoResult Core::GetBufferInfo(MojoHandle buffer_handle, 970 const MojoGetBufferInfoOptions* options, 971 MojoSharedBufferInfo* info) { 972 if (options) { 973 if (options->struct_size < sizeof(*options)) 974 return MOJO_RESULT_INVALID_ARGUMENT; 975 if (options->flags != MOJO_GET_BUFFER_INFO_FLAG_NONE) 976 return MOJO_RESULT_UNIMPLEMENTED; 977 } 978 if (!info || info->struct_size < sizeof(MojoSharedBufferInfo)) 979 return MOJO_RESULT_INVALID_ARGUMENT; 980 981 scoped_refptr<Dispatcher> dispatcher(GetDispatcher(buffer_handle)); 982 if (!dispatcher) 983 return MOJO_RESULT_INVALID_ARGUMENT; 984 985 return dispatcher->GetBufferInfo(info); 986 } 987 988 MojoResult Core::WrapPlatformHandle( 989 const MojoPlatformHandle* platform_handle, 990 const MojoWrapPlatformHandleOptions* options, 991 MojoHandle* mojo_handle) { 992 if (!platform_handle || 993 platform_handle->struct_size < sizeof(*platform_handle)) { 994 return MOJO_RESULT_INVALID_ARGUMENT; 995 } 996 997 auto handle = PlatformHandle::FromMojoPlatformHandle(platform_handle); 998 MojoHandle h = 999 AddDispatcher(PlatformHandleDispatcher::Create(std::move(handle))); 1000 if (h == MOJO_HANDLE_INVALID) 1001 return MOJO_RESULT_RESOURCE_EXHAUSTED; 1002 1003 *mojo_handle = h; 1004 return MOJO_RESULT_OK; 1005 } 1006 1007 MojoResult Core::UnwrapPlatformHandle( 1008 MojoHandle mojo_handle, 1009 const MojoUnwrapPlatformHandleOptions* options, 1010 MojoPlatformHandle* platform_handle) { 1011 if (!platform_handle || 1012 platform_handle->struct_size < sizeof(*platform_handle)) { 1013 return MOJO_RESULT_INVALID_ARGUMENT; 1014 } 1015 1016 scoped_refptr<Dispatcher> dispatcher; 1017 { 1018 base::AutoLock lock(handles_->GetLock()); 1019 dispatcher = handles_->GetDispatcher(mojo_handle); 1020 if (dispatcher->GetType() != Dispatcher::Type::PLATFORM_HANDLE) 1021 return MOJO_RESULT_INVALID_ARGUMENT; 1022 1023 MojoResult result = 1024 handles_->GetAndRemoveDispatcher(mojo_handle, &dispatcher); 1025 if (result != MOJO_RESULT_OK) 1026 return result; 1027 } 1028 1029 PlatformHandleDispatcher* phd = 1030 static_cast<PlatformHandleDispatcher*>(dispatcher.get()); 1031 PlatformHandle handle = phd->TakePlatformHandle(); 1032 phd->Close(); 1033 1034 PlatformHandle::ToMojoPlatformHandle(std::move(handle), platform_handle); 1035 return MOJO_RESULT_OK; 1036 } 1037 1038 MojoResult Core::WrapPlatformSharedMemoryRegion( 1039 const MojoPlatformHandle* platform_handles, 1040 uint32_t num_platform_handles, 1041 uint64_t size, 1042 const MojoSharedBufferGuid* guid, 1043 MojoPlatformSharedMemoryRegionAccessMode access_mode, 1044 const MojoWrapPlatformSharedMemoryRegionOptions* options, 1045 MojoHandle* mojo_handle) { 1046 DCHECK(size); 1047 1048 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \ 1049 (!defined(OS_MACOSX) || defined(OS_IOS)) 1050 if (access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) { 1051 if (num_platform_handles != 2) 1052 return MOJO_RESULT_INVALID_ARGUMENT; 1053 } 1054 #else 1055 if (num_platform_handles != 1) 1056 return MOJO_RESULT_INVALID_ARGUMENT; 1057 #endif 1058 1059 PlatformHandle handles[2]; 1060 bool handles_ok = true; 1061 for (size_t i = 0; i < num_platform_handles; ++i) { 1062 handles[i] = PlatformHandle::FromMojoPlatformHandle(&platform_handles[i]); 1063 if (!handles[i].is_valid()) 1064 handles_ok = false; 1065 } 1066 if (!handles_ok) 1067 return MOJO_RESULT_INVALID_ARGUMENT; 1068 1069 base::UnguessableToken token = 1070 base::UnguessableToken::Deserialize(guid->high, guid->low); 1071 1072 base::subtle::PlatformSharedMemoryRegion::Mode mode; 1073 switch (access_mode) { 1074 case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY: 1075 mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly; 1076 break; 1077 case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE: 1078 mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable; 1079 break; 1080 case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE: 1081 mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe; 1082 break; 1083 default: 1084 return MOJO_RESULT_INVALID_ARGUMENT; 1085 } 1086 1087 base::subtle::PlatformSharedMemoryRegion region = 1088 base::subtle::PlatformSharedMemoryRegion::Take( 1089 CreateSharedMemoryRegionHandleFromPlatformHandles( 1090 std::move(handles[0]), std::move(handles[1])), 1091 mode, size, token); 1092 if (!region.IsValid()) 1093 return MOJO_RESULT_UNKNOWN; 1094 1095 scoped_refptr<SharedBufferDispatcher> dispatcher; 1096 MojoResult result = 1097 SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion( 1098 std::move(region), &dispatcher); 1099 if (result != MOJO_RESULT_OK) 1100 return result; 1101 1102 MojoHandle h = AddDispatcher(dispatcher); 1103 if (h == MOJO_HANDLE_INVALID) { 1104 dispatcher->Close(); 1105 return MOJO_RESULT_RESOURCE_EXHAUSTED; 1106 } 1107 1108 *mojo_handle = h; 1109 return MOJO_RESULT_OK; 1110 } 1111 1112 MojoResult Core::UnwrapPlatformSharedMemoryRegion( 1113 MojoHandle mojo_handle, 1114 const MojoUnwrapPlatformSharedMemoryRegionOptions* options, 1115 MojoPlatformHandle* platform_handles, 1116 uint32_t* num_platform_handles, 1117 uint64_t* size, 1118 MojoSharedBufferGuid* guid, 1119 MojoPlatformSharedMemoryRegionAccessMode* access_mode) { 1120 scoped_refptr<Dispatcher> dispatcher; 1121 MojoResult result = MOJO_RESULT_OK; 1122 { 1123 base::AutoLock lock(handles_->GetLock()); 1124 result = handles_->GetAndRemoveDispatcher(mojo_handle, &dispatcher); 1125 if (result != MOJO_RESULT_OK) 1126 return result; 1127 } 1128 1129 if (dispatcher->GetType() != Dispatcher::Type::SHARED_BUFFER) { 1130 dispatcher->Close(); 1131 return MOJO_RESULT_INVALID_ARGUMENT; 1132 } 1133 1134 SharedBufferDispatcher* shm_dispatcher = 1135 static_cast<SharedBufferDispatcher*>(dispatcher.get()); 1136 base::subtle::PlatformSharedMemoryRegion region = 1137 shm_dispatcher->PassPlatformSharedMemoryRegion(); 1138 DCHECK(region.IsValid()); 1139 DCHECK(size); 1140 *size = region.GetSize(); 1141 1142 base::UnguessableToken token = region.GetGUID(); 1143 guid->high = token.GetHighForSerialization(); 1144 guid->low = token.GetLowForSerialization(); 1145 1146 DCHECK(access_mode); 1147 switch (region.GetMode()) { 1148 case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly: 1149 *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY; 1150 break; 1151 case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable: 1152 *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE; 1153 break; 1154 case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe: 1155 *access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE; 1156 break; 1157 default: 1158 return MOJO_RESULT_INVALID_ARGUMENT; 1159 } 1160 1161 PlatformHandle handle; 1162 PlatformHandle read_only_handle; 1163 ExtractPlatformHandlesFromSharedMemoryRegionHandle( 1164 region.PassPlatformHandle(), &handle, &read_only_handle); 1165 1166 const uint32_t available_handle_storage_slots = *num_platform_handles; 1167 if (available_handle_storage_slots < 1) 1168 return MOJO_RESULT_RESOURCE_EXHAUSTED; 1169 *num_platform_handles = 1; 1170 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \ 1171 (!defined(OS_MACOSX) || defined(OS_IOS)) 1172 if (region.GetMode() == 1173 base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) { 1174 if (available_handle_storage_slots < 2) 1175 return MOJO_RESULT_INVALID_ARGUMENT; 1176 PlatformHandle::ToMojoPlatformHandle(std::move(read_only_handle), 1177 &platform_handles[1]); 1178 if (platform_handles[1].type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) 1179 return MOJO_RESULT_INVALID_ARGUMENT; 1180 *num_platform_handles = 2; 1181 } 1182 #endif 1183 1184 PlatformHandle::ToMojoPlatformHandle(std::move(handle), &platform_handles[0]); 1185 if (platform_handles[0].type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) 1186 return MOJO_RESULT_INVALID_ARGUMENT; 1187 1188 return MOJO_RESULT_OK; 1189 } 1190 1191 MojoResult Core::CreateInvitation(const MojoCreateInvitationOptions* options, 1192 MojoHandle* invitation_handle) { 1193 if (options && options->struct_size < sizeof(*options)) 1194 return MOJO_RESULT_INVALID_ARGUMENT; 1195 if (!invitation_handle) 1196 return MOJO_RESULT_INVALID_ARGUMENT; 1197 1198 *invitation_handle = AddDispatcher(new InvitationDispatcher); 1199 if (*invitation_handle == MOJO_HANDLE_INVALID) 1200 return MOJO_RESULT_RESOURCE_EXHAUSTED; 1201 1202 return MOJO_RESULT_OK; 1203 } 1204 1205 MojoResult Core::AttachMessagePipeToInvitation( 1206 MojoHandle invitation_handle, 1207 const void* name, 1208 uint32_t name_num_bytes, 1209 const MojoAttachMessagePipeToInvitationOptions* options, 1210 MojoHandle* message_pipe_handle) { 1211 if (options && options->struct_size < sizeof(*options)) 1212 return MOJO_RESULT_INVALID_ARGUMENT; 1213 if (!message_pipe_handle) 1214 return MOJO_RESULT_INVALID_ARGUMENT; 1215 if (name_num_bytes == 0) 1216 return MOJO_RESULT_INVALID_ARGUMENT; 1217 1218 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle); 1219 if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION) 1220 return MOJO_RESULT_INVALID_ARGUMENT; 1221 auto* invitation_dispatcher = 1222 static_cast<InvitationDispatcher*>(dispatcher.get()); 1223 1224 RequestContext request_context; 1225 1226 ports::PortRef remote_peer_port; 1227 MojoHandle local_handle = CreatePartialMessagePipe(&remote_peer_port); 1228 if (local_handle == MOJO_HANDLE_INVALID) 1229 return MOJO_RESULT_RESOURCE_EXHAUSTED; 1230 1231 MojoResult result = invitation_dispatcher->AttachMessagePipe( 1232 base::StringPiece(static_cast<const char*>(name), name_num_bytes), 1233 std::move(remote_peer_port)); 1234 if (result != MOJO_RESULT_OK) { 1235 Close(local_handle); 1236 return result; 1237 } 1238 1239 *message_pipe_handle = local_handle; 1240 return MOJO_RESULT_OK; 1241 } 1242 1243 MojoResult Core::ExtractMessagePipeFromInvitation( 1244 MojoHandle invitation_handle, 1245 const void* name, 1246 uint32_t name_num_bytes, 1247 const MojoExtractMessagePipeFromInvitationOptions* options, 1248 MojoHandle* message_pipe_handle) { 1249 if (options && options->struct_size < sizeof(*options)) 1250 return MOJO_RESULT_INVALID_ARGUMENT; 1251 if (!message_pipe_handle) 1252 return MOJO_RESULT_INVALID_ARGUMENT; 1253 if (name_num_bytes == 0) 1254 return MOJO_RESULT_INVALID_ARGUMENT; 1255 1256 RequestContext request_context; 1257 1258 base::StringPiece name_string(static_cast<const char*>(name), name_num_bytes); 1259 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle); 1260 if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION) 1261 return MOJO_RESULT_INVALID_ARGUMENT; 1262 auto* invitation_dispatcher = 1263 static_cast<InvitationDispatcher*>(dispatcher.get()); 1264 // First attempt to extract from the invitation object itself. This is for 1265 // cases where this invitation was created in-process or is an accepted 1266 // isolated invitation. 1267 MojoResult extract_result = invitation_dispatcher->ExtractMessagePipe( 1268 name_string, message_pipe_handle); 1269 if (extract_result == MOJO_RESULT_OK || 1270 extract_result == MOJO_RESULT_RESOURCE_EXHAUSTED) { 1271 return extract_result; 1272 } 1273 1274 *message_pipe_handle = 1275 ExtractMessagePipeFromInvitation(name_string.as_string()); 1276 if (*message_pipe_handle == MOJO_HANDLE_INVALID) 1277 return MOJO_RESULT_RESOURCE_EXHAUSTED; 1278 return MOJO_RESULT_OK; 1279 } 1280 1281 MojoResult Core::SendInvitation( 1282 MojoHandle invitation_handle, 1283 const MojoPlatformProcessHandle* process_handle, 1284 const MojoInvitationTransportEndpoint* transport_endpoint, 1285 MojoProcessErrorHandler error_handler, 1286 uintptr_t error_handler_context, 1287 const MojoSendInvitationOptions* options) { 1288 if (options && options->struct_size < sizeof(*options)) 1289 return MOJO_RESULT_INVALID_ARGUMENT; 1290 1291 base::ProcessHandle target_process = base::kNullProcessHandle; 1292 if (process_handle) { 1293 if (process_handle->struct_size < sizeof(*process_handle)) 1294 return MOJO_RESULT_INVALID_ARGUMENT; 1295 #if defined(OS_WIN) 1296 target_process = reinterpret_cast<base::ProcessHandle>( 1297 static_cast<uintptr_t>(process_handle->value)); 1298 #else 1299 target_process = static_cast<base::ProcessHandle>(process_handle->value); 1300 #endif 1301 } 1302 1303 ProcessErrorCallback process_error_callback; 1304 if (error_handler) { 1305 auto error_handler_task_runner = GetNodeController()->io_task_runner(); 1306 process_error_callback = base::BindRepeating( 1307 &RunMojoProcessErrorHandler, 1308 base::Owned(new ProcessDisconnectHandler( 1309 error_handler_task_runner, error_handler, error_handler_context)), 1310 error_handler_task_runner, error_handler, error_handler_context); 1311 } else if (default_process_error_callback_) { 1312 process_error_callback = default_process_error_callback_; 1313 } 1314 1315 if (!transport_endpoint) 1316 return MOJO_RESULT_INVALID_ARGUMENT; 1317 if (transport_endpoint->struct_size < sizeof(*transport_endpoint)) 1318 return MOJO_RESULT_INVALID_ARGUMENT; 1319 if (transport_endpoint->num_platform_handles == 0) 1320 return MOJO_RESULT_INVALID_ARGUMENT; 1321 if (!transport_endpoint->platform_handles) 1322 return MOJO_RESULT_INVALID_ARGUMENT; 1323 if (transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL && 1324 transport_endpoint->type != 1325 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) { 1326 return MOJO_RESULT_UNIMPLEMENTED; 1327 } 1328 1329 scoped_refptr<Dispatcher> dispatcher = GetDispatcher(invitation_handle); 1330 if (!dispatcher || dispatcher->GetType() != Dispatcher::Type::INVITATION) 1331 return MOJO_RESULT_INVALID_ARGUMENT; 1332 auto* invitation_dispatcher = 1333 static_cast<InvitationDispatcher*>(dispatcher.get()); 1334 1335 auto endpoint = PlatformHandle::FromMojoPlatformHandle( 1336 &transport_endpoint->platform_handles[0]); 1337 if (!endpoint.is_valid()) 1338 return MOJO_RESULT_INVALID_ARGUMENT; 1339 1340 ConnectionParams connection_params; 1341 #if defined(OS_WIN) || defined(OS_POSIX) 1342 if (transport_endpoint->type == 1343 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) { 1344 connection_params = 1345 ConnectionParams(PlatformChannelServerEndpoint(std::move(endpoint))); 1346 } 1347 #endif 1348 if (!connection_params.server_endpoint().is_valid()) { 1349 connection_params = 1350 ConnectionParams(PlatformChannelEndpoint(std::move(endpoint))); 1351 } 1352 1353 // At this point everything else has been validated, so we can take ownership 1354 // of the dispatcher. 1355 { 1356 base::AutoLock lock(handles_->GetLock()); 1357 scoped_refptr<Dispatcher> removed_dispatcher; 1358 MojoResult result = handles_->GetAndRemoveDispatcher(invitation_handle, 1359 &removed_dispatcher); 1360 if (result != MOJO_RESULT_OK) { 1361 // Release ownership of the endpoint platform handle, per the API 1362 // contract. The caller retains ownership on failure. 1363 connection_params.TakeEndpoint().TakePlatformHandle().release(); 1364 connection_params.TakeServerEndpoint().TakePlatformHandle().release(); 1365 return result; 1366 } 1367 DCHECK_EQ(removed_dispatcher.get(), invitation_dispatcher); 1368 } 1369 1370 std::vector<std::pair<std::string, ports::PortRef>> attached_ports; 1371 InvitationDispatcher::PortMapping attached_port_map = 1372 invitation_dispatcher->TakeAttachedPorts(); 1373 invitation_dispatcher->Close(); 1374 for (auto& entry : attached_port_map) 1375 attached_ports.emplace_back(entry.first, std::move(entry.second)); 1376 1377 bool is_isolated = 1378 options && (options->flags & MOJO_SEND_INVITATION_FLAG_ISOLATED); 1379 RequestContext request_context; 1380 if (is_isolated) { 1381 DCHECK_EQ(attached_ports.size(), 1u); 1382 DCHECK_EQ(attached_ports[0].first, kIsolatedInvitationPipeName); 1383 base::StringPiece connection_name(options->isolated_connection_name, 1384 options->isolated_connection_name_length); 1385 GetNodeController()->ConnectIsolated(std::move(connection_params), 1386 attached_ports[0].second, 1387 connection_name); 1388 } else { 1389 GetNodeController()->SendBrokerClientInvitation( 1390 target_process, std::move(connection_params), attached_ports, 1391 process_error_callback); 1392 } 1393 1394 return MOJO_RESULT_OK; 1395 } 1396 1397 MojoResult Core::AcceptInvitation( 1398 const MojoInvitationTransportEndpoint* transport_endpoint, 1399 const MojoAcceptInvitationOptions* options, 1400 MojoHandle* invitation_handle) { 1401 if (options && options->struct_size < sizeof(*options)) 1402 return MOJO_RESULT_INVALID_ARGUMENT; 1403 1404 if (!transport_endpoint) 1405 return MOJO_RESULT_INVALID_ARGUMENT; 1406 if (transport_endpoint->struct_size < sizeof(*transport_endpoint)) 1407 return MOJO_RESULT_INVALID_ARGUMENT; 1408 if (transport_endpoint->num_platform_handles == 0) 1409 return MOJO_RESULT_INVALID_ARGUMENT; 1410 if (!transport_endpoint->platform_handles) 1411 return MOJO_RESULT_INVALID_ARGUMENT; 1412 if (transport_endpoint->type != MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL && 1413 transport_endpoint->type != 1414 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) { 1415 return MOJO_RESULT_UNIMPLEMENTED; 1416 } 1417 1418 if (!invitation_handle) 1419 return MOJO_RESULT_INVALID_ARGUMENT; 1420 auto dispatcher = base::MakeRefCounted<InvitationDispatcher>(); 1421 *invitation_handle = AddDispatcher(dispatcher); 1422 if (*invitation_handle == MOJO_HANDLE_INVALID) 1423 return MOJO_RESULT_RESOURCE_EXHAUSTED; 1424 1425 auto endpoint = PlatformHandle::FromMojoPlatformHandle( 1426 &transport_endpoint->platform_handles[0]); 1427 if (!endpoint.is_valid()) { 1428 Close(*invitation_handle); 1429 *invitation_handle = MOJO_HANDLE_INVALID; 1430 return MOJO_RESULT_INVALID_ARGUMENT; 1431 } 1432 1433 ConnectionParams connection_params; 1434 #if defined(OS_WIN) || defined(OS_POSIX) 1435 if (transport_endpoint->type == 1436 MOJO_INVITATION_TRANSPORT_TYPE_CHANNEL_SERVER) { 1437 connection_params = 1438 ConnectionParams(PlatformChannelServerEndpoint(std::move(endpoint))); 1439 } 1440 #endif 1441 if (!connection_params.server_endpoint().is_valid()) { 1442 connection_params = 1443 ConnectionParams(PlatformChannelEndpoint(std::move(endpoint))); 1444 } 1445 1446 bool is_isolated = 1447 options && (options->flags & MOJO_ACCEPT_INVITATION_FLAG_ISOLATED); 1448 NodeController* const node_controller = GetNodeController(); 1449 RequestContext request_context; 1450 if (is_isolated) { 1451 // For an isolated invitation, we simply mint a new port pair here and send 1452 // one name to the remote endpoint while stashing the other in the accepted 1453 // invitation object for later extraction. 1454 ports::PortRef local_port; 1455 ports::PortRef remote_port; 1456 node_controller->node()->CreatePortPair(&local_port, &remote_port); 1457 node_controller->ConnectIsolated(std::move(connection_params), remote_port, 1458 base::StringPiece()); 1459 MojoResult result = 1460 dispatcher->AttachMessagePipe(kIsolatedInvitationPipeName, local_port); 1461 DCHECK_EQ(MOJO_RESULT_OK, result); 1462 } else { 1463 node_controller->AcceptBrokerClientInvitation(std::move(connection_params)); 1464 } 1465 1466 return MOJO_RESULT_OK; 1467 } 1468 1469 MojoResult Core::SetQuota(MojoHandle handle, 1470 MojoQuotaType type, 1471 uint64_t limit, 1472 const MojoSetQuotaOptions* options) { 1473 RequestContext request_context; 1474 if (options && options->struct_size < sizeof(*options)) 1475 return MOJO_RESULT_INVALID_ARGUMENT; 1476 auto dispatcher = GetDispatcher(handle); 1477 if (!dispatcher) 1478 return MOJO_RESULT_INVALID_ARGUMENT; 1479 1480 return dispatcher->SetQuota(type, limit); 1481 } 1482 1483 MojoResult Core::QueryQuota(MojoHandle handle, 1484 MojoQuotaType type, 1485 const MojoQueryQuotaOptions* options, 1486 uint64_t* limit, 1487 uint64_t* usage) { 1488 RequestContext request_context; 1489 if (options && options->struct_size < sizeof(*options)) 1490 return MOJO_RESULT_INVALID_ARGUMENT; 1491 auto dispatcher = GetDispatcher(handle); 1492 if (!dispatcher) 1493 return MOJO_RESULT_INVALID_ARGUMENT; 1494 return dispatcher->QueryQuota(type, limit, usage); 1495 } 1496 1497 void Core::GetActiveHandlesForTest(std::vector<MojoHandle>* handles) { 1498 base::AutoLock lock(handles_->GetLock()); 1499 handles_->GetActiveHandlesForTest(handles); 1500 } 1501 1502 // static 1503 void Core::PassNodeControllerToIOThread( 1504 std::unique_ptr<NodeController> node_controller) { 1505 // It's OK to leak this reference. At this point we know the IO loop is still 1506 // running, and we know the NodeController will observe its eventual 1507 // destruction. This tells the NodeController to delete itself when that 1508 // happens. 1509 node_controller.release()->DestroyOnIOThreadShutdown(); 1510 } 1511 1512 } // namespace core 1513 } // namespace mojo 1514