• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2018 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 #ifndef BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
6 #define BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
7 
8 #include <utility>
9 
10 #include "base/compiler_specific.h"
11 #include "base/gtest_prod_util.h"
12 #include "base/macros.h"
13 #include "base/unguessable_token.h"
14 #include "build/build_config.h"
15 
16 #if defined(OS_MACOSX) && !defined(OS_IOS)
17 #include <mach/mach.h>
18 #include "base/mac/scoped_mach_port.h"
19 #elif defined(OS_FUCHSIA)
20 #include <lib/zx/vmo.h>
21 #elif defined(OS_WIN)
22 #include "base/win/scoped_handle.h"
23 #include "base/win/windows_types.h"
24 #elif defined(OS_POSIX)
25 #include <sys/types.h>
26 #include "base/file_descriptor_posix.h"
27 #include "base/files/scoped_file.h"
28 #endif
29 
30 namespace base {
31 namespace subtle {
32 
33 #if defined(OS_POSIX) && (!defined(OS_MACOSX) || defined(OS_IOS)) && \
34     !defined(OS_ANDROID)
35 // Helper structs to keep two descriptors on POSIX. It's needed to support
36 // ConvertToReadOnly().
37 struct BASE_EXPORT FDPair {
38   int fd;
39   int readonly_fd;
40 };
41 
42 struct BASE_EXPORT ScopedFDPair {
43   ScopedFDPair();
44   ScopedFDPair(ScopedFD in_fd, ScopedFD in_readonly_fd);
45   ScopedFDPair(ScopedFDPair&&);
46   ScopedFDPair& operator=(ScopedFDPair&&);
47   ~ScopedFDPair();
48 
49   FDPair get() const;
50 
51   ScopedFD fd;
52   ScopedFD readonly_fd;
53 };
54 #endif
55 
56 // Implementation class for shared memory regions.
57 //
58 // This class does the following:
59 //
60 // - Wraps and owns a shared memory region platform handle.
61 // - Provides a way to allocate a new region of platform shared memory of given
62 //   size.
63 // - Provides a way to create mapping of the region in the current process'
64 //   address space, under special access-control constraints (see Mode).
65 // - Provides methods to help transferring the handle across process boundaries.
66 // - Holds a 128-bit unique identifier used to uniquely identify the same
67 //   kernel region resource across processes (used for memory tracking).
68 // - Has a method to retrieve the region's size in bytes.
69 //
70 // IMPORTANT NOTE: Users should never use this directly, but
71 // ReadOnlySharedMemoryRegion, WritableSharedMemoryRegion or
72 // UnsafeSharedMemoryRegion since this is an implementation class.
73 class BASE_EXPORT PlatformSharedMemoryRegion {
74  public:
75   // Permission mode of the platform handle. Each mode corresponds to one of the
76   // typed shared memory classes:
77   //
78   // * ReadOnlySharedMemoryRegion: A region that can only create read-only
79   // mappings.
80   //
81   // * WritableSharedMemoryRegion: A region that can only create writable
82   // mappings. The region can be demoted to ReadOnlySharedMemoryRegion without
83   // the possibility of promoting back to writable.
84   //
85   // * UnsafeSharedMemoryRegion: A region that can only create writable
86   // mappings. The region cannot be demoted to ReadOnlySharedMemoryRegion.
87   enum class Mode {
88     kReadOnly,  // ReadOnlySharedMemoryRegion
89     kWritable,  // WritableSharedMemoryRegion
90     kUnsafe,    // UnsafeSharedMemoryRegion
91     kMaxValue = kUnsafe
92   };
93 
94 // Platform-specific shared memory type used by this class.
95 #if defined(OS_MACOSX) && !defined(OS_IOS)
96   using PlatformHandle = mach_port_t;
97   using ScopedPlatformHandle = mac::ScopedMachSendRight;
98 #elif defined(OS_FUCHSIA)
99   using PlatformHandle = zx_handle_t;
100   using ScopedPlatformHandle = zx::vmo;
101 #elif defined(OS_WIN)
102   using PlatformHandle = HANDLE;
103   using ScopedPlatformHandle = win::ScopedHandle;
104 #elif defined(OS_ANDROID)
105   using PlatformHandle = int;
106   using ScopedPlatformHandle = ScopedFD;
107 #else
108   using PlatformHandle = FDPair;
109   using ScopedPlatformHandle = ScopedFDPair;
110 #endif
111 
112   // The minimum alignment in bytes that any mapped address produced by Map()
113   // and MapAt() is guaranteed to have.
114   enum { kMapMinimumAlignment = 32 };
115 
116   // Creates a new PlatformSharedMemoryRegion with corresponding mode and size.
117   // Creating in kReadOnly mode isn't supported because then there will be no
118   // way to modify memory content.
119   static PlatformSharedMemoryRegion CreateWritable(size_t size);
120   static PlatformSharedMemoryRegion CreateUnsafe(size_t size);
121 
122   // Returns a new PlatformSharedMemoryRegion that takes ownership of the
123   // |handle|. All parameters must be taken from another valid
124   // PlatformSharedMemoryRegion instance, e.g. |size| must be equal to the
125   // actual region size as allocated by the kernel.
126   // Closes the |handle| and returns an invalid instance if passed parameters
127   // are invalid.
128   static PlatformSharedMemoryRegion Take(ScopedPlatformHandle handle,
129                                          Mode mode,
130                                          size_t size,
131                                          const UnguessableToken& guid);
132 
133   // Default constructor initializes an invalid instance, i.e. an instance that
134   // doesn't wrap any valid platform handle.
135   PlatformSharedMemoryRegion();
136 
137   // Move operations are allowed.
138   PlatformSharedMemoryRegion(PlatformSharedMemoryRegion&&);
139   PlatformSharedMemoryRegion& operator=(PlatformSharedMemoryRegion&&);
140 
141   // Destructor closes the platform handle. Does nothing if the handle is
142   // invalid.
143   ~PlatformSharedMemoryRegion();
144 
145   // Passes ownership of the platform handle to the caller. The current instance
146   // becomes invalid. It's the responsibility of the caller to close the handle.
147   ScopedPlatformHandle PassPlatformHandle() WARN_UNUSED_RESULT;
148 
149   // Returns the platform handle. The current instance keeps ownership of this
150   // handle.
151   PlatformHandle GetPlatformHandle() const;
152 
153   // Whether the platform handle is valid.
154   bool IsValid() const;
155 
156   // Duplicates the platform handle and creates a new PlatformSharedMemoryRegion
157   // with the same |mode_|, |size_| and |guid_| that owns this handle. Returns
158   // invalid region on failure, the current instance remains valid.
159   // Can be called only in kReadOnly and kUnsafe modes, CHECK-fails if is
160   // called in kWritable mode.
161   PlatformSharedMemoryRegion Duplicate() const;
162 
163   // Converts the region to read-only. Returns whether the operation succeeded.
164   // Makes the current instance invalid on failure. Can be called only in
165   // kWritable mode, all other modes will CHECK-fail. The object will have
166   // kReadOnly mode after this call on success.
167   bool ConvertToReadOnly();
168 #if defined(OS_MACOSX) && !defined(OS_IOS)
169   // Same as above, but |mapped_addr| is used as a hint to avoid additional
170   // mapping of the memory object.
171   // |mapped_addr| must be mapped location of |memory_object_|. If the location
172   // is unknown, |mapped_addr| should be |nullptr|.
173   bool ConvertToReadOnly(void* mapped_addr);
174 #endif  // defined(OS_MACOSX) && !defined(OS_IOS)
175 
176   // Converts the region to unsafe. Returns whether the operation succeeded.
177   // Makes the current instance invalid on failure. Can be called only in
178   // kWritable mode, all other modes will CHECK-fail. The object will have
179   // kUnsafe mode after this call on success.
180   bool ConvertToUnsafe();
181 
182   // Maps |size| bytes of the shared memory region starting with the given
183   // |offset| into the caller's address space. |offset| must be aligned to value
184   // of |SysInfo::VMAllocationGranularity()|. Fails if requested bytes are out
185   // of the region limits.
186   // Returns true and sets |memory| and |mapped_size| on success, returns false
187   // and leaves output parameters in unspecified state otherwise. The mapped
188   // address is guaranteed to have an alignment of at least
189   // |kMapMinimumAlignment|.
190   bool MapAt(off_t offset,
191              size_t size,
192              void** memory,
193              size_t* mapped_size) const;
194 
GetGUID()195   const UnguessableToken& GetGUID() const { return guid_; }
196 
GetSize()197   size_t GetSize() const { return size_; }
198 
GetMode()199   Mode GetMode() const { return mode_; }
200 
201  private:
202   FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
203                            CreateReadOnlyRegionDeathTest);
204   FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
205                            CheckPlatformHandlePermissionsCorrespondToMode);
206   static PlatformSharedMemoryRegion Create(Mode mode, size_t size);
207 
208   static bool CheckPlatformHandlePermissionsCorrespondToMode(
209       PlatformHandle handle,
210       Mode mode,
211       size_t size);
212 
213   PlatformSharedMemoryRegion(ScopedPlatformHandle handle,
214                              Mode mode,
215                              size_t size,
216                              const UnguessableToken& guid);
217 
218   ScopedPlatformHandle handle_;
219   Mode mode_ = Mode::kReadOnly;
220   size_t size_ = 0;
221   UnguessableToken guid_;
222 
223   DISALLOW_COPY_AND_ASSIGN(PlatformSharedMemoryRegion);
224 };
225 
226 }  // namespace subtle
227 }  // namespace base
228 
229 #endif  // BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
230