• 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/system/shared_buffer_dispatcher.h"
6 
7 #include <limits>
8 
9 #include "base/logging.h"
10 #include "base/memory/scoped_ptr.h"
11 #include "mojo/embedder/platform_support.h"
12 #include "mojo/public/c/system/macros.h"
13 #include "mojo/system/channel.h"
14 #include "mojo/system/constants.h"
15 #include "mojo/system/memory.h"
16 #include "mojo/system/options_validation.h"
17 
18 namespace mojo {
19 namespace system {
20 
21 namespace {
22 
23 struct SerializedSharedBufferDispatcher {
24   size_t num_bytes;
25   size_t platform_handle_index;
26 };
27 
28 }  // namespace
29 
30 // static
31 const MojoCreateSharedBufferOptions
32     SharedBufferDispatcher::kDefaultCreateOptions = {
33         static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)),
34         MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE};
35 
36 // static
ValidateCreateOptions(UserPointer<const MojoCreateSharedBufferOptions> in_options,MojoCreateSharedBufferOptions * out_options)37 MojoResult SharedBufferDispatcher::ValidateCreateOptions(
38     UserPointer<const MojoCreateSharedBufferOptions> in_options,
39     MojoCreateSharedBufferOptions* out_options) {
40   const MojoCreateSharedBufferOptionsFlags kKnownFlags =
41       MOJO_CREATE_SHARED_BUFFER_OPTIONS_FLAG_NONE;
42 
43   *out_options = kDefaultCreateOptions;
44   if (in_options.IsNull())
45     return MOJO_RESULT_OK;
46 
47   UserOptionsReader<MojoCreateSharedBufferOptions> reader(in_options);
48   if (!reader.is_valid())
49     return MOJO_RESULT_INVALID_ARGUMENT;
50 
51   if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateSharedBufferOptions, flags, reader))
52     return MOJO_RESULT_OK;
53   if ((reader.options().flags & ~kKnownFlags))
54     return MOJO_RESULT_UNIMPLEMENTED;
55   out_options->flags = reader.options().flags;
56 
57   // Checks for fields beyond |flags|:
58 
59   // (Nothing here yet.)
60 
61   return MOJO_RESULT_OK;
62 }
63 
64 // static
Create(embedder::PlatformSupport * platform_support,const MojoCreateSharedBufferOptions &,uint64_t num_bytes,scoped_refptr<SharedBufferDispatcher> * result)65 MojoResult SharedBufferDispatcher::Create(
66     embedder::PlatformSupport* platform_support,
67     const MojoCreateSharedBufferOptions& /*validated_options*/,
68     uint64_t num_bytes,
69     scoped_refptr<SharedBufferDispatcher>* result) {
70   if (!num_bytes)
71     return MOJO_RESULT_INVALID_ARGUMENT;
72   if (num_bytes > kMaxSharedMemoryNumBytes)
73     return MOJO_RESULT_RESOURCE_EXHAUSTED;
74 
75   scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer(
76       platform_support->CreateSharedBuffer(static_cast<size_t>(num_bytes)));
77   if (!shared_buffer.get())
78     return MOJO_RESULT_RESOURCE_EXHAUSTED;
79 
80   *result = new SharedBufferDispatcher(shared_buffer);
81   return MOJO_RESULT_OK;
82 }
83 
GetType() const84 Dispatcher::Type SharedBufferDispatcher::GetType() const {
85   return kTypeSharedBuffer;
86 }
87 
88 // static
Deserialize(Channel * channel,const void * source,size_t size,embedder::PlatformHandleVector * platform_handles)89 scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize(
90     Channel* channel,
91     const void* source,
92     size_t size,
93     embedder::PlatformHandleVector* platform_handles) {
94   DCHECK(channel);
95 
96   if (size != sizeof(SerializedSharedBufferDispatcher)) {
97     LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)";
98     return scoped_refptr<SharedBufferDispatcher>();
99   }
100 
101   const SerializedSharedBufferDispatcher* serialization =
102       static_cast<const SerializedSharedBufferDispatcher*>(source);
103   size_t num_bytes = serialization->num_bytes;
104   size_t platform_handle_index = serialization->platform_handle_index;
105 
106   if (!num_bytes) {
107     LOG(ERROR)
108         << "Invalid serialized shared buffer dispatcher (invalid num_bytes)";
109     return scoped_refptr<SharedBufferDispatcher>();
110   }
111 
112   if (!platform_handles || platform_handle_index >= platform_handles->size()) {
113     LOG(ERROR)
114         << "Invalid serialized shared buffer dispatcher (missing handles)";
115     return scoped_refptr<SharedBufferDispatcher>();
116   }
117 
118   // Starts off invalid, which is what we want.
119   embedder::PlatformHandle platform_handle;
120   // We take ownership of the handle, so we have to invalidate the one in
121   // |platform_handles|.
122   std::swap(platform_handle, (*platform_handles)[platform_handle_index]);
123 
124   // Wrapping |platform_handle| in a |ScopedPlatformHandle| means that it'll be
125   // closed even if creation fails.
126   scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer(
127       channel->platform_support()->CreateSharedBufferFromHandle(
128           num_bytes, embedder::ScopedPlatformHandle(platform_handle)));
129   if (!shared_buffer.get()) {
130     LOG(ERROR)
131         << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)";
132     return scoped_refptr<SharedBufferDispatcher>();
133   }
134 
135   return scoped_refptr<SharedBufferDispatcher>(
136       new SharedBufferDispatcher(shared_buffer));
137 }
138 
SharedBufferDispatcher(scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer)139 SharedBufferDispatcher::SharedBufferDispatcher(
140     scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer)
141     : shared_buffer_(shared_buffer) {
142   DCHECK(shared_buffer_.get());
143 }
144 
~SharedBufferDispatcher()145 SharedBufferDispatcher::~SharedBufferDispatcher() {
146 }
147 
148 // static
ValidateDuplicateOptions(UserPointer<const MojoDuplicateBufferHandleOptions> in_options,MojoDuplicateBufferHandleOptions * out_options)149 MojoResult SharedBufferDispatcher::ValidateDuplicateOptions(
150     UserPointer<const MojoDuplicateBufferHandleOptions> in_options,
151     MojoDuplicateBufferHandleOptions* out_options) {
152   const MojoDuplicateBufferHandleOptionsFlags kKnownFlags =
153       MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE;
154   static const MojoDuplicateBufferHandleOptions kDefaultOptions = {
155       static_cast<uint32_t>(sizeof(MojoDuplicateBufferHandleOptions)),
156       MOJO_DUPLICATE_BUFFER_HANDLE_OPTIONS_FLAG_NONE};
157 
158   *out_options = kDefaultOptions;
159   if (in_options.IsNull())
160     return MOJO_RESULT_OK;
161 
162   UserOptionsReader<MojoDuplicateBufferHandleOptions> reader(in_options);
163   if (!reader.is_valid())
164     return MOJO_RESULT_INVALID_ARGUMENT;
165 
166   if (!OPTIONS_STRUCT_HAS_MEMBER(
167           MojoDuplicateBufferHandleOptions, flags, reader))
168     return MOJO_RESULT_OK;
169   if ((reader.options().flags & ~kKnownFlags))
170     return MOJO_RESULT_UNIMPLEMENTED;
171   out_options->flags = reader.options().flags;
172 
173   // Checks for fields beyond |flags|:
174 
175   // (Nothing here yet.)
176 
177   return MOJO_RESULT_OK;
178 }
179 
CloseImplNoLock()180 void SharedBufferDispatcher::CloseImplNoLock() {
181   lock().AssertAcquired();
182   DCHECK(shared_buffer_.get());
183   shared_buffer_ = nullptr;
184 }
185 
186 scoped_refptr<Dispatcher>
CreateEquivalentDispatcherAndCloseImplNoLock()187 SharedBufferDispatcher::CreateEquivalentDispatcherAndCloseImplNoLock() {
188   lock().AssertAcquired();
189   DCHECK(shared_buffer_.get());
190   scoped_refptr<embedder::PlatformSharedBuffer> shared_buffer;
191   shared_buffer.swap(shared_buffer_);
192   return scoped_refptr<Dispatcher>(new SharedBufferDispatcher(shared_buffer));
193 }
194 
DuplicateBufferHandleImplNoLock(UserPointer<const MojoDuplicateBufferHandleOptions> options,scoped_refptr<Dispatcher> * new_dispatcher)195 MojoResult SharedBufferDispatcher::DuplicateBufferHandleImplNoLock(
196     UserPointer<const MojoDuplicateBufferHandleOptions> options,
197     scoped_refptr<Dispatcher>* new_dispatcher) {
198   lock().AssertAcquired();
199 
200   MojoDuplicateBufferHandleOptions validated_options;
201   MojoResult result = ValidateDuplicateOptions(options, &validated_options);
202   if (result != MOJO_RESULT_OK)
203     return result;
204 
205   *new_dispatcher = new SharedBufferDispatcher(shared_buffer_);
206   return MOJO_RESULT_OK;
207 }
208 
MapBufferImplNoLock(uint64_t offset,uint64_t num_bytes,MojoMapBufferFlags flags,scoped_ptr<embedder::PlatformSharedBufferMapping> * mapping)209 MojoResult SharedBufferDispatcher::MapBufferImplNoLock(
210     uint64_t offset,
211     uint64_t num_bytes,
212     MojoMapBufferFlags flags,
213     scoped_ptr<embedder::PlatformSharedBufferMapping>* mapping) {
214   lock().AssertAcquired();
215   DCHECK(shared_buffer_.get());
216 
217   if (offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
218     return MOJO_RESULT_INVALID_ARGUMENT;
219   if (num_bytes > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
220     return MOJO_RESULT_INVALID_ARGUMENT;
221 
222   if (!shared_buffer_->IsValidMap(static_cast<size_t>(offset),
223                                   static_cast<size_t>(num_bytes)))
224     return MOJO_RESULT_INVALID_ARGUMENT;
225 
226   DCHECK(mapping);
227   *mapping = shared_buffer_->MapNoCheck(static_cast<size_t>(offset),
228                                         static_cast<size_t>(num_bytes));
229   if (!*mapping)
230     return MOJO_RESULT_RESOURCE_EXHAUSTED;
231 
232   return MOJO_RESULT_OK;
233 }
234 
StartSerializeImplNoLock(Channel *,size_t * max_size,size_t * max_platform_handles)235 void SharedBufferDispatcher::StartSerializeImplNoLock(
236     Channel* /*channel*/,
237     size_t* max_size,
238     size_t* max_platform_handles) {
239   DCHECK(HasOneRef());  // Only one ref => no need to take the lock.
240   *max_size = sizeof(SerializedSharedBufferDispatcher);
241   *max_platform_handles = 1;
242 }
243 
EndSerializeAndCloseImplNoLock(Channel *,void * destination,size_t * actual_size,embedder::PlatformHandleVector * platform_handles)244 bool SharedBufferDispatcher::EndSerializeAndCloseImplNoLock(
245     Channel* /*channel*/,
246     void* destination,
247     size_t* actual_size,
248     embedder::PlatformHandleVector* platform_handles) {
249   DCHECK(HasOneRef());  // Only one ref => no need to take the lock.
250   DCHECK(shared_buffer_.get());
251 
252   SerializedSharedBufferDispatcher* serialization =
253       static_cast<SerializedSharedBufferDispatcher*>(destination);
254   // If there's only one reference to |shared_buffer_|, then it's ours (and no
255   // one else can make any more references to it), so we can just take its
256   // handle.
257   embedder::ScopedPlatformHandle platform_handle(
258       shared_buffer_->HasOneRef() ? shared_buffer_->PassPlatformHandle()
259                                   : shared_buffer_->DuplicatePlatformHandle());
260   if (!platform_handle.is_valid()) {
261     shared_buffer_ = nullptr;
262     return false;
263   }
264 
265   serialization->num_bytes = shared_buffer_->GetNumBytes();
266   serialization->platform_handle_index = platform_handles->size();
267   platform_handles->push_back(platform_handle.release());
268   *actual_size = sizeof(SerializedSharedBufferDispatcher);
269 
270   shared_buffer_ = nullptr;
271 
272   return true;
273 }
274 
275 }  // namespace system
276 }  // namespace mojo
277