Home | History | Annotate | Download | only in system
      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