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/public/c/system/thunks.h" 6 7 #include <cstddef> 8 #include <cstdint> 9 #include <cstring> 10 11 #include "base/logging.h" 12 #include "base/macros.h" 13 #include "base/memory/protected_memory.h" 14 #include "base/memory/protected_memory_cfi.h" 15 #include "base/no_destructor.h" 16 #include "build/build_config.h" 17 #include "mojo/public/c/system/core.h" 18 19 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN) 20 #include "base/environment.h" 21 #include "base/files/file_path.h" 22 #include "base/optional.h" 23 #include "base/scoped_native_library.h" 24 #include "base/threading/thread_restrictions.h" 25 #endif 26 27 namespace { 28 29 typedef void (*MojoGetSystemThunksFunction)(MojoSystemThunks* thunks); 30 31 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN) 32 PROTECTED_MEMORY_SECTION 33 base::ProtectedMemory<MojoGetSystemThunksFunction> g_get_thunks; 34 #endif 35 36 PROTECTED_MEMORY_SECTION base::ProtectedMemory<MojoSystemThunks> g_thunks; 37 38 MojoResult NotImplemented(const char* name) { 39 DLOG(ERROR) << "Function 'Mojo" << name 40 << "()' not supported in this version of Mojo Core."; 41 return MOJO_RESULT_UNIMPLEMENTED; 42 } 43 44 } // namespace 45 46 // Macro to verify that the thunk symbol |name| is actually present in the 47 // runtime version of Mojo Core that is currently in use. 48 #define FUNCTION_IS_IMPLEMENTED(name) \ 49 (reinterpret_cast<uintptr_t>(static_cast<const void*>(&g_thunks->name)) - \ 50 reinterpret_cast<uintptr_t>(static_cast<const void*>(&g_thunks)) < \ 51 g_thunks->size) 52 53 #define INVOKE_THUNK(name, ...) \ 54 FUNCTION_IS_IMPLEMENTED(name) \ 55 ? base::UnsanitizedCfiCall(g_thunks, &MojoSystemThunks::name)(__VA_ARGS__) \ 56 : NotImplemented(#name) 57 58 namespace mojo { 59 60 // NOTE: This is defined within the global mojo namespace so that it can be 61 // referenced as a friend to base::ScopedAllowBlocking when library support is 62 // enabled. 63 class CoreLibraryInitializer { 64 public: 65 CoreLibraryInitializer(const MojoInitializeOptions* options) { 66 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN) 67 bool application_provided_path = false; 68 base::Optional<base::FilePath> library_path; 69 if (options && options->struct_size >= sizeof(*options) && 70 options->mojo_core_path) { 71 base::StringPiece utf8_path(options->mojo_core_path, 72 options->mojo_core_path_length); 73 library_path.emplace(base::FilePath::FromUTF8Unsafe(utf8_path)); 74 application_provided_path = true; 75 } else { 76 auto environment = base::Environment::Create(); 77 std::string library_path_value; 78 const char kLibraryPathEnvironmentVar[] = "MOJO_CORE_LIBRARY_PATH"; 79 if (environment->GetVar(kLibraryPathEnvironmentVar, &library_path_value)) 80 library_path = base::FilePath::FromUTF8Unsafe(library_path_value); 81 } 82 83 if (!library_path) { 84 // Default to looking for the library in the current working directory. 85 #if defined(OS_CHROMEOS) || defined(OS_LINUX) 86 const base::FilePath::CharType kDefaultLibraryPathValue[] = 87 FILE_PATH_LITERAL("./libmojo_core.so"); 88 #elif defined(OS_WIN) 89 const base::FilePath::CharType kDefaultLibraryPathValue[] = 90 FILE_PATH_LITERAL("mojo_core.dll"); 91 #endif 92 library_path.emplace(kDefaultLibraryPathValue); 93 } 94 95 base::ScopedAllowBlocking allow_blocking; 96 library_.emplace(*library_path); 97 if (!application_provided_path) { 98 CHECK(library_->is_valid()) 99 << "Unable to load the mojo_core library. Make sure the library is " 100 << "in the working directory or is correctly pointed to by the " 101 << "MOJO_CORE_LIBRARY_PATH environment variable."; 102 } else { 103 CHECK(library_->is_valid()) 104 << "Unable to locate mojo_core library. This application expects to " 105 << "find it at " << library_path->value(); 106 } 107 108 const char kGetThunksFunctionName[] = "MojoGetSystemThunks"; 109 { 110 auto writer = base::AutoWritableMemory::Create(g_get_thunks); 111 *g_get_thunks = reinterpret_cast<MojoGetSystemThunksFunction>( 112 library_->GetFunctionPointer(kGetThunksFunctionName)); 113 } 114 CHECK(*g_get_thunks) << "Invalid mojo_core library: " 115 << library_path->value(); 116 117 DCHECK_EQ(g_thunks->size, 0u); 118 { 119 auto writer = base::AutoWritableMemory::Create(g_thunks); 120 g_thunks->size = sizeof(*g_thunks); 121 base::UnsanitizedCfiCall(g_get_thunks)(&*g_thunks); 122 } 123 124 CHECK_GT(g_thunks->size, 0u) 125 << "Invalid mojo_core library: " << library_path->value(); 126 #else // defined(OS_CHROMEOS) || defined(OS_LINUX) 127 NOTREACHED() 128 << "Dynamic mojo_core loading is not supported on this platform."; 129 #endif // defined(OS_CHROMEOS) || defined(OS_LINUX) 130 } 131 132 ~CoreLibraryInitializer() = default; 133 134 private: 135 #if defined(OS_CHROMEOS) || defined(OS_LINUX) || defined(OS_WIN) 136 base::Optional<base::ScopedNativeLibrary> library_; 137 #endif 138 139 DISALLOW_COPY_AND_ASSIGN(CoreLibraryInitializer); 140 }; 141 142 } // namespace mojo 143 144 extern "C" { 145 146 MojoResult MojoInitialize(const struct MojoInitializeOptions* options) { 147 static base::NoDestructor<mojo::CoreLibraryInitializer> initializer(options); 148 ALLOW_UNUSED_LOCAL(initializer); 149 DCHECK(g_thunks->Initialize); 150 151 return INVOKE_THUNK(Initialize, options); 152 } 153 154 MojoTimeTicks MojoGetTimeTicksNow() { 155 return INVOKE_THUNK(GetTimeTicksNow); 156 } 157 158 MojoResult MojoClose(MojoHandle handle) { 159 return INVOKE_THUNK(Close, handle); 160 } 161 162 MojoResult MojoQueryHandleSignalsState( 163 MojoHandle handle, 164 struct MojoHandleSignalsState* signals_state) { 165 return INVOKE_THUNK(QueryHandleSignalsState, handle, signals_state); 166 } 167 168 MojoResult MojoCreateMessagePipe(const MojoCreateMessagePipeOptions* options, 169 MojoHandle* message_pipe_handle0, 170 MojoHandle* message_pipe_handle1) { 171 return INVOKE_THUNK(CreateMessagePipe, options, message_pipe_handle0, 172 message_pipe_handle1); 173 } 174 175 MojoResult MojoWriteMessage(MojoHandle message_pipe_handle, 176 MojoMessageHandle message_handle, 177 const MojoWriteMessageOptions* options) { 178 return INVOKE_THUNK(WriteMessage, message_pipe_handle, message_handle, 179 options); 180 } 181 182 MojoResult MojoReadMessage(MojoHandle message_pipe_handle, 183 const MojoReadMessageOptions* options, 184 MojoMessageHandle* message_handle) { 185 return INVOKE_THUNK(ReadMessage, message_pipe_handle, options, 186 message_handle); 187 } 188 189 MojoResult MojoFuseMessagePipes(MojoHandle handle0, 190 MojoHandle handle1, 191 const MojoFuseMessagePipesOptions* options) { 192 return INVOKE_THUNK(FuseMessagePipes, handle0, handle1, options); 193 } 194 195 MojoResult MojoCreateDataPipe(const MojoCreateDataPipeOptions* options, 196 MojoHandle* data_pipe_producer_handle, 197 MojoHandle* data_pipe_consumer_handle) { 198 return INVOKE_THUNK(CreateDataPipe, options, data_pipe_producer_handle, 199 data_pipe_consumer_handle); 200 } 201 202 MojoResult MojoWriteData(MojoHandle data_pipe_producer_handle, 203 const void* elements, 204 uint32_t* num_elements, 205 const MojoWriteDataOptions* options) { 206 return INVOKE_THUNK(WriteData, data_pipe_producer_handle, elements, 207 num_elements, options); 208 } 209 210 MojoResult MojoBeginWriteData(MojoHandle data_pipe_producer_handle, 211 const MojoBeginWriteDataOptions* options, 212 void** buffer, 213 uint32_t* buffer_num_elements) { 214 return INVOKE_THUNK(BeginWriteData, data_pipe_producer_handle, options, 215 buffer, buffer_num_elements); 216 } 217 218 MojoResult MojoEndWriteData(MojoHandle data_pipe_producer_handle, 219 uint32_t num_elements_written, 220 const MojoEndWriteDataOptions* options) { 221 return INVOKE_THUNK(EndWriteData, data_pipe_producer_handle, 222 num_elements_written, options); 223 } 224 225 MojoResult MojoReadData(MojoHandle data_pipe_consumer_handle, 226 const MojoReadDataOptions* options, 227 void* elements, 228 uint32_t* num_elements) { 229 return INVOKE_THUNK(ReadData, data_pipe_consumer_handle, options, elements, 230 num_elements); 231 } 232 233 MojoResult MojoBeginReadData(MojoHandle data_pipe_consumer_handle, 234 const MojoBeginReadDataOptions* options, 235 const void** buffer, 236 uint32_t* buffer_num_elements) { 237 return INVOKE_THUNK(BeginReadData, data_pipe_consumer_handle, options, buffer, 238 buffer_num_elements); 239 } 240 241 MojoResult MojoEndReadData(MojoHandle data_pipe_consumer_handle, 242 uint32_t num_elements_read, 243 const MojoEndReadDataOptions* options) { 244 return INVOKE_THUNK(EndReadData, data_pipe_consumer_handle, num_elements_read, 245 options); 246 } 247 248 MojoResult MojoCreateSharedBuffer(uint64_t num_bytes, 249 const MojoCreateSharedBufferOptions* options, 250 MojoHandle* shared_buffer_handle) { 251 return INVOKE_THUNK(CreateSharedBuffer, num_bytes, options, 252 shared_buffer_handle); 253 } 254 255 MojoResult MojoDuplicateBufferHandle( 256 MojoHandle buffer_handle, 257 const MojoDuplicateBufferHandleOptions* options, 258 MojoHandle* new_buffer_handle) { 259 return INVOKE_THUNK(DuplicateBufferHandle, buffer_handle, options, 260 new_buffer_handle); 261 } 262 263 MojoResult MojoMapBuffer(MojoHandle buffer_handle, 264 uint64_t offset, 265 uint64_t num_bytes, 266 const MojoMapBufferOptions* options, 267 void** buffer) { 268 return INVOKE_THUNK(MapBuffer, buffer_handle, offset, num_bytes, options, 269 buffer); 270 } 271 272 MojoResult MojoUnmapBuffer(void* buffer) { 273 return INVOKE_THUNK(UnmapBuffer, buffer); 274 } 275 276 MojoResult MojoGetBufferInfo(MojoHandle buffer_handle, 277 const MojoGetBufferInfoOptions* options, 278 MojoSharedBufferInfo* info) { 279 return INVOKE_THUNK(GetBufferInfo, buffer_handle, options, info); 280 } 281 282 MojoResult MojoCreateTrap(MojoTrapEventHandler handler, 283 const MojoCreateTrapOptions* options, 284 MojoHandle* trap_handle) { 285 return INVOKE_THUNK(CreateTrap, handler, options, trap_handle); 286 } 287 288 MojoResult MojoAddTrigger(MojoHandle trap_handle, 289 MojoHandle handle, 290 MojoHandleSignals signals, 291 MojoTriggerCondition condition, 292 uintptr_t context, 293 const MojoAddTriggerOptions* options) { 294 return INVOKE_THUNK(AddTrigger, trap_handle, handle, signals, condition, 295 context, options); 296 } 297 298 MojoResult MojoRemoveTrigger(MojoHandle trap_handle, 299 uintptr_t context, 300 const MojoRemoveTriggerOptions* options) { 301 return INVOKE_THUNK(RemoveTrigger, trap_handle, context, options); 302 } 303 304 MojoResult MojoArmTrap(MojoHandle trap_handle, 305 const MojoArmTrapOptions* options, 306 uint32_t* num_blocking_events, 307 MojoTrapEvent* blocking_events) { 308 return INVOKE_THUNK(ArmTrap, trap_handle, options, num_blocking_events, 309 blocking_events); 310 } 311 312 MojoResult MojoCreateMessage(const MojoCreateMessageOptions* options, 313 MojoMessageHandle* message) { 314 return INVOKE_THUNK(CreateMessage, options, message); 315 } 316 317 MojoResult MojoDestroyMessage(MojoMessageHandle message) { 318 return INVOKE_THUNK(DestroyMessage, message); 319 } 320 321 MojoResult MojoSerializeMessage(MojoMessageHandle message, 322 const MojoSerializeMessageOptions* options) { 323 return INVOKE_THUNK(SerializeMessage, message, options); 324 } 325 326 MojoResult MojoAppendMessageData(MojoMessageHandle message, 327 uint32_t payload_size, 328 const MojoHandle* handles, 329 uint32_t num_handles, 330 const MojoAppendMessageDataOptions* options, 331 void** buffer, 332 uint32_t* buffer_size) { 333 return INVOKE_THUNK(AppendMessageData, message, payload_size, handles, 334 num_handles, options, buffer, buffer_size); 335 } 336 337 MojoResult MojoGetMessageData(MojoMessageHandle message, 338 const MojoGetMessageDataOptions* options, 339 void** buffer, 340 uint32_t* num_bytes, 341 MojoHandle* handles, 342 uint32_t* num_handles) { 343 return INVOKE_THUNK(GetMessageData, message, options, buffer, num_bytes, 344 handles, num_handles); 345 } 346 347 MojoResult MojoSetMessageContext(MojoMessageHandle message, 348 uintptr_t context, 349 MojoMessageContextSerializer serializer, 350 MojoMessageContextDestructor destructor, 351 const MojoSetMessageContextOptions* options) { 352 return INVOKE_THUNK(SetMessageContext, message, context, serializer, 353 destructor, options); 354 } 355 356 MojoResult MojoGetMessageContext(MojoMessageHandle message, 357 const MojoGetMessageContextOptions* options, 358 uintptr_t* context) { 359 return INVOKE_THUNK(GetMessageContext, message, options, context); 360 } 361 362 MojoResult MojoNotifyBadMessage(MojoMessageHandle message, 363 const char* error, 364 uint32_t error_num_bytes, 365 const MojoNotifyBadMessageOptions* options) { 366 return INVOKE_THUNK(NotifyBadMessage, message, error, error_num_bytes, 367 options); 368 } 369 370 MojoResult MojoWrapPlatformHandle(const MojoPlatformHandle* platform_handle, 371 const MojoWrapPlatformHandleOptions* options, 372 MojoHandle* mojo_handle) { 373 return INVOKE_THUNK(WrapPlatformHandle, platform_handle, options, 374 mojo_handle); 375 } 376 377 MojoResult MojoUnwrapPlatformHandle( 378 MojoHandle mojo_handle, 379 const MojoUnwrapPlatformHandleOptions* options, 380 MojoPlatformHandle* platform_handle) { 381 return INVOKE_THUNK(UnwrapPlatformHandle, mojo_handle, options, 382 platform_handle); 383 } 384 385 MojoResult MojoWrapPlatformSharedMemoryRegion( 386 const struct MojoPlatformHandle* platform_handles, 387 uint32_t num_platform_handles, 388 uint64_t num_bytes, 389 const MojoSharedBufferGuid* guid, 390 MojoPlatformSharedMemoryRegionAccessMode access_mode, 391 const MojoWrapPlatformSharedMemoryRegionOptions* options, 392 MojoHandle* mojo_handle) { 393 return INVOKE_THUNK(WrapPlatformSharedMemoryRegion, platform_handles, 394 num_platform_handles, num_bytes, guid, access_mode, 395 options, mojo_handle); 396 } 397 398 MojoResult MojoUnwrapPlatformSharedMemoryRegion( 399 MojoHandle mojo_handle, 400 const MojoUnwrapPlatformSharedMemoryRegionOptions* options, 401 struct MojoPlatformHandle* platform_handles, 402 uint32_t* num_platform_handles, 403 uint64_t* num_bytes, 404 struct MojoSharedBufferGuid* guid, 405 MojoPlatformSharedMemoryRegionAccessMode* access_mode) { 406 return INVOKE_THUNK(UnwrapPlatformSharedMemoryRegion, mojo_handle, options, 407 platform_handles, num_platform_handles, num_bytes, guid, 408 access_mode); 409 } 410 411 MojoResult MojoCreateInvitation(const MojoCreateInvitationOptions* options, 412 MojoHandle* invitation_handle) { 413 return INVOKE_THUNK(CreateInvitation, options, invitation_handle); 414 } 415 416 MojoResult MojoAttachMessagePipeToInvitation( 417 MojoHandle invitation_handle, 418 const void* name, 419 uint32_t name_num_bytes, 420 const MojoAttachMessagePipeToInvitationOptions* options, 421 MojoHandle* message_pipe_handle) { 422 return INVOKE_THUNK(AttachMessagePipeToInvitation, invitation_handle, name, 423 name_num_bytes, options, message_pipe_handle); 424 } 425 426 MojoResult MojoExtractMessagePipeFromInvitation( 427 MojoHandle invitation_handle, 428 const void* name, 429 uint32_t name_num_bytes, 430 const MojoExtractMessagePipeFromInvitationOptions* options, 431 MojoHandle* message_pipe_handle) { 432 return INVOKE_THUNK(ExtractMessagePipeFromInvitation, invitation_handle, name, 433 name_num_bytes, options, message_pipe_handle); 434 } 435 436 MojoResult MojoSendInvitation( 437 MojoHandle invitation_handle, 438 const MojoPlatformProcessHandle* process_handle, 439 const MojoInvitationTransportEndpoint* transport_endpoint, 440 MojoProcessErrorHandler error_handler, 441 uintptr_t error_handler_context, 442 const MojoSendInvitationOptions* options) { 443 return INVOKE_THUNK(SendInvitation, invitation_handle, process_handle, 444 transport_endpoint, error_handler, error_handler_context, 445 options); 446 } 447 448 MojoResult MojoAcceptInvitation( 449 const MojoInvitationTransportEndpoint* transport_endpoint, 450 const MojoAcceptInvitationOptions* options, 451 MojoHandle* invitation_handle) { 452 return INVOKE_THUNK(AcceptInvitation, transport_endpoint, options, 453 invitation_handle); 454 } 455 456 MojoResult MojoSetQuota(MojoHandle handle, 457 MojoQuotaType type, 458 uint64_t limit, 459 const MojoSetQuotaOptions* options) { 460 return INVOKE_THUNK(SetQuota, handle, type, limit, options); 461 } 462 463 MojoResult MojoQueryQuota(MojoHandle handle, 464 MojoQuotaType type, 465 const MojoQueryQuotaOptions* options, 466 uint64_t* limit, 467 uint64_t* usage) { 468 return INVOKE_THUNK(QueryQuota, handle, type, options, limit, usage); 469 } 470 471 } // extern "C" 472 473 void MojoEmbedderSetSystemThunks(const MojoSystemThunks* thunks) { 474 // Assume embedders will always use matching versions of the Mojo Core and 475 // public APIs. 476 DCHECK_EQ(thunks->size, sizeof(*g_thunks)); 477 478 // This should only have to check that the |g_thunks->size| is zero, but we 479 // have multiple Mojo Core initializations in some test suites still. For now 480 // we allow double calls as long as they're the same thunks as before. 481 DCHECK(g_thunks->size == 0 || !memcmp(&*g_thunks, thunks, sizeof(*g_thunks))) 482 << "Cannot set embedder thunks after Mojo API calls have been made."; 483 484 auto writer = base::AutoWritableMemory::Create(g_thunks); 485 *g_thunks = *thunks; 486 } 487