1 // Copyright 2016 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/public/cpp/system/platform_handle.h" 6 7 #include "base/memory/platform_shared_memory_region.h" 8 #include "base/numerics/safe_conversions.h" 9 #include "build/build_config.h" 10 11 #if defined(OS_MACOSX) && !defined(OS_IOS) 12 #include <mach/mach.h> 13 #include "base/mac/mach_logging.h" 14 #endif 15 16 namespace mojo { 17 18 namespace { 19 20 uint64_t PlatformHandleValueFromPlatformFile(base::PlatformFile file) { 21 #if defined(OS_WIN) 22 return reinterpret_cast<uint64_t>(file); 23 #else 24 return static_cast<uint64_t>(file); 25 #endif 26 } 27 28 base::PlatformFile PlatformFileFromPlatformHandleValue(uint64_t value) { 29 #if defined(OS_WIN) 30 return reinterpret_cast<base::PlatformFile>(value); 31 #else 32 return static_cast<base::PlatformFile>(value); 33 #endif 34 } 35 36 ScopedSharedBufferHandle WrapPlatformSharedMemoryRegion( 37 base::subtle::PlatformSharedMemoryRegion region) { 38 if (!region.IsValid()) 39 return ScopedSharedBufferHandle(); 40 41 MojoPlatformSharedMemoryRegionAccessMode access_mode; 42 switch (region.GetMode()) { 43 case base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly: 44 access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY; 45 break; 46 case base::subtle::PlatformSharedMemoryRegion::Mode::kWritable: 47 access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE; 48 break; 49 case base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe: 50 access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE; 51 break; 52 default: 53 NOTREACHED(); 54 return ScopedSharedBufferHandle(); 55 } 56 57 base::subtle::PlatformSharedMemoryRegion::ScopedPlatformHandle handle = 58 region.PassPlatformHandle(); 59 MojoPlatformHandle platform_handles[2]; 60 uint32_t num_platform_handles = 1; 61 platform_handles[0].struct_size = sizeof(platform_handles[0]); 62 #if defined(OS_WIN) 63 platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE; 64 platform_handles[0].value = reinterpret_cast<uint64_t>(handle.Take()); 65 #elif defined(OS_FUCHSIA) 66 platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE; 67 platform_handles[0].value = static_cast<uint64_t>(handle.release()); 68 #elif defined(OS_MACOSX) && !defined(OS_IOS) 69 platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT; 70 platform_handles[0].value = static_cast<uint64_t>(handle.release()); 71 #elif defined(OS_ANDROID) 72 platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR; 73 platform_handles[0].value = static_cast<uint64_t>(handle.release()); 74 #else 75 platform_handles[0].type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR; 76 platform_handles[0].value = static_cast<uint64_t>(handle.fd.release()); 77 78 if (region.GetMode() == 79 base::subtle::PlatformSharedMemoryRegion::Mode::kWritable) { 80 num_platform_handles = 2; 81 platform_handles[1].struct_size = sizeof(platform_handles[1]); 82 platform_handles[1].type = MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR; 83 platform_handles[1].value = 84 static_cast<uint64_t>(handle.readonly_fd.release()); 85 } 86 #endif 87 const auto& guid = region.GetGUID(); 88 MojoSharedBufferGuid mojo_guid = {guid.GetHighForSerialization(), 89 guid.GetLowForSerialization()}; 90 MojoHandle mojo_handle; 91 MojoResult result = MojoWrapPlatformSharedMemoryRegion( 92 platform_handles, num_platform_handles, region.GetSize(), &mojo_guid, 93 access_mode, nullptr, &mojo_handle); 94 if (result != MOJO_RESULT_OK) 95 return ScopedSharedBufferHandle(); 96 return ScopedSharedBufferHandle(SharedBufferHandle(mojo_handle)); 97 } 98 99 base::subtle::PlatformSharedMemoryRegion UnwrapPlatformSharedMemoryRegion( 100 ScopedSharedBufferHandle mojo_handle) { 101 if (!mojo_handle.is_valid()) 102 return base::subtle::PlatformSharedMemoryRegion(); 103 104 MojoPlatformHandle platform_handles[2]; 105 platform_handles[0].struct_size = sizeof(platform_handles[0]); 106 platform_handles[1].struct_size = sizeof(platform_handles[1]); 107 uint32_t num_platform_handles = 2; 108 uint64_t size; 109 MojoSharedBufferGuid mojo_guid; 110 MojoPlatformSharedMemoryRegionAccessMode access_mode; 111 MojoResult result = MojoUnwrapPlatformSharedMemoryRegion( 112 mojo_handle.release().value(), nullptr, platform_handles, 113 &num_platform_handles, &size, &mojo_guid, &access_mode); 114 if (result != MOJO_RESULT_OK) 115 return base::subtle::PlatformSharedMemoryRegion(); 116 117 base::subtle::PlatformSharedMemoryRegion::ScopedPlatformHandle region_handle; 118 #if defined(OS_WIN) 119 if (num_platform_handles != 1) 120 return base::subtle::PlatformSharedMemoryRegion(); 121 if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE) 122 return base::subtle::PlatformSharedMemoryRegion(); 123 region_handle.Set(reinterpret_cast<HANDLE>(platform_handles[0].value)); 124 #elif defined(OS_FUCHSIA) 125 if (num_platform_handles != 1) 126 return base::subtle::PlatformSharedMemoryRegion(); 127 if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE) 128 return base::subtle::PlatformSharedMemoryRegion(); 129 region_handle.reset(static_cast<zx_handle_t>(platform_handles[0].value)); 130 #elif defined(OS_MACOSX) && !defined(OS_IOS) 131 if (num_platform_handles != 1) 132 return base::subtle::PlatformSharedMemoryRegion(); 133 if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT) 134 return base::subtle::PlatformSharedMemoryRegion(); 135 region_handle.reset(static_cast<mach_port_t>(platform_handles[0].value)); 136 #elif defined(OS_ANDROID) 137 if (num_platform_handles != 1) 138 return base::subtle::PlatformSharedMemoryRegion(); 139 if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR) 140 return base::subtle::PlatformSharedMemoryRegion(); 141 region_handle.reset(static_cast<int>(platform_handles[0].value)); 142 #else 143 if (access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) { 144 if (num_platform_handles != 2) 145 return base::subtle::PlatformSharedMemoryRegion(); 146 } else if (num_platform_handles != 1) { 147 return base::subtle::PlatformSharedMemoryRegion(); 148 } 149 if (platform_handles[0].type != MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR) 150 return base::subtle::PlatformSharedMemoryRegion(); 151 region_handle.fd.reset(static_cast<int>(platform_handles[0].value)); 152 if (num_platform_handles == 2) { 153 if (platform_handles[1].type != MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR) 154 return base::subtle::PlatformSharedMemoryRegion(); 155 region_handle.readonly_fd.reset( 156 static_cast<int>(platform_handles[1].value)); 157 } 158 #endif 159 160 base::subtle::PlatformSharedMemoryRegion::Mode mode; 161 switch (access_mode) { 162 case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY: 163 mode = base::subtle::PlatformSharedMemoryRegion::Mode::kReadOnly; 164 break; 165 case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE: 166 mode = base::subtle::PlatformSharedMemoryRegion::Mode::kWritable; 167 break; 168 case MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE: 169 mode = base::subtle::PlatformSharedMemoryRegion::Mode::kUnsafe; 170 break; 171 default: 172 return base::subtle::PlatformSharedMemoryRegion(); 173 } 174 175 return base::subtle::PlatformSharedMemoryRegion::Take( 176 std::move(region_handle), mode, size, 177 base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low)); 178 } 179 180 } // namespace 181 182 ScopedHandle WrapPlatformHandle(PlatformHandle handle) { 183 MojoPlatformHandle platform_handle; 184 PlatformHandle::ToMojoPlatformHandle(std::move(handle), &platform_handle); 185 186 MojoHandle wrapped_handle; 187 MojoResult result = 188 MojoWrapPlatformHandle(&platform_handle, nullptr, &wrapped_handle); 189 if (result != MOJO_RESULT_OK) 190 return ScopedHandle(); 191 return ScopedHandle(Handle(wrapped_handle)); 192 } 193 194 PlatformHandle UnwrapPlatformHandle(ScopedHandle handle) { 195 MojoPlatformHandle platform_handle; 196 platform_handle.struct_size = sizeof(platform_handle); 197 MojoResult result = MojoUnwrapPlatformHandle(handle.release().value(), 198 nullptr, &platform_handle); 199 if (result != MOJO_RESULT_OK) 200 return PlatformHandle(); 201 return PlatformHandle::FromMojoPlatformHandle(&platform_handle); 202 } 203 204 // Wraps a PlatformFile as a Mojo handle. Takes ownership of the file object. 205 ScopedHandle WrapPlatformFile(base::PlatformFile platform_file) { 206 MojoPlatformHandle platform_handle; 207 platform_handle.struct_size = sizeof(MojoPlatformHandle); 208 platform_handle.type = kPlatformFileHandleType; 209 platform_handle.value = PlatformHandleValueFromPlatformFile(platform_file); 210 211 MojoHandle mojo_handle; 212 MojoResult result = 213 MojoWrapPlatformHandle(&platform_handle, nullptr, &mojo_handle); 214 CHECK_EQ(result, MOJO_RESULT_OK); 215 216 return ScopedHandle(Handle(mojo_handle)); 217 } 218 219 MojoResult UnwrapPlatformFile(ScopedHandle handle, base::PlatformFile* file) { 220 MojoPlatformHandle platform_handle; 221 platform_handle.struct_size = sizeof(MojoPlatformHandle); 222 MojoResult result = MojoUnwrapPlatformHandle(handle.release().value(), 223 nullptr, &platform_handle); 224 if (result != MOJO_RESULT_OK) 225 return result; 226 227 if (platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_INVALID) { 228 *file = base::kInvalidPlatformFile; 229 } else { 230 CHECK_EQ(platform_handle.type, kPlatformFileHandleType); 231 *file = PlatformFileFromPlatformHandleValue(platform_handle.value); 232 } 233 234 return MOJO_RESULT_OK; 235 } 236 237 ScopedSharedBufferHandle WrapSharedMemoryHandle( 238 const base::SharedMemoryHandle& memory_handle, 239 size_t size, 240 UnwrappedSharedMemoryHandleProtection protection) { 241 if (!memory_handle.IsValid()) 242 return ScopedSharedBufferHandle(); 243 MojoPlatformHandle platform_handle; 244 platform_handle.struct_size = sizeof(MojoPlatformHandle); 245 platform_handle.type = kPlatformSharedBufferHandleType; 246 #if defined(OS_MACOSX) && !defined(OS_IOS) 247 platform_handle.value = 248 static_cast<uint64_t>(memory_handle.GetMemoryObject()); 249 #else 250 platform_handle.value = 251 PlatformHandleValueFromPlatformFile(memory_handle.GetHandle()); 252 #endif 253 254 MojoPlatformSharedMemoryRegionAccessMode access_mode = 255 MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_UNSAFE; 256 if (protection == UnwrappedSharedMemoryHandleProtection::kReadOnly) { 257 access_mode = MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY; 258 259 #if defined(OS_ANDROID) 260 // Many callers assume that base::SharedMemory::GetReadOnlyHandle() gives 261 // them a handle which is actually read-only. This assumption is invalid on 262 // Android. As a precursor to migrating all base::SharedMemory usage -- 263 // including Mojo internals -- to the new base shared memory API, we ensure 264 // that regions are set to read-only if any of their handles are wrapped 265 // read-only. This relies on existing usages not attempting to map the 266 // region writable any time after this call. 267 if (!memory_handle.IsRegionReadOnly()) 268 memory_handle.SetRegionReadOnly(); 269 #endif 270 } 271 272 MojoSharedBufferGuid guid; 273 guid.high = memory_handle.GetGUID().GetHighForSerialization(); 274 guid.low = memory_handle.GetGUID().GetLowForSerialization(); 275 MojoHandle mojo_handle; 276 MojoResult result = MojoWrapPlatformSharedMemoryRegion( 277 &platform_handle, 1, size, &guid, access_mode, nullptr, &mojo_handle); 278 CHECK_EQ(result, MOJO_RESULT_OK); 279 280 return ScopedSharedBufferHandle(SharedBufferHandle(mojo_handle)); 281 } 282 283 MojoResult UnwrapSharedMemoryHandle( 284 ScopedSharedBufferHandle handle, 285 base::SharedMemoryHandle* memory_handle, 286 size_t* size, 287 UnwrappedSharedMemoryHandleProtection* protection) { 288 if (!handle.is_valid()) 289 return MOJO_RESULT_INVALID_ARGUMENT; 290 MojoPlatformHandle platform_handles[2]; 291 platform_handles[0].struct_size = sizeof(platform_handles[0]); 292 platform_handles[1].struct_size = sizeof(platform_handles[1]); 293 294 uint32_t num_platform_handles = 2; 295 uint64_t num_bytes; 296 MojoSharedBufferGuid mojo_guid; 297 MojoPlatformSharedMemoryRegionAccessMode access_mode; 298 MojoResult result = MojoUnwrapPlatformSharedMemoryRegion( 299 handle.release().value(), nullptr, platform_handles, 300 &num_platform_handles, &num_bytes, &mojo_guid, &access_mode); 301 if (result != MOJO_RESULT_OK) 302 return result; 303 304 if (size) { 305 DCHECK(base::IsValueInRangeForNumericType<size_t>(num_bytes)); 306 *size = static_cast<size_t>(num_bytes); 307 } 308 309 if (protection) { 310 *protection = 311 access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_READ_ONLY 312 ? UnwrappedSharedMemoryHandleProtection::kReadOnly 313 : UnwrappedSharedMemoryHandleProtection::kReadWrite; 314 } 315 316 base::UnguessableToken guid = 317 base::UnguessableToken::Deserialize(mojo_guid.high, mojo_guid.low); 318 #if defined(OS_MACOSX) && !defined(OS_IOS) 319 DCHECK_EQ(platform_handles[0].type, MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT); 320 DCHECK_EQ(num_platform_handles, 1u); 321 *memory_handle = base::SharedMemoryHandle( 322 static_cast<mach_port_t>(platform_handles[0].value), num_bytes, guid); 323 #elif defined(OS_FUCHSIA) 324 DCHECK_EQ(platform_handles[0].type, MOJO_PLATFORM_HANDLE_TYPE_FUCHSIA_HANDLE); 325 DCHECK_EQ(num_platform_handles, 1u); 326 *memory_handle = base::SharedMemoryHandle( 327 static_cast<zx_handle_t>(platform_handles[0].value), num_bytes, guid); 328 #elif defined(OS_POSIX) 329 DCHECK_EQ(platform_handles[0].type, 330 MOJO_PLATFORM_HANDLE_TYPE_FILE_DESCRIPTOR); 331 *memory_handle = base::SharedMemoryHandle( 332 base::FileDescriptor(static_cast<int>(platform_handles[0].value), false), 333 num_bytes, guid); 334 #if !defined(OS_ANDROID) 335 if (access_mode == MOJO_PLATFORM_SHARED_MEMORY_REGION_ACCESS_MODE_WRITABLE) { 336 DCHECK_EQ(num_platform_handles, 2u); 337 // When unwrapping as a base::SharedMemoryHandle, make sure to discard the 338 // extra file descriptor if the region is writable. base::SharedMemoryHandle 339 // effectively only supports read-only and unsafe usage modes when wrapping 340 // or unwrapping to and from Mojo handles. 341 base::ScopedFD discarded_readonly_fd( 342 static_cast<int>(platform_handles[1].value)); 343 } else { 344 DCHECK_EQ(num_platform_handles, 1u); 345 } 346 #else // !defined(OS_ANDROID) 347 DCHECK_EQ(num_platform_handles, 1u); 348 #endif // !defined(OS_ANDROID) 349 #elif defined(OS_WIN) 350 DCHECK_EQ(platform_handles[0].type, MOJO_PLATFORM_HANDLE_TYPE_WINDOWS_HANDLE); 351 DCHECK_EQ(num_platform_handles, 1u); 352 *memory_handle = base::SharedMemoryHandle( 353 reinterpret_cast<HANDLE>(platform_handles[0].value), num_bytes, guid); 354 #endif 355 356 return MOJO_RESULT_OK; 357 } 358 359 ScopedSharedBufferHandle WrapReadOnlySharedMemoryRegion( 360 base::ReadOnlySharedMemoryRegion region) { 361 return WrapPlatformSharedMemoryRegion( 362 base::ReadOnlySharedMemoryRegion::TakeHandleForSerialization( 363 std::move(region))); 364 } 365 366 ScopedSharedBufferHandle WrapUnsafeSharedMemoryRegion( 367 base::UnsafeSharedMemoryRegion region) { 368 return WrapPlatformSharedMemoryRegion( 369 base::UnsafeSharedMemoryRegion::TakeHandleForSerialization( 370 std::move(region))); 371 } 372 373 ScopedSharedBufferHandle WrapWritableSharedMemoryRegion( 374 base::WritableSharedMemoryRegion region) { 375 return WrapPlatformSharedMemoryRegion( 376 base::WritableSharedMemoryRegion::TakeHandleForSerialization( 377 std::move(region))); 378 } 379 380 base::ReadOnlySharedMemoryRegion UnwrapReadOnlySharedMemoryRegion( 381 ScopedSharedBufferHandle handle) { 382 return base::ReadOnlySharedMemoryRegion::Deserialize( 383 UnwrapPlatformSharedMemoryRegion(std::move(handle))); 384 } 385 386 base::UnsafeSharedMemoryRegion UnwrapUnsafeSharedMemoryRegion( 387 ScopedSharedBufferHandle handle) { 388 return base::UnsafeSharedMemoryRegion::Deserialize( 389 UnwrapPlatformSharedMemoryRegion(std::move(handle))); 390 } 391 392 base::WritableSharedMemoryRegion UnwrapWritableSharedMemoryRegion( 393 ScopedSharedBufferHandle handle) { 394 return base::WritableSharedMemoryRegion::Deserialize( 395 UnwrapPlatformSharedMemoryRegion(std::move(handle))); 396 } 397 398 #if defined(OS_MACOSX) && !defined(OS_IOS) 399 ScopedHandle WrapMachPort(mach_port_t port) { 400 kern_return_t kr = 401 mach_port_mod_refs(mach_task_self(), port, MACH_PORT_RIGHT_SEND, 1); 402 MACH_LOG_IF(ERROR, kr != KERN_SUCCESS, kr) 403 << "MachPortAttachmentMac mach_port_mod_refs"; 404 if (kr != KERN_SUCCESS) 405 return ScopedHandle(); 406 407 MojoPlatformHandle platform_handle; 408 platform_handle.struct_size = sizeof(MojoPlatformHandle); 409 platform_handle.type = MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT; 410 platform_handle.value = static_cast<uint64_t>(port); 411 412 MojoHandle mojo_handle; 413 MojoResult result = 414 MojoWrapPlatformHandle(&platform_handle, nullptr, &mojo_handle); 415 CHECK_EQ(result, MOJO_RESULT_OK); 416 417 return ScopedHandle(Handle(mojo_handle)); 418 } 419 420 MojoResult UnwrapMachPort(ScopedHandle handle, mach_port_t* port) { 421 MojoPlatformHandle platform_handle; 422 platform_handle.struct_size = sizeof(MojoPlatformHandle); 423 MojoResult result = MojoUnwrapPlatformHandle(handle.release().value(), 424 nullptr, &platform_handle); 425 if (result != MOJO_RESULT_OK) 426 return result; 427 428 CHECK(platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_MACH_PORT || 429 platform_handle.type == MOJO_PLATFORM_HANDLE_TYPE_INVALID); 430 *port = static_cast<mach_port_t>(platform_handle.value); 431 return MOJO_RESULT_OK; 432 } 433 #endif // defined(OS_MACOSX) && !defined(OS_IOS) 434 435 } // namespace mojo 436