platform_shared_memory_region.h 9.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239
  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. #ifndef BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
  5. #define BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
  6. #include "base/base_export.h"
  7. #include "base/containers/span.h"
  8. #include "base/gtest_prod_util.h"
  9. #include "base/memory/platform_shared_memory_handle.h"
  10. #include "base/memory/shared_memory_mapper.h"
  11. #include "base/unguessable_token.h"
  12. #include "build/build_config.h"
  13. #include "third_party/abseil-cpp/absl/types/optional.h"
  14. #include <stdint.h>
  15. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  16. namespace content {
  17. class SandboxIPCHandler;
  18. }
  19. #endif
  20. namespace base {
  21. namespace subtle {
  22. // Implementation class for shared memory regions.
  23. //
  24. // This class does the following:
  25. //
  26. // - Wraps and owns a shared memory region platform handle.
  27. // - Provides a way to allocate a new region of platform shared memory of given
  28. // size.
  29. // - Provides a way to create mapping of the region in the current process'
  30. // address space, under special access-control constraints (see Mode).
  31. // - Provides methods to help transferring the handle across process boundaries.
  32. // - Holds a 128-bit unique identifier used to uniquely identify the same
  33. // kernel region resource across processes (used for memory tracking).
  34. // - Has a method to retrieve the region's size in bytes.
  35. //
  36. // IMPORTANT NOTE: Users should never use this directly, but
  37. // ReadOnlySharedMemoryRegion, WritableSharedMemoryRegion or
  38. // UnsafeSharedMemoryRegion since this is an implementation class.
  39. class BASE_EXPORT PlatformSharedMemoryRegion {
  40. public:
  41. // Permission mode of the platform handle. Each mode corresponds to one of the
  42. // typed shared memory classes:
  43. //
  44. // * ReadOnlySharedMemoryRegion: A region that can only create read-only
  45. // mappings.
  46. //
  47. // * WritableSharedMemoryRegion: A region that can only create writable
  48. // mappings. The region can be demoted to ReadOnlySharedMemoryRegion without
  49. // the possibility of promoting back to writable.
  50. //
  51. // * UnsafeSharedMemoryRegion: A region that can only create writable
  52. // mappings. The region cannot be demoted to ReadOnlySharedMemoryRegion.
  53. enum class Mode {
  54. kReadOnly, // ReadOnlySharedMemoryRegion
  55. kWritable, // WritableSharedMemoryRegion
  56. kUnsafe, // UnsafeSharedMemoryRegion
  57. kMaxValue = kUnsafe
  58. };
  59. // Errors that can occur during Shared Memory construction.
  60. // These match tools/metrics/histograms/enums.xml.
  61. // This enum is append-only.
  62. enum class CreateError {
  63. SUCCESS = 0,
  64. SIZE_ZERO = 1,
  65. SIZE_TOO_LARGE = 2,
  66. INITIALIZE_ACL_FAILURE = 3,
  67. INITIALIZE_SECURITY_DESC_FAILURE = 4,
  68. SET_SECURITY_DESC_FAILURE = 5,
  69. CREATE_FILE_MAPPING_FAILURE = 6,
  70. REDUCE_PERMISSIONS_FAILURE = 7,
  71. ALREADY_EXISTS = 8,
  72. ALLOCATE_FILE_REGION_FAILURE = 9,
  73. FSTAT_FAILURE = 10,
  74. INODES_MISMATCH = 11,
  75. GET_SHMEM_TEMP_DIR_FAILURE = 12,
  76. kMaxValue = GET_SHMEM_TEMP_DIR_FAILURE
  77. };
  78. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  79. // Structure to limit access to executable region creation.
  80. struct ExecutableRegion {
  81. private:
  82. // Creates a new shared memory region the unsafe mode (writable and not and
  83. // convertible to read-only), and in addition marked executable. A ScopedFD
  84. // to this region is returned. Any any mapping will have to be done
  85. // manually, including setting executable permissions if necessary
  86. //
  87. // This is only used to support sandbox_ipc_linux.cc, and should not be used
  88. // anywhere else in chrome. This is restricted via AllowCreateExecutable.
  89. // TODO(crbug.com/982879): remove this when NaCl is unshipped.
  90. //
  91. // Returns an invalid ScopedFD if the call fails.
  92. static ScopedFD CreateFD(size_t size);
  93. friend class content::SandboxIPCHandler;
  94. };
  95. #endif
  96. // The minimum alignment in bytes that any mapped address produced by Map()
  97. // and MapAt() is guaranteed to have.
  98. enum { kMapMinimumAlignment = 32 };
  99. // Creates a new PlatformSharedMemoryRegion with corresponding mode and size.
  100. // Creating in kReadOnly mode isn't supported because then there will be no
  101. // way to modify memory content.
  102. static PlatformSharedMemoryRegion CreateWritable(size_t size);
  103. static PlatformSharedMemoryRegion CreateUnsafe(size_t size);
  104. // Returns a new PlatformSharedMemoryRegion that takes ownership of the
  105. // |handle|. All parameters must be taken from another valid
  106. // PlatformSharedMemoryRegion instance, e.g. |size| must be equal to the
  107. // actual region size as allocated by the kernel.
  108. // Closes the |handle| and returns an invalid instance if passed parameters
  109. // are invalid.
  110. static PlatformSharedMemoryRegion Take(
  111. ScopedPlatformSharedMemoryHandle handle,
  112. Mode mode,
  113. size_t size,
  114. const UnguessableToken& guid);
  115. #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_APPLE)
  116. // Specialized version of Take() for POSIX that takes only one file descriptor
  117. // instead of pair. Cannot be used with kWritable |mode|.
  118. static PlatformSharedMemoryRegion Take(ScopedFD handle,
  119. Mode mode,
  120. size_t size,
  121. const UnguessableToken& guid);
  122. #endif
  123. // Default constructor initializes an invalid instance, i.e. an instance that
  124. // doesn't wrap any valid platform handle.
  125. PlatformSharedMemoryRegion();
  126. // Move operations are allowed.
  127. PlatformSharedMemoryRegion(PlatformSharedMemoryRegion&&);
  128. PlatformSharedMemoryRegion& operator=(PlatformSharedMemoryRegion&&);
  129. PlatformSharedMemoryRegion(const PlatformSharedMemoryRegion&) = delete;
  130. PlatformSharedMemoryRegion& operator=(const PlatformSharedMemoryRegion&) =
  131. delete;
  132. // Destructor closes the platform handle. Does nothing if the handle is
  133. // invalid.
  134. ~PlatformSharedMemoryRegion();
  135. // Passes ownership of the platform handle to the caller. The current instance
  136. // becomes invalid. It's the responsibility of the caller to close the
  137. // handle. If the current instance is invalid, ScopedPlatformHandle will also
  138. // be invalid.
  139. [[nodiscard]] ScopedPlatformSharedMemoryHandle PassPlatformHandle();
  140. // Returns the platform handle. The current instance keeps ownership of this
  141. // handle.
  142. PlatformSharedMemoryHandle GetPlatformHandle() const;
  143. // Whether the platform handle is valid.
  144. bool IsValid() const;
  145. // Duplicates the platform handle and creates a new PlatformSharedMemoryRegion
  146. // with the same |mode_|, |size_| and |guid_| that owns this handle. Returns
  147. // invalid region on failure, the current instance remains valid.
  148. // Can be called only in kReadOnly and kUnsafe modes, CHECK-fails if is
  149. // called in kWritable mode.
  150. PlatformSharedMemoryRegion Duplicate() const;
  151. // Converts the region to read-only. Returns whether the operation succeeded.
  152. // Makes the current instance invalid on failure. Can be called only in
  153. // kWritable mode, all other modes will CHECK-fail. The object will have
  154. // kReadOnly mode after this call on success.
  155. bool ConvertToReadOnly();
  156. #if BUILDFLAG(IS_APPLE)
  157. // Same as above, but |mapped_addr| is used as a hint to avoid additional
  158. // mapping of the memory object.
  159. // |mapped_addr| must be mapped location of |memory_object_|. If the location
  160. // is unknown, |mapped_addr| should be |nullptr|.
  161. bool ConvertToReadOnly(void* mapped_addr);
  162. #endif // BUILDFLAG(IS_APPLE)
  163. // Converts the region to unsafe. 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. // kUnsafe mode after this call on success.
  167. bool ConvertToUnsafe();
  168. // Maps |size| bytes of the shared memory region starting with the given
  169. // |offset| into the caller's address space using the provided
  170. // |SharedMemoryMapper|. |offset| must be aligned to value of
  171. // |SysInfo::VMAllocationGranularity()|. Fails if requested bytes are out of
  172. // the region limits. Returns the mapping as span on success, or absl::nullopt
  173. // on failure. The mapped address is guaranteed to have an alignment of at
  174. // least |kMapMinimumAlignment|.
  175. absl::optional<span<uint8_t>> MapAt(uint64_t offset,
  176. size_t size,
  177. SharedMemoryMapper* mapper) const;
  178. const UnguessableToken& GetGUID() const { return guid_; }
  179. size_t GetSize() const { return size_; }
  180. Mode GetMode() const { return mode_; }
  181. private:
  182. FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
  183. CreateReadOnlyRegionDeathTest);
  184. FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
  185. CheckPlatformHandlePermissionsCorrespondToMode);
  186. static PlatformSharedMemoryRegion Create(Mode mode,
  187. size_t size
  188. #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
  189. ,
  190. bool executable = false
  191. #endif
  192. );
  193. static bool CheckPlatformHandlePermissionsCorrespondToMode(
  194. PlatformSharedMemoryHandle handle,
  195. Mode mode,
  196. size_t size);
  197. PlatformSharedMemoryRegion(ScopedPlatformSharedMemoryHandle handle,
  198. Mode mode,
  199. size_t size,
  200. const UnguessableToken& guid);
  201. ScopedPlatformSharedMemoryHandle handle_;
  202. Mode mode_ = Mode::kReadOnly;
  203. size_t size_ = 0;
  204. UnguessableToken guid_;
  205. };
  206. } // namespace subtle
  207. } // namespace base
  208. #endif // BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_