SharedMemoryHandle.h (8500B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #ifndef mozilla_ipc_SharedMemoryHandle_h 8 #define mozilla_ipc_SharedMemoryHandle_h 9 10 #include <utility> 11 12 #include "mozilla/UniquePtrExtensions.h" 13 14 namespace IPC { 15 template <class P> 16 struct ParamTraits; 17 class MessageWriter; 18 class MessageReader; 19 } // namespace IPC 20 21 namespace mozilla::geckoargs { 22 template <typename T> 23 struct CommandLineArg; 24 } 25 26 namespace mozilla::ipc { 27 28 namespace shared_memory { 29 30 enum class Type { 31 Mutable, 32 ReadOnly, 33 MutableOrReadOnly, 34 Freezable, 35 }; 36 37 #if defined(XP_DARWIN) 38 using PlatformHandle = mozilla::UniqueMachSendRight; 39 #else 40 using PlatformHandle = mozilla::UniqueFileHandle; 41 #endif 42 43 template <Type T> 44 struct Handle; 45 46 template <Type T, bool WithHandle = false> 47 struct Mapping; 48 49 using MutableHandle = Handle<Type::Mutable>; 50 using ReadOnlyHandle = Handle<Type::ReadOnly>; 51 using FreezableHandle = Handle<Type::Freezable>; 52 53 using MutableMapping = Mapping<Type::Mutable>; 54 using ReadOnlyMapping = Mapping<Type::ReadOnly>; 55 using MutableOrReadOnlyMapping = Mapping<Type::MutableOrReadOnly>; 56 using FreezableMapping = Mapping<Type::Freezable>; 57 58 using MutableMappingWithHandle = Mapping<Type::Mutable, true>; 59 using ReadOnlyMappingWithHandle = Mapping<Type::ReadOnly, true>; 60 61 class HandleBase { 62 public: 63 /** 64 * The size of the shared memory region to which this handle refers. 65 */ 66 uint64_t Size() const { return mSize; } 67 68 /** 69 * Whether this shared memory handle is valid. 70 */ 71 bool IsValid() const { return (bool)*this; } 72 73 /** 74 * Whether this shared memory handle is valid. 75 */ 76 explicit operator bool() const { return (bool)mHandle; } 77 78 /** 79 * Take the platform handle. 80 * 81 * This should be used with caution, as it drops all of the guarantees of the 82 * shared memory handle classes. 83 */ 84 PlatformHandle TakePlatformHandle() && { return std::move(mHandle); } 85 86 friend class Platform; 87 friend struct IPC::ParamTraits<mozilla::ipc::shared_memory::MutableHandle>; 88 friend struct IPC::ParamTraits<mozilla::ipc::shared_memory::ReadOnlyHandle>; 89 friend struct mozilla::geckoargs::CommandLineArg< 90 mozilla::ipc::shared_memory::ReadOnlyHandle>; 91 92 protected: 93 HandleBase(); 94 MOZ_IMPLICIT HandleBase(std::nullptr_t) {} 95 ~HandleBase(); 96 97 HandleBase(HandleBase&& aOther) 98 : mHandle(std::move(aOther.mHandle)), 99 mSize(std::exchange(aOther.mSize, 0)) {} 100 101 HandleBase& operator=(HandleBase&& aOther); 102 103 HandleBase(const HandleBase&) = delete; 104 HandleBase& operator=(const HandleBase&) = delete; 105 106 HandleBase Clone() const; 107 108 template <Type T> 109 Handle<T> CloneAs() const { 110 return Clone().ConvertTo<T>(); 111 } 112 113 template <Type T> 114 Handle<T> ConvertTo() && { 115 Handle<T> d; 116 static_cast<HandleBase&>(d) = std::move(*this); 117 return d; 118 } 119 120 void ToMessageWriter(IPC::MessageWriter* aWriter) &&; 121 bool FromMessageReader(IPC::MessageReader* aReader); 122 123 private: 124 /** 125 * Set the size of the handle. 126 * 127 * This method must be used rather than setting `mSize` directly, as there is 128 * additional bookkeeping that goes along with this value. 129 */ 130 void SetSize(uint64_t aSize); 131 132 PlatformHandle mHandle = nullptr; 133 uint64_t mSize = 0; 134 }; 135 136 /** 137 * A handle to a shared memory region. 138 */ 139 template <> 140 struct Handle<Type::Mutable> : HandleBase { 141 /** 142 * Create an empty Handle. 143 */ 144 Handle() = default; 145 MOZ_IMPLICIT Handle(std::nullptr_t) {} 146 147 /** 148 * Clone the handle. 149 */ 150 Handle Clone() const { return CloneAs<Type::Mutable>(); } 151 152 /** 153 * Convert the handle to a read-only handle. 154 * 155 * Note that this doesn't enforce any sort of security or guarantees on the 156 * underlying shared memory. 157 */ 158 ReadOnlyHandle ToReadOnly() &&; 159 160 /** 161 * Use the handle as a read-only handle. 162 * 163 * Note that this doesn't enforce any sort of security or guarantees on the 164 * underlying shared memory. 165 */ 166 const ReadOnlyHandle& AsReadOnly() const; 167 168 /** 169 * Map the shared memory region into memory. 170 */ 171 MutableMapping Map(void* aFixedAddress = nullptr) const; 172 173 /** 174 * Map a subregion of the shared memory region into memory. 175 */ 176 MutableMapping MapSubregion(uint64_t aOffset, size_t aSize, 177 void* aFixedAddress = nullptr) const; 178 179 /** 180 * Map the shared memory region into memory, keeping the handle with it. 181 */ 182 MutableMappingWithHandle MapWithHandle(void* aFixedAddress = nullptr) &&; 183 }; 184 185 /** 186 * A read-only handle to a shared memory region. 187 */ 188 template <> 189 struct Handle<Type::ReadOnly> : HandleBase { 190 /** 191 * Create an empty ReadOnlyHandle. 192 */ 193 Handle() = default; 194 MOZ_IMPLICIT Handle(std::nullptr_t) {} 195 196 /** 197 * Clone the handle. 198 */ 199 Handle Clone() const { return CloneAs<Type::ReadOnly>(); } 200 201 /** 202 * Map the shared memory region into memory. 203 */ 204 ReadOnlyMapping Map(void* aFixedAddress = nullptr) const; 205 206 /** 207 * Map a subregion of the shared memory region into memory. 208 */ 209 ReadOnlyMapping MapSubregion(uint64_t aOffset, size_t aSize, 210 void* aFixedAddress = nullptr) const; 211 212 /** 213 * Map the shared memory region into memory, keeping the handle with it. 214 */ 215 ReadOnlyMappingWithHandle MapWithHandle(void* aFixedAddress = nullptr) &&; 216 }; 217 218 /** 219 * A freezable handle to a shared memory region. 220 * 221 * One cannot clone this handle, ensuring that at most one writable mapping 222 * exists. After freezing, no new writable mappings can be created. 223 */ 224 template <> 225 struct Handle<Type::Freezable> : HandleBase { 226 /** 227 * Create an empty FreezableHandle. 228 */ 229 Handle() = default; 230 MOZ_IMPLICIT Handle(std::nullptr_t) {} 231 ~Handle(); 232 233 Handle(Handle&&) = default; 234 Handle& operator=(Handle&&) = default; 235 236 /** 237 * Convert to a normal handle if we will not freeze this handle. 238 */ 239 MutableHandle WontFreeze() &&; 240 241 /** 242 * Freeze this handle, returning a read-only handle. 243 */ 244 ReadOnlyHandle Freeze() &&; 245 246 /** 247 * Map the shared memory region into memory. 248 */ 249 FreezableMapping Map(void* aFixedAddress = nullptr) &&; 250 251 /** 252 * Map a subregion of the shared memory region into memory. 253 */ 254 FreezableMapping MapSubregion(uint64_t aOffset, size_t aSize, 255 void* aFixedAddress = nullptr) &&; 256 257 friend class Platform; 258 #if !defined(XP_DARWIN) && !defined(XP_WIN) && !defined(ANDROID) 259 private: 260 PlatformHandle mFrozenFile; 261 #endif 262 }; 263 264 /** 265 * Create a new shared memory region. 266 */ 267 MutableHandle Create(uint64_t aSize); 268 269 /** 270 * Create a new freezable shared memory region. 271 * 272 * Freezable shared memory regions are distinguished by the property that there 273 * is guaranteed to be at most one writable mapping of the region at a time. 274 * 275 * Furthermore, a freezable shared memory region can be frozen while mapped. In 276 * this case, the mapping remains valid but there can be no new writable 277 * mappings. 278 */ 279 FreezableHandle CreateFreezable(uint64_t aSize); 280 281 #if defined(XP_LINUX) 282 // If named POSIX shm is being used, append the prefix (including 283 // the leading '/') that would be used by a process with the given 284 // pid to the given string and return true. If not, return false. 285 // (This is public so that the Linux sandboxing code can use it.) 286 bool AppendPosixShmPrefix(std::string* str, pid_t pid); 287 288 // Returns whether POSIX shm is in use. 289 bool UsingPosixShm(); 290 #endif 291 292 } // namespace shared_memory 293 294 using MutableSharedMemoryHandle = shared_memory::MutableHandle; 295 using ReadOnlySharedMemoryHandle = shared_memory::ReadOnlyHandle; 296 using FreezableSharedMemoryHandle = shared_memory::FreezableHandle; 297 298 } // namespace mozilla::ipc 299 300 namespace IPC { 301 302 template <> 303 struct ParamTraits<mozilla::ipc::shared_memory::MutableHandle> { 304 static void Write(MessageWriter* aWriter, 305 mozilla::ipc::shared_memory::MutableHandle&& aParam); 306 static bool Read(MessageReader* aReader, 307 mozilla::ipc::shared_memory::MutableHandle* aResult); 308 }; 309 310 template <> 311 struct ParamTraits<mozilla::ipc::shared_memory::ReadOnlyHandle> { 312 static void Write(MessageWriter* aWriter, 313 mozilla::ipc::shared_memory::ReadOnlyHandle&& aParam); 314 static bool Read(MessageReader* aReader, 315 mozilla::ipc::shared_memory::ReadOnlyHandle* aResult); 316 }; 317 318 } // namespace IPC 319 320 #endif