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
20namespace mojo {
21namespace edk {
22
23namespace {
24
25#pragma pack(push, 1)
26
27struct SerializedState {
28  uint64_t num_bytes;
29  uint32_t flags;
30  uint32_t padding;
31};
32
33const uint32_t kSerializedStateFlagsReadOnly = 1 << 0;
34
35#pragma pack(pop)
36
37static_assert(sizeof(SerializedState) % 8 == 0,
38              "Invalid SerializedState size.");
39
40}  // namespace
41
42// static
43const MojoCreateSharedBufferOptions
44    SharedBufferDispatcher::kDefaultCreateOptions = {
45        static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)),
46        MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE};
47
48// static
49MojoResult 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
77MojoResult 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
103MojoResult 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
114scoped_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
162scoped_refptr<PlatformSharedBuffer>
163SharedBufferDispatcher::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
173Dispatcher::Type SharedBufferDispatcher::GetType() const {
174  return Type::SHARED_BUFFER;
175}
176
177MojoResult 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
186MojoResult 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
217MojoResult 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
246void 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
254bool 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
275bool 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
283void SharedBufferDispatcher::CompleteTransitAndClose() {
284  base::AutoLock lock(lock_);
285  in_transit_ = false;
286  shared_buffer_ = nullptr;
287  ignore_result(handle_for_transit_.release());
288}
289
290void SharedBufferDispatcher::CancelTransit() {
291  base::AutoLock lock(lock_);
292  in_transit_ = false;
293  handle_for_transit_.reset();
294}
295
296SharedBufferDispatcher::SharedBufferDispatcher(
297    scoped_refptr<PlatformSharedBuffer> shared_buffer)
298    : shared_buffer_(shared_buffer) {
299  DCHECK(shared_buffer_);
300}
301
302SharedBufferDispatcher::~SharedBufferDispatcher() {
303  DCHECK(!shared_buffer_ && !in_transit_);
304}
305
306// static
307MojoResult 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