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_SharedMemory_h
8 #define mozilla_ipc_SharedMemory_h
9 
10 #include "nsDebug.h"
11 #include "nsISupportsImpl.h"  // NS_INLINE_DECL_REFCOUNTING
12 #include "mozilla/Attributes.h"
13 
14 #include "base/process.h"
15 #include "chrome/common/ipc_message_utils.h"
16 
17 //
18 // This is a low-level wrapper around platform shared memory.  Don't
19 // use it directly; use Shmem allocated through IPDL interfaces.
20 //
21 namespace {
22 enum Rights { RightsNone = 0, RightsRead = 1 << 0, RightsWrite = 1 << 1 };
23 }  // namespace
24 
25 namespace mozilla {
26 
27 namespace ipc {
28 class SharedMemory;
29 }  // namespace ipc
30 
31 namespace ipc {
32 
33 class SharedMemory {
34  protected:
~SharedMemory()35   virtual ~SharedMemory() {
36     Unmapped();
37     Destroyed();
38   }
39 
40  public:
41   enum SharedMemoryType { TYPE_BASIC, TYPE_UNKNOWN };
42 
43   enum OpenRights {
44     RightsReadOnly = RightsRead,
45     RightsReadWrite = RightsRead | RightsWrite,
46   };
47 
Size()48   size_t Size() const { return mMappedSize; }
49 
50   virtual void* memory() const = 0;
51 
52   virtual bool Create(size_t size) = 0;
53   virtual bool Map(size_t nBytes, void* fixed_address = nullptr) = 0;
54   virtual void Unmap() = 0;
55 
56   virtual void CloseHandle() = 0;
57 
58   virtual SharedMemoryType Type() const = 0;
59 
60   virtual bool ShareHandle(base::ProcessId aProcessId,
61                            IPC::Message* aMessage) = 0;
62   virtual bool ReadHandle(const IPC::Message* aMessage,
63                           PickleIterator* aIter) = 0;
64 
Protect(char * aAddr,size_t aSize,int aRights)65   void Protect(char* aAddr, size_t aSize, int aRights) {
66     char* memStart = reinterpret_cast<char*>(memory());
67     if (!memStart) MOZ_CRASH("SharedMemory region points at NULL!");
68     char* memEnd = memStart + Size();
69 
70     char* protStart = aAddr;
71     if (!protStart) MOZ_CRASH("trying to Protect() a NULL region!");
72     char* protEnd = protStart + aSize;
73 
74     if (!(memStart <= protStart && protEnd <= memEnd))
75       MOZ_CRASH("attempt to Protect() a region outside this SharedMemory");
76 
77     // checks alignment etc.
78     SystemProtect(aAddr, aSize, aRights);
79   }
80 
81   // bug 1168843, compositor thread may create shared memory instances that are
82   // destroyed by main thread on shutdown, so this must use thread-safe RC to
83   // avoid hitting assertion
84   NS_INLINE_DECL_THREADSAFE_REFCOUNTING(SharedMemory)
85 
86   static void SystemProtect(char* aAddr, size_t aSize, int aRights);
87   [[nodiscard]] static bool SystemProtectFallible(char* aAddr, size_t aSize,
88                                                   int aRights);
89   static size_t SystemPageSize();
90   static size_t PageAlignedSize(size_t aSize);
91 
92  protected:
93   SharedMemory();
94 
95   // Implementations should call these methods on shmem usage changes,
96   // but *only if* the OS-specific calls are known to have succeeded.
97   // The methods are expected to be called in the pattern
98   //
99   //   Created (Mapped Unmapped)* Destroy
100   //
101   // but this isn't checked.
102   void Created(size_t aNBytes);
103   void Mapped(size_t aNBytes);
104   void Unmapped();
105   void Destroyed();
106 
107   // The size of the shmem region requested in Create(), if
108   // successful.  SharedMemory instances that are opened from a
109   // foreign handle have an alloc size of 0, even though they have
110   // access to the alloc-size information.
111   size_t mAllocSize;
112   // The size of the region mapped in Map(), if successful.  All
113   // SharedMemorys that are mapped have a non-zero mapped size.
114   size_t mMappedSize;
115 };
116 
117 template <typename HandleImpl>
118 class SharedMemoryCommon : public SharedMemory {
119  public:
120   typedef HandleImpl Handle;
121 
122   virtual bool ShareToProcess(base::ProcessId aProcessId, Handle* aHandle) = 0;
123   virtual bool IsHandleValid(const Handle& aHandle) const = 0;
124   virtual bool SetHandle(const Handle& aHandle, OpenRights aRights) = 0;
125 
ShareHandle(base::ProcessId aProcessId,IPC::Message * aMessage)126   virtual bool ShareHandle(base::ProcessId aProcessId,
127                            IPC::Message* aMessage) override {
128     Handle handle;
129     if (!ShareToProcess(aProcessId, &handle)) {
130       return false;
131     }
132     IPC::WriteParam(aMessage, handle);
133     return true;
134   }
135 
ReadHandle(const IPC::Message * aMessage,PickleIterator * aIter)136   virtual bool ReadHandle(const IPC::Message* aMessage,
137                           PickleIterator* aIter) override {
138     Handle handle;
139     return IPC::ReadParam(aMessage, aIter, &handle) && IsHandleValid(handle) &&
140            SetHandle(handle, RightsReadWrite);
141   }
142 };
143 
144 }  // namespace ipc
145 }  // namespace mozilla
146 
147 #endif  // ifndef mozilla_ipc_SharedMemory_h
148