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 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 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 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 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 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 202 Dispatcher::Type SharedBufferDispatcher::GetType() const { 203 return Type::SHARED_BUFFER; 204 } 205 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 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 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 ®ion_, 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 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 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 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 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 385 void SharedBufferDispatcher::CompleteTransitAndClose() { 386 base::AutoLock lock(lock_); 387 in_transit_ = false; 388 region_ = base::subtle::PlatformSharedMemoryRegion(); 389 } 390 391 void SharedBufferDispatcher::CancelTransit() { 392 base::AutoLock lock(lock_); 393 in_transit_ = false; 394 } 395 396 SharedBufferDispatcher::SharedBufferDispatcher( 397 base::subtle::PlatformSharedMemoryRegion region) 398 : region_(std::move(region)) { 399 DCHECK(region_.IsValid()); 400 } 401 402 SharedBufferDispatcher::~SharedBufferDispatcher() { 403 DCHECK(!region_.IsValid() && !in_transit_); 404 } 405 406 // static 407 scoped_refptr<SharedBufferDispatcher> SharedBufferDispatcher::CreateInternal( 408 base::subtle::PlatformSharedMemoryRegion region) { 409 return base::WrapRefCounted(new SharedBufferDispatcher(std::move(region))); 410 } 411 412 // static 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