Home | History | Annotate | Download | only in system
      1 // Copyright 2014 The Chromium Authors. All rights reserved.
      2 // Use of this source code is governed by a BSD-style license that can be
      3 // found in the LICENSE file.
      4 
      5 #include "mojo/edk/system/shared_buffer_dispatcher.h"
      6 
      7 #include <stddef.h>
      8 #include <stdint.h>
      9 
     10 #include <limits>
     11 #include <memory>
     12 #include <utility>
     13 
     14 #include "base/logging.h"
     15 #include "mojo/edk/embedder/embedder_internal.h"
     16 #include "mojo/edk/system/configuration.h"
     17 #include "mojo/edk/system/node_controller.h"
     18 #include "mojo/edk/system/options_validation.h"
     19 
     20 namespace mojo {
     21 namespace edk {
     22 
     23 namespace {
     24 
     25 #pragma pack(push, 1)
     26 
     27 struct SerializedState {
     28   uint64_t num_bytes;
     29   uint32_t flags;
     30   uint32_t padding;
     31 };
     32 
     33 const uint32_t kSerializedStateFlagsReadOnly = 1 << 0;
     34 
     35 #pragma pack(pop)
     36 
     37 static_assert(sizeof(SerializedState) % 8 == 0,
     38               "Invalid SerializedState size.");
     39 
     40 }  // namespace
     41 
     42 // static
     43 const MojoCreateSharedBufferOptions
     44     SharedBufferDispatcher::kDefaultCreateOptions = {
     45         static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)),
     46         MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE};
     47 
     48 // static
     49 MojoResult SharedBufferDispatcher::ValidateCreateOptions(
     50     const MojoCreateSharedBufferOptions* in_options,
     51     MojoCreateSharedBufferOptions* out_options) {
     52   const MojoCreateSharedBufferOptionsFlags kKnownFlags =
     53       MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE;
     54 
     55   *out_options = kDefaultCreateOptions;
     56   if (!in_options)
     57     return MOJO_RESULT_OK;
     58 
     59   UserOptionsReader<MojoCreateSharedBufferOptions> reader(in_options);
     60   if (!reader.is_valid())
     61     return MOJO_RESULT_INVALID_ARGUMENT;
     62 
     63   if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateSharedBufferOptions, flags, reader))
     64     return MOJO_RESULT_OK;
     65   if ((reader.options().flags & ~kKnownFlags))
     66     return MOJO_RESULT_UNIMPLEMENTED;
     67   out_options->flags = reader.options().flags;
     68 
     69   // Checks for fields beyond |flags|:
     70 
     71   // (Nothing here yet.)
     72 
     73   return MOJO_RESULT_OK;
     74 }
     75 
     76 // static
     77 MojoResult SharedBufferDispatcher::Create(
     78     const MojoCreateSharedBufferOptions& /*validated_options*/,
     79     NodeController* node_controller,
     80     uint64_t num_bytes,
     81     scoped_refptr<SharedBufferDispatcher>* result) {
     82   if (!num_bytes)
     83     return MOJO_RESULT_INVALID_ARGUMENT;
     84   if (num_bytes > GetConfiguration().max_shared_memory_num_bytes)
     85     return MOJO_RESULT_RESOURCE_EXHAUSTED;
     86 
     87   scoped_refptr<PlatformSharedBuffer> shared_buffer;
     88   if (node_controller) {
     89     shared_buffer =
     90         node_controller->CreateSharedBuffer(static_cast<size_t>(num_bytes));
     91   } else {
     92     shared_buffer =
     93         PlatformSharedBuffer::Create(static_cast<size_t>(num_bytes));
     94   }
     95   if (!shared_buffer)
     96     return MOJO_RESULT_RESOURCE_EXHAUSTED;
     97 
     98   *result = CreateInternal(std::move(shared_buffer));
     99   return MOJO_RESULT_OK;
    100 }
    101 
    102 // static
    103 MojoResult SharedBufferDispatcher::CreateFromPlatformSharedBuffer(
    104     const scoped_refptr<PlatformSharedBuffer>& shared_buffer,
    105     scoped_refptr<SharedBufferDispatcher>* result) {
    106   if (!shared_buffer)
    107     return MOJO_RESULT_INVALID_ARGUMENT;
    108 
    109   *result = CreateInternal(shared_buffer);
    110   return MOJO_RESULT_OK;
    111 }
    112 
    113 // static
    114 scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize(
    115     const void* bytes,
    116     size_t num_bytes,
    117     const ports::PortName* ports,
    118     size_t num_ports,
    119     PlatformHandle* platform_handles,
    120     size_t num_platform_handles) {
    121   if (num_bytes != sizeof(SerializedState)) {
    122     LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)";
    123     return nullptr;
    124   }
    125 
    126   const SerializedState* serialization =
    127       static_cast<const SerializedState*>(bytes);
    128   if (!serialization->num_bytes) {
    129     LOG(ERROR)
    130         << "Invalid serialized shared buffer dispatcher (invalid num_bytes)";
    131     return nullptr;
    132   }
    133 
    134   if (!platform_handles || num_platform_handles != 1 || num_ports) {
    135     LOG(ERROR)
    136         << "Invalid serialized shared buffer dispatcher (missing handles)";
    137     return nullptr;
    138   }
    139 
    140   // Starts off invalid, which is what we want.
    141   PlatformHandle platform_handle;
    142   // We take ownership of the handle, so we have to invalidate the one in
    143   // |platform_handles|.
    144   std::swap(platform_handle, *platform_handles);
    145 
    146   // Wrapping |platform_handle| in a |ScopedPlatformHandle| means that it'll be
    147   // closed even if creation fails.
    148   bool read_only = (serialization->flags & kSerializedStateFlagsReadOnly);
    149   scoped_refptr<PlatformSharedBuffer> shared_buffer(
    150       PlatformSharedBuffer::CreateFromPlatformHandle(
    151           static_cast<size_t>(serialization->num_bytes), read_only,
    152           ScopedPlatformHandle(platform_handle)));
    153   if (!shared_buffer) {
    154     LOG(ERROR)
    155         << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)";
    156     return nullptr;
    157   }
    158 
    159   return CreateInternal(std::move(shared_buffer));
    160 }
    161 
    162 scoped_refptr<PlatformSharedBuffer>
    163 SharedBufferDispatcher::PassPlatformSharedBuffer() {
    164   base::AutoLock lock(lock_);
    165   if (!shared_buffer_ || in_transit_)
    166     return nullptr;
    167 
    168   scoped_refptr<PlatformSharedBuffer> retval = shared_buffer_;
    169   shared_buffer_ = nullptr;
    170   return retval;
    171 }
    172 
    173 Dispatcher::Type SharedBufferDispatcher::GetType() const {
    174   return Type::SHARED_BUFFER;
    175 }
    176 
    177 MojoResult SharedBufferDispatcher::Close() {
    178   base::AutoLock lock(lock_);
    179   if (in_transit_)
    180     return MOJO_RESULT_INVALID_ARGUMENT;
    181 
    182   shared_buffer_ = nullptr;
    183   return MOJO_RESULT_OK;
    184 }
    185 
    186 MojoResult SharedBufferDispatcher::DuplicateBufferHandle(
    187     const MojoDuplicateBufferHandleOptions* options,
    188     scoped_refptr<Dispatcher>* new_dispatcher) {
    189   MojoDuplicateBufferHandleOptions validated_options;
    190   MojoResult result = ValidateDuplicateOptions(options, &validated_options);
    191   if (result != MOJO_RESULT_OK)
    192     return result;
    193 
    194   // Note: Since this is "duplicate", we keep our ref to |shared_buffer_|.
    195   base::AutoLock lock(lock_);
    196   if (in_transit_)
    197     return MOJO_RESULT_INVALID_ARGUMENT;
    198 
    199   if ((validated_options.flags &
    200        MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY) &&
    201       (!shared_buffer_->IsReadOnly())) {
    202     // If a read-only duplicate is requested and |shared_buffer_| is not
    203     // read-only, make a read-only duplicate of |shared_buffer_|.
    204     scoped_refptr<PlatformSharedBuffer> read_only_buffer =
    205         shared_buffer_->CreateReadOnlyDuplicate();
    206     if (!read_only_buffer)
    207       return MOJO_RESULT_FAILED_PRECONDITION;
    208     DCHECK(read_only_buffer->IsReadOnly());
    209     *new_dispatcher = CreateInternal(std::move(read_only_buffer));
    210     return MOJO_RESULT_OK;
    211   }
    212 
    213   *new_dispatcher = CreateInternal(shared_buffer_);
    214   return MOJO_RESULT_OK;
    215 }
    216 
    217 MojoResult SharedBufferDispatcher::MapBuffer(
    218     uint64_t offset,
    219     uint64_t num_bytes,
    220     MojoMapBufferFlags flags,
    221     std::unique_ptr<PlatformSharedBufferMapping>* mapping) {
    222   if (offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
    223     return MOJO_RESULT_INVALID_ARGUMENT;
    224   if (num_bytes > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
    225     return MOJO_RESULT_INVALID_ARGUMENT;
    226 
    227   base::AutoLock lock(lock_);
    228   DCHECK(shared_buffer_);
    229   if (in_transit_ ||
    230       !shared_buffer_->IsValidMap(static_cast<size_t>(offset),
    231                                   static_cast<size_t>(num_bytes))) {
    232     return MOJO_RESULT_INVALID_ARGUMENT;
    233   }
    234 
    235   DCHECK(mapping);
    236   *mapping = shared_buffer_->MapNoCheck(static_cast<size_t>(offset),
    237                                         static_cast<size_t>(num_bytes));
    238   if (!*mapping) {
    239     LOG(ERROR) << "Unable to map: read_only" << shared_buffer_->IsReadOnly();
    240     return MOJO_RESULT_RESOURCE_EXHAUSTED;
    241   }
    242 
    243   return MOJO_RESULT_OK;
    244 }
    245 
    246 void SharedBufferDispatcher::StartSerialize(uint32_t* num_bytes,
    247                                             uint32_t* num_ports,
    248                                             uint32_t* num_platform_handles) {
    249   *num_bytes = sizeof(SerializedState);
    250   *num_ports = 0;
    251   *num_platform_handles = 1;
    252 }
    253 
    254 bool SharedBufferDispatcher::EndSerialize(void* destination,
    255                                           ports::PortName* ports,
    256                                           PlatformHandle* handles) {
    257   SerializedState* serialization =
    258       static_cast<SerializedState*>(destination);
    259   base::AutoLock lock(lock_);
    260   serialization->num_bytes =
    261         static_cast<uint64_t>(shared_buffer_->GetNumBytes());
    262   serialization->flags =
    263       (shared_buffer_->IsReadOnly() ? kSerializedStateFlagsReadOnly : 0);
    264   serialization->padding = 0;
    265 
    266   handle_for_transit_ = shared_buffer_->DuplicatePlatformHandle();
    267   if (!handle_for_transit_.is_valid()) {
    268     shared_buffer_ = nullptr;
    269     return false;
    270   }
    271   handles[0] = handle_for_transit_.get();
    272   return true;
    273 }
    274 
    275 bool SharedBufferDispatcher::BeginTransit() {
    276   base::AutoLock lock(lock_);
    277   if (in_transit_)
    278     return false;
    279   in_transit_ = static_cast<bool>(shared_buffer_);
    280   return in_transit_;
    281 }
    282 
    283 void SharedBufferDispatcher::CompleteTransitAndClose() {
    284   base::AutoLock lock(lock_);
    285   in_transit_ = false;
    286   shared_buffer_ = nullptr;
    287   ignore_result(handle_for_transit_.release());
    288 }
    289 
    290 void SharedBufferDispatcher::CancelTransit() {
    291   base::AutoLock lock(lock_);
    292   in_transit_ = false;
    293   handle_for_transit_.reset();
    294 }
    295 
    296 SharedBufferDispatcher::SharedBufferDispatcher(
    297     scoped_refptr<PlatformSharedBuffer> shared_buffer)
    298     : shared_buffer_(shared_buffer) {
    299   DCHECK(shared_buffer_);
    300 }
    301 
    302 SharedBufferDispatcher::~SharedBufferDispatcher() {
    303   DCHECK(!shared_buffer_ && !in_transit_);
    304 }
    305 
    306 // static
    307 MojoResult SharedBufferDispatcher::ValidateDuplicateOptions(
    308     const MojoDuplicateBufferHandleOptions* in_options,
    309     MojoDuplicateBufferHandleOptions* out_options) {
    310   const MojoDuplicateBufferHandleOptionsFlags kKnownFlags =
    311       MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_READ_ONLY;
    312   static const MojoDuplicateBufferHandleOptions kDefaultOptions = {
    313       static_cast<uint32_t>(sizeof(MojoDuplicateBufferHandleOptions)),
    314       MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE};
    315 
    316   *out_options = kDefaultOptions;
    317   if (!in_options)
    318     return MOJO_RESULT_OK;
    319 
    320   UserOptionsReader<MojoDuplicateBufferHandleOptions> reader(in_options);
    321   if (!reader.is_valid())
    322     return MOJO_RESULT_INVALID_ARGUMENT;
    323 
    324   if (!OPTIONS_STRUCT_HAS_MEMBER(MojoDuplicateBufferHandleOptions, flags,
    325                                  reader))
    326     return MOJO_RESULT_OK;
    327   if ((reader.options().flags & ~kKnownFlags))
    328     return MOJO_RESULT_UNIMPLEMENTED;
    329   out_options->flags = reader.options().flags;
    330 
    331   // Checks for fields beyond |flags|:
    332 
    333   // (Nothing here yet.)
    334 
    335   return MOJO_RESULT_OK;
    336 }
    337 
    338 }  // namespace edk
    339 }  // namespace mojo
    340