• 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/core/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 "base/memory/ptr_util.h"
16 #include "build/build_config.h"
17 #include "mojo/core/configuration.h"
18 #include "mojo/core/node_controller.h"
19 #include "mojo/core/options_validation.h"
20 #include "mojo/core/platform_handle_utils.h"
21 #include "mojo/core/platform_shared_memory_mapping.h"
22 #include "mojo/public/c/system/platform_handle.h"
23 
24 namespace mojo {
25 namespace core {
26 
27 namespace {
28 
29 #pragma pack(push, 1)
30 
31 struct SerializedState {
32   uint64_t num_bytes;
33   uint32_t access_mode;
34   uint64_t guid_high;
35   uint64_t guid_low;
36   uint32_t padding;
37 };
38 
39 #pragma pack(pop)
40 
41 static_assert(sizeof(SerializedState) % 8 == 0,
42               "Invalid SerializedState size.");
43 
44 }  // namespace
45 
46 // static
47 const MojoCreateSharedBufferOptions
48     SharedBufferDispatcher::kDefaultCreateOptions = {
49         static_cast<uint32_t>(sizeof(MojoCreateSharedBufferOptions)),
50         MOJO_CREATE_SHARED_BUFFER_FLAG_NONE};
51 
52 // static
ValidateCreateOptions(const MojoCreateSharedBufferOptions * in_options,MojoCreateSharedBufferOptions * out_options)53 MojoResult SharedBufferDispatcher::ValidateCreateOptions(
54     const MojoCreateSharedBufferOptions* in_options,
55     MojoCreateSharedBufferOptions* out_options) {
56   const MojoCreateSharedBufferFlags kKnownFlags =
57       MOJO_CREATE_SHARED_BUFFER_FLAG_NONE;
58 
59   *out_options = kDefaultCreateOptions;
60   if (!in_options)
61     return MOJO_RESULT_OK;
62 
63   UserOptionsReader<MojoCreateSharedBufferOptions> reader(in_options);
64   if (!reader.is_valid())
65     return MOJO_RESULT_INVALID_ARGUMENT;
66 
67   if (!OPTIONS_STRUCT_HAS_MEMBER(MojoCreateSharedBufferOptions, flags, reader))
68     return MOJO_RESULT_OK;
69   if ((reader.options().flags & ~kKnownFlags))
70     return MOJO_RESULT_UNIMPLEMENTED;
71   out_options->flags = reader.options().flags;
72 
73   // Checks for fields beyond |flags|:
74 
75   // (Nothing here yet.)
76 
77   return MOJO_RESULT_OK;
78 }
79 
80 // static
Create(const MojoCreateSharedBufferOptions &,NodeController * node_controller,uint64_t num_bytes,scoped_refptr<SharedBufferDispatcher> * result)81 MojoResult SharedBufferDispatcher::Create(
82     const MojoCreateSharedBufferOptions& /*validated_options*/,
83     NodeController* node_controller,
84     uint64_t num_bytes,
85     scoped_refptr<SharedBufferDispatcher>* result) {
86   if (!num_bytes)
87     return MOJO_RESULT_INVALID_ARGUMENT;
88   if (num_bytes > GetConfiguration().max_shared_memory_num_bytes)
89     return MOJO_RESULT_RESOURCE_EXHAUSTED;
90 
91   base::WritableSharedMemoryRegion writable_region;
92   if (node_controller) {
93     writable_region =
94         node_controller->CreateSharedBuffer(static_cast<size_t>(num_bytes));
95   } else {
96     writable_region = base::WritableSharedMemoryRegion::Create(
97         static_cast<size_t>(num_bytes));
98   }
99   if (!writable_region.IsValid())
100     return MOJO_RESULT_RESOURCE_EXHAUSTED;
101 
102   *result = CreateInternal(
103       base::WritableSharedMemoryRegion::TakeHandleForSerialization(
104           std::move(writable_region)));
105   return MOJO_RESULT_OK;
106 }
107 
108 // static
CreateFromPlatformSharedMemoryRegion(base::subtle::PlatformSharedMemoryRegion region,scoped_refptr<SharedBufferDispatcher> * result)109 MojoResult SharedBufferDispatcher::CreateFromPlatformSharedMemoryRegion(
110     base::subtle::PlatformSharedMemoryRegion region,
111     scoped_refptr<SharedBufferDispatcher>* result) {
112   if (!region.IsValid())
113     return MOJO_RESULT_INVALID_ARGUMENT;
114 
115   *result = CreateInternal(std::move(region));
116   return MOJO_RESULT_OK;
117 }
118 
119 // 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)120 scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::Deserialize(
121     const void* bytes,
122     size_t num_bytes,
123     const ports::PortName* ports,
124     size_t num_ports,
125     PlatformHandle* platform_handles,
126     size_t num_platform_handles) {
127   if (num_bytes != sizeof(SerializedState)) {
128     LOG(ERROR) << "Invalid serialized shared buffer dispatcher (bad size)";
129     return nullptr;
130   }
131 
132   const SerializedState* serialized_state =
133       static_cast<const SerializedState*>(bytes);
134   if (!serialized_state->num_bytes) {
135     LOG(ERROR)
136         << "Invalid serialized shared buffer dispatcher (invalid num_bytes)";
137     return nullptr;
138   }
139 
140   if (num_ports)
141     return nullptr;
142 
143   PlatformHandle handles[2];
144 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
145     (!defined(OS_MACOSX) || defined(OS_IOS))
146   if (serialized_state->access_mode ==
147       MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) {
148     if (num_platform_handles != 2)
149       return nullptr;
150     handles[1] = std::move(platform_handles[1]);
151   } else {
152     if (num_platform_handles != 1)
153       return nullptr;
154   }
155 #else
156   if (num_platform_handles != 1)
157     return nullptr;
158 #endif
159   handles[0] = std::move(platform_handles[0]);
160 
161   base::UnguessableToken guid = base::UnguessableToken::Deserialize(
162       serialized_state->guid_high, serialized_state->guid_low);
163 
164   base::subtle::PlatformSharedMemoryRegion::Mode mode;
165   switch (serialized_state->access_mode) {
166     case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY:
167       mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly;
168       break;
169     case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE:
170       mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable;
171       break;
172     case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE:
173       mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe;
174       break;
175     default:
176       LOG(ERROR) << "Invalid serialized shared buffer access mode.";
177       return nullptr;
178   }
179 
180   auto region = base::subtle::PlatformSharedMemoryRegion::Take(
181       CreateSharedMemoryRegionHandleFromPlatformHandles(std::move(handles[0]),
182                                                         std::move(handles[1])),
183       mode, static_cast<size_t>(serialized_state->num_bytes), guid);
184   if (!region.IsValid()) {
185     LOG(ERROR)
186         << "Invalid serialized shared buffer dispatcher (invalid num_bytes?)";
187     return nullptr;
188   }
189 
190   return CreateInternal(std::move(region));
191 }
192 
193 base::subtle::PlatformSharedMemoryRegion
PassPlatformSharedMemoryRegion()194 SharedBufferDispatcher::PassPlatformSharedMemoryRegion() {
195   base::AutoLock lock(lock_);
196   if (!region_.IsValid() || in_transit_)
197     return base::subtle::PlatformSharedMemoryRegion();
198 
199   return std::move(region_);
200 }
201 
GetType() const202 Dispatcher::Type SharedBufferDispatcher::GetType() const {
203   return Type::SHARED_BUFFER;
204 }
205 
Close()206 MojoResult SharedBufferDispatcher::Close() {
207   base::AutoLock lock(lock_);
208   if (in_transit_)
209     return MOJO_RESULT_INVALID_ARGUMENT;
210 
211   region_ = base::subtle::PlatformSharedMemoryRegion();
212   return MOJO_RESULT_OK;
213 }
214 
DuplicateBufferHandle(const MojoDuplicateBufferHandleOptions * options,scoped_refptr<Dispatcher> * new_dispatcher)215 MojoResult SharedBufferDispatcher::DuplicateBufferHandle(
216     const MojoDuplicateBufferHandleOptions* options,
217     scoped_refptr<Dispatcher>* new_dispatcher) {
218   MojoDuplicateBufferHandleOptions validated_options;
219   MojoResult result = ValidateDuplicateOptions(options, &validated_options);
220   if (result != MOJO_RESULT_OK)
221     return result;
222 
223   base::AutoLock lock(lock_);
224   if (in_transit_)
225     return MOJO_RESULT_INVALID_ARGUMENT;
226 
227   if ((validated_options.flags & MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY)) {
228     // If a read-only duplicate is requested and this handle is not already
229     // read-only, we need to make it read-only before duplicating. If it's
230     // unsafe it can't be made read-only, and we must fail instead.
231     if (region_.GetMode() ==
232         base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe) {
233       return MOJO_RESULT_FAILED_PRECONDITION;
234     } else if (region_.GetMode() ==
235                base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
236       region_ = base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization(
237           base::WritableSharedMemoryRegion::ConvertToReadOnly(
238               base::WritableSharedMemoryRegion::Deserialize(
239                   std::move(region_))));
240     }
241 
242     DCHECK_EQ(region_.GetMode(),
243               base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly);
244   } else {
245     // A writable duplicate was requested. If this is already a read-only handle
246     // we have to reject. Otherwise we have to convert to unsafe to ensure that
247     // no future read-only duplication requests can succeed.
248     if (region_.GetMode() ==
249         base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly) {
250       return MOJO_RESULT_FAILED_PRECONDITION;
251     } else if (region_.GetMode() ==
252                base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
253       auto handle = region_.PassPlatformHandle();
254 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
255     (!defined(OS_MACOSX) || defined(OS_IOS))
256       // On POSIX systems excluding Android, Fuchsia, and OSX, we explicitly
257       // wipe out the secondary (read-only) FD from the platform handle to
258       // repurpose it for exclusive unsafe usage.
259       handle.readonly_fd.reset();
260 #endif
261       region_ = base::subtle::PlatformSharedMemoryRegion::Take(
262           std::move(handle),
263           base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe,
264           region_.GetSize(), region_.GetGUID());
265     }
266   }
267 
268   *new_dispatcher = CreateInternal(region_.Duplicate());
269   return MOJO_RESULT_OK;
270 }
271 
MapBuffer(uint64_t offset,uint64_t num_bytes,std::unique_ptr<PlatformSharedMemoryMapping> * mapping)272 MojoResult SharedBufferDispatcher::MapBuffer(
273     uint64_t offset,
274     uint64_t num_bytes,
275     std::unique_ptr<PlatformSharedMemoryMapping>* mapping) {
276   if (offset > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
277     return MOJO_RESULT_INVALID_ARGUMENT;
278   if (num_bytes > static_cast<uint64_t>(std::numeric_limits<size_t>::max()))
279     return MOJO_RESULT_INVALID_ARGUMENT;
280 
281   base::AutoLock lock(lock_);
282   DCHECK(region_.IsValid());
283   if (in_transit_ || num_bytes == 0 ||
284       static_cast<size_t>(offset + num_bytes) > region_.GetSize()) {
285     return MOJO_RESULT_INVALID_ARGUMENT;
286   }
287 
288   DCHECK(mapping);
289   *mapping = std::make_unique<PlatformSharedMemoryMapping>(
290       &region_, static_cast<size_t>(offset), static_cast<size_t>(num_bytes));
291   if (!(*mapping)->IsValid()) {
292     LOG(ERROR) << "Failed to map shared memory region.";
293     return MOJO_RESULT_RESOURCE_EXHAUSTED;
294   }
295 
296   return MOJO_RESULT_OK;
297 }
298 
GetBufferInfo(MojoSharedBufferInfo * info)299 MojoResult SharedBufferDispatcher::GetBufferInfo(MojoSharedBufferInfo* info) {
300   if (!info)
301     return MOJO_RESULT_INVALID_ARGUMENT;
302 
303   base::AutoLock lock(lock_);
304   info->struct_size = sizeof(*info);
305   info->size = region_.GetSize();
306   return MOJO_RESULT_OK;
307 }
308 
StartSerialize(uint32_t * num_bytes,uint32_t * num_ports,uint32_t * num_platform_handles)309 void SharedBufferDispatcher::StartSerialize(uint32_t* num_bytes,
310                                             uint32_t* num_ports,
311                                             uint32_t* num_platform_handles) {
312   *num_bytes = sizeof(SerializedState);
313   *num_ports = 0;
314   *num_platform_handles = 1;
315 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
316     (!defined(OS_MACOSX) || defined(OS_IOS))
317   if (region_.GetMode() ==
318       base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
319     *num_platform_handles = 2;
320   }
321 #endif
322 }
323 
EndSerialize(void * destination,ports::PortName * ports,PlatformHandle * handles)324 bool SharedBufferDispatcher::EndSerialize(void* destination,
325                                           ports::PortName* ports,
326                                           PlatformHandle* handles) {
327   SerializedState* serialized_state =
328       static_cast<SerializedState*>(destination);
329   base::AutoLock lock(lock_);
330   serialized_state->num_bytes = region_.GetSize();
331   switch (region_.GetMode()) {
332     case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly:
333       serialized_state->access_mode =
334           MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY;
335       break;
336     case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable:
337       serialized_state->access_mode =
338           MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE;
339       break;
340     case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe:
341       serialized_state->access_mode =
342           MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE;
343       break;
344     default:
345       NOTREACHED();
346       return false;
347   }
348 
349   const base::UnguessableToken& guid = region_.GetGUID();
350   serialized_state->guid_high = guid.GetHighForSerialization();
351   serialized_state->guid_low = guid.GetLowForSerialization();
352   serialized_state->padding = 0;
353 
354   auto region = std::move(region_);
355 #if defined(OS_POSIX) && !defined(OS_ANDROID) && \
356     (!defined(OS_MACOSX) || defined(OS_IOS))
357   if (region.GetMode() ==
358       base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) {
359     PlatformHandle platform_handles[2];
360     ExtractPlatformHandlesFromSharedMemoryRegionHandle(
361         region.PassPlatformHandle(), &platform_handles[0],
362         &platform_handles[1]);
363     handles[0] = std::move(platform_handles[0]);
364     handles[1] = std::move(platform_handles[1]);
365     return true;
366   }
367 #endif
368 
369   PlatformHandle platform_handle;
370   PlatformHandle ignored_handle;
371   ExtractPlatformHandlesFromSharedMemoryRegionHandle(
372       region.PassPlatformHandle(), &platform_handle, &ignored_handle);
373   handles[0] = std::move(platform_handle);
374   return true;
375 }
376 
BeginTransit()377 bool SharedBufferDispatcher::BeginTransit() {
378   base::AutoLock lock(lock_);
379   if (in_transit_)
380     return false;
381   in_transit_ = region_.IsValid();
382   return in_transit_;
383 }
384 
CompleteTransitAndClose()385 void SharedBufferDispatcher::CompleteTransitAndClose() {
386   base::AutoLock lock(lock_);
387   in_transit_ = false;
388   region_ = base::subtle::PlatformSharedMemoryRegion();
389 }
390 
CancelTransit()391 void SharedBufferDispatcher::CancelTransit() {
392   base::AutoLock lock(lock_);
393   in_transit_ = false;
394 }
395 
SharedBufferDispatcher(base::subtle::PlatformSharedMemoryRegion region)396 SharedBufferDispatcher::SharedBufferDispatcher(
397     base::subtle::PlatformSharedMemoryRegion region)
398     : region_(std::move(region)) {
399   DCHECK(region_.IsValid());
400 }
401 
~SharedBufferDispatcher()402 SharedBufferDispatcher::~SharedBufferDispatcher() {
403   DCHECK(!region_.IsValid() && !in_transit_);
404 }
405 
406 // static
CreateInternal(base::subtle::PlatformSharedMemoryRegion region)407 scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::CreateInternal(
408     base::subtle::PlatformSharedMemoryRegion region) {
409   return base::WrapRefCounted(new SharedBufferDispatcher(std::move(region)));
410 }
411 
412 // static
ValidateDuplicateOptions(const MojoDuplicateBufferHandleOptions * in_options,MojoDuplicateBufferHandleOptions * out_options)413 MojoResult SharedBufferDispatcher::ValidateDuplicateOptions(
414     const MojoDuplicateBufferHandleOptions* in_options,
415     MojoDuplicateBufferHandleOptions* out_options) {
416   const MojoDuplicateBufferHandleFlags kKnownFlags =
417       MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_READ_ONLY;
418   static const MojoDuplicateBufferHandleOptions kDefaultOptions = {
419       static_cast<uint32_t>(sizeof(MojoDuplicateBufferHandleOptions)),
420       MOJO_DUPLICATE_BUFFER_HANDLE_FLAG_NONE};
421 
422   *out_options = kDefaultOptions;
423   if (!in_options)
424     return MOJO_RESULT_OK;
425 
426   UserOptionsReader<MojoDuplicateBufferHandleOptions> reader(in_options);
427   if (!reader.is_valid())
428     return MOJO_RESULT_INVALID_ARGUMENT;
429 
430   if (!OPTIONS_STRUCT_HAS_MEMBER(MojoDuplicateBufferHandleOptions, flags,
431                                  reader))
432     return MOJO_RESULT_OK;
433   if ((reader.options().flags & ~kKnownFlags))
434     return MOJO_RESULT_UNIMPLEMENTED;
435   out_options->flags = reader.options().flags;
436 
437   // Checks for fields beyond |flags|:
438 
439   // (Nothing here yet.)
440 
441   return MOJO_RESULT_OK;
442 }
443 
444 }  // namespace core
445 }  // namespace mojo
446