• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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
ValidateCreateOptions(const MojoCreateSharedBufferOptions * in_options,MojoCreateSharedBufferOptions * out_options)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
Create(const MojoCreateSharedBufferOptions &,NodeController * node_controller,uint64_t num_bytes,scoped_refptr<SharedBufferDispatcher> * result)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
CreateFromPlatformSharedBuffer(const scoped_refptr<PlatformSharedBuffer> & shared_buffer,scoped_refptr<SharedBufferDispatcher> * result)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
Deserialize(const void * bytes,size_t num_bytes,const ports::PortName * ports,size_t num_ports,PlatformHandle * platform_handles,size_t num_platform_handles)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>
PassPlatformSharedBuffer()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 
GetType() const173 Dispatcher::Type SharedBufferDispatcher::GetType() const {
174   return Type::SHARED_BUFFER;
175 }
176 
Close()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 
DuplicateBufferHandle(const MojoDuplicateBufferHandleOptions * options,scoped_refptr<Dispatcher> * new_dispatcher)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 
MapBuffer(uint64_t offset,uint64_t num_bytes,MojoMapBufferFlags flags,std::unique_ptr<PlatformSharedBufferMapping> * mapping)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 
StartSerialize(uint32_t * num_bytes,uint32_t * num_ports,uint32_t * num_platform_handles)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 
EndSerialize(void * destination,ports::PortName * ports,PlatformHandle * handles)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 
BeginTransit()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 
CompleteTransitAndClose()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 
CancelTransit()290 void SharedBufferDispatcher::CancelTransit() {
291   base::AutoLock lock(lock_);
292   in_transit_ = false;
293   handle_for_transit_.reset();
294 }
295 
SharedBufferDispatcher(scoped_refptr<PlatformSharedBuffer> shared_buffer)296 SharedBufferDispatcher::SharedBufferDispatcher(
297     scoped_refptr<PlatformSharedBuffer> shared_buffer)
298     : shared_buffer_(shared_buffer) {
299   DCHECK(shared_buffer_);
300 }
301 
~SharedBufferDispatcher()302 SharedBufferDispatcher::~SharedBufferDispatcher() {
303   DCHECK(!shared_buffer_ && !in_transit_);
304 }
305 
306 // static
ValidateDuplicateOptions(const MojoDuplicateBufferHandleOptions * in_options,MojoDuplicateBufferHandleOptions * out_options)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