1 // Copyright 2018 The Chromium Authors 2 // Use of this source code is governed by a BSD-style license that can be 3 // found in the LICENSE file. 4 5 #ifndef BASE_MEMORY_WRITABLE_SHARED_MEMORY_REGION_H_ 6 #define BASE_MEMORY_WRITABLE_SHARED_MEMORY_REGION_H_ 7 8 #include <stdint.h> 9 10 #include "base/base_export.h" 11 #include "base/check.h" 12 #include "base/compiler_specific.h" 13 #include "base/memory/platform_shared_memory_region.h" 14 #include "base/memory/read_only_shared_memory_region.h" 15 #include "base/memory/shared_memory_mapping.h" 16 #include "base/memory/unsafe_shared_memory_region.h" 17 #include "build/build_config.h" 18 19 namespace base { 20 21 // Scoped move-only handle to a region of platform shared memory. The instance 22 // owns the platform handle it wraps. Mappings created by this region are 23 // writable. These mappings remain valid even after the region handle is moved 24 // or destroyed. 25 // 26 // This region can be locked to read-only access by converting it to a 27 // ReadOnlySharedMemoryRegion. However, unlike ReadOnlySharedMemoryRegion and 28 // UnsafeSharedMemoryRegion, ownership of this region (while writable) is unique 29 // and may only be transferred, not duplicated. 30 // 31 // Unlike ReadOnlySharedMemoryRegion and UnsafeSharedMemoryRegion, 32 // WritableSharedMemoryRegion doesn't provide GetPlatformHandle() method to 33 // ensure that the region is never duplicated while writable. 34 class BASE_EXPORT WritableSharedMemoryRegion { 35 public: 36 using MappingType = WritableSharedMemoryMapping; 37 // Creates a new WritableSharedMemoryRegion instance of a given 38 // size that can be used for mapping writable shared memory into the virtual 39 // address space. 40 static WritableSharedMemoryRegion Create(size_t size); 41 using CreateFunction = decltype(Create); 42 43 // Returns a WritableSharedMemoryRegion built from a platform handle that was 44 // taken from another WritableSharedMemoryRegion instance. Returns an invalid 45 // region iff the |handle| is invalid. CHECK-fails if the |handle| isn't 46 // writable. 47 // This should be used only by the code passing handles across process 48 // boundaries. 49 static WritableSharedMemoryRegion Deserialize( 50 subtle::PlatformSharedMemoryRegion handle); 51 52 // Extracts a platform handle from the region. Ownership is transferred to the 53 // returned region object. 54 // This should be used only for sending the handle from the current 55 // process to another. 56 static subtle::PlatformSharedMemoryRegion TakeHandleForSerialization( 57 WritableSharedMemoryRegion region); 58 59 // Makes the region read-only. No new writable mappings of the region can be 60 // created after this call. Returns an invalid region on failure. 61 static ReadOnlySharedMemoryRegion ConvertToReadOnly( 62 WritableSharedMemoryRegion region); 63 64 // Makes the region unsafe. The region cannot be converted to read-only after 65 // this call. Returns an invalid region on failure. 66 static UnsafeSharedMemoryRegion ConvertToUnsafe( 67 WritableSharedMemoryRegion region); 68 69 // Default constructor initializes an invalid instance. 70 WritableSharedMemoryRegion(); 71 72 // Move operations are allowed. 73 WritableSharedMemoryRegion(WritableSharedMemoryRegion&&); 74 WritableSharedMemoryRegion& operator=(WritableSharedMemoryRegion&&); 75 76 WritableSharedMemoryRegion(const WritableSharedMemoryRegion&) = delete; 77 WritableSharedMemoryRegion& operator=(const WritableSharedMemoryRegion&) = 78 delete; 79 80 // Destructor closes shared memory region if valid. 81 // All created mappings will remain valid. 82 ~WritableSharedMemoryRegion(); 83 84 // Maps the shared memory region into the caller's address space with write 85 // access. The mapped address is guaranteed to have an alignment of 86 // at least |subtle::PlatformSharedMemoryRegion::kMapMinimumAlignment|. 87 // Returns a valid WritableSharedMemoryMapping instance on success, invalid 88 // otherwise. A custom |SharedMemoryMapper| for mapping (and later unmapping) 89 // the region can be provided using the optional |mapper| parameter. 90 WritableSharedMemoryMapping Map(SharedMemoryMapper* mapper = nullptr) const; 91 92 // Similar to `Map()`, but maps only `size` bytes of the shared memory block 93 // at byte `offset`. Returns an invalid mapping if requested bytes are out of 94 // the region limits. 95 // 96 // `offset` does not need to be aligned; if `offset` is not a multiple of 97 // `subtle::PlatformSharedMemoryRegion::kMapMinimumAlignment`, then the 98 // returned mapping will not respect alignment either. Internally, `offset` 99 // and `size` are still first adjusted to respect alignment when mapping in 100 // the shared memory region, but the returned mapping will be "unadjusted" to 101 // match the exact `offset` and `size` requested. 102 WritableSharedMemoryMapping MapAt(uint64_t offset, 103 size_t size, 104 SharedMemoryMapper* mapper = nullptr) const; 105 106 // Whether underlying platform handles are valid. 107 bool IsValid() const; 108 109 // Returns the maximum mapping size that can be created from this region. GetSize()110 size_t GetSize() const { 111 DCHECK(IsValid()); 112 return handle_.GetSize(); 113 } 114 115 // Returns 128-bit GUID of the region. GetGUID()116 const UnguessableToken& GetGUID() const LIFETIME_BOUND { 117 DCHECK(IsValid()); 118 return handle_.GetGUID(); 119 } 120 121 #if BUILDFLAG(IS_WIN) 122 // On Windows it is necessary in rare cases to take a writable handle from a 123 // region that will be converted to read-only. On this platform it is a safe 124 // operation, as the handle returned from this method will remain writable 125 // after the region is converted to read-only. However, it breaks chromium's 126 // WritableSharedMemoryRegion semantics and so should be use with care. UnsafeGetPlatformHandle()127 HANDLE UnsafeGetPlatformHandle() const { return handle_.GetPlatformHandle(); } 128 #endif 129 130 private: 131 friend class SharedMemoryHooks; 132 133 explicit WritableSharedMemoryRegion( 134 subtle::PlatformSharedMemoryRegion handle); 135 set_create_hook(CreateFunction * hook)136 static void set_create_hook(CreateFunction* hook) { create_hook_ = hook; } 137 138 static CreateFunction* create_hook_; 139 140 subtle::PlatformSharedMemoryRegion handle_; 141 }; 142 143 } // namespace base 144 145 #endif // BASE_MEMORY_WRITABLE_SHARED_MEMORY_REGION_H_ 146