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