123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239 |
- // Copyright 2018 The Chromium Authors. All rights reserved.
- // Use of this source code is governed by a BSD-style license that can be
- // found in the LICENSE file.
- #ifndef BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
- #define BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
- #include "base/base_export.h"
- #include "base/containers/span.h"
- #include "base/gtest_prod_util.h"
- #include "base/memory/platform_shared_memory_handle.h"
- #include "base/memory/shared_memory_mapper.h"
- #include "base/unguessable_token.h"
- #include "build/build_config.h"
- #include "third_party/abseil-cpp/absl/types/optional.h"
- #include <stdint.h>
- #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- namespace content {
- class SandboxIPCHandler;
- }
- #endif
- namespace base {
- namespace subtle {
- // Implementation class for shared memory regions.
- //
- // This class does the following:
- //
- // - Wraps and owns a shared memory region platform handle.
- // - Provides a way to allocate a new region of platform shared memory of given
- // size.
- // - Provides a way to create mapping of the region in the current process'
- // address space, under special access-control constraints (see Mode).
- // - Provides methods to help transferring the handle across process boundaries.
- // - Holds a 128-bit unique identifier used to uniquely identify the same
- // kernel region resource across processes (used for memory tracking).
- // - Has a method to retrieve the region's size in bytes.
- //
- // IMPORTANT NOTE: Users should never use this directly, but
- // ReadOnlySharedMemoryRegion, WritableSharedMemoryRegion or
- // UnsafeSharedMemoryRegion since this is an implementation class.
- class BASE_EXPORT PlatformSharedMemoryRegion {
- public:
- // Permission mode of the platform handle. Each mode corresponds to one of the
- // typed shared memory classes:
- //
- // * ReadOnlySharedMemoryRegion: A region that can only create read-only
- // mappings.
- //
- // * WritableSharedMemoryRegion: A region that can only create writable
- // mappings. The region can be demoted to ReadOnlySharedMemoryRegion without
- // the possibility of promoting back to writable.
- //
- // * UnsafeSharedMemoryRegion: A region that can only create writable
- // mappings. The region cannot be demoted to ReadOnlySharedMemoryRegion.
- enum class Mode {
- kReadOnly, // ReadOnlySharedMemoryRegion
- kWritable, // WritableSharedMemoryRegion
- kUnsafe, // UnsafeSharedMemoryRegion
- kMaxValue = kUnsafe
- };
- // Errors that can occur during Shared Memory construction.
- // These match tools/metrics/histograms/enums.xml.
- // This enum is append-only.
- enum class CreateError {
- SUCCESS = 0,
- SIZE_ZERO = 1,
- SIZE_TOO_LARGE = 2,
- INITIALIZE_ACL_FAILURE = 3,
- INITIALIZE_SECURITY_DESC_FAILURE = 4,
- SET_SECURITY_DESC_FAILURE = 5,
- CREATE_FILE_MAPPING_FAILURE = 6,
- REDUCE_PERMISSIONS_FAILURE = 7,
- ALREADY_EXISTS = 8,
- ALLOCATE_FILE_REGION_FAILURE = 9,
- FSTAT_FAILURE = 10,
- INODES_MISMATCH = 11,
- GET_SHMEM_TEMP_DIR_FAILURE = 12,
- kMaxValue = GET_SHMEM_TEMP_DIR_FAILURE
- };
- #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- // Structure to limit access to executable region creation.
- struct ExecutableRegion {
- private:
- // Creates a new shared memory region the unsafe mode (writable and not and
- // convertible to read-only), and in addition marked executable. A ScopedFD
- // to this region is returned. Any any mapping will have to be done
- // manually, including setting executable permissions if necessary
- //
- // This is only used to support sandbox_ipc_linux.cc, and should not be used
- // anywhere else in chrome. This is restricted via AllowCreateExecutable.
- // TODO(crbug.com/982879): remove this when NaCl is unshipped.
- //
- // Returns an invalid ScopedFD if the call fails.
- static ScopedFD CreateFD(size_t size);
- friend class content::SandboxIPCHandler;
- };
- #endif
- // The minimum alignment in bytes that any mapped address produced by Map()
- // and MapAt() is guaranteed to have.
- enum { kMapMinimumAlignment = 32 };
- // Creates a new PlatformSharedMemoryRegion with corresponding mode and size.
- // Creating in kReadOnly mode isn't supported because then there will be no
- // way to modify memory content.
- static PlatformSharedMemoryRegion CreateWritable(size_t size);
- static PlatformSharedMemoryRegion CreateUnsafe(size_t size);
- // Returns a new PlatformSharedMemoryRegion that takes ownership of the
- // |handle|. All parameters must be taken from another valid
- // PlatformSharedMemoryRegion instance, e.g. |size| must be equal to the
- // actual region size as allocated by the kernel.
- // Closes the |handle| and returns an invalid instance if passed parameters
- // are invalid.
- static PlatformSharedMemoryRegion Take(
- ScopedPlatformSharedMemoryHandle handle,
- Mode mode,
- size_t size,
- const UnguessableToken& guid);
- #if BUILDFLAG(IS_POSIX) && !BUILDFLAG(IS_ANDROID) && !BUILDFLAG(IS_APPLE)
- // Specialized version of Take() for POSIX that takes only one file descriptor
- // instead of pair. Cannot be used with kWritable |mode|.
- static PlatformSharedMemoryRegion Take(ScopedFD handle,
- Mode mode,
- size_t size,
- const UnguessableToken& guid);
- #endif
- // Default constructor initializes an invalid instance, i.e. an instance that
- // doesn't wrap any valid platform handle.
- PlatformSharedMemoryRegion();
- // Move operations are allowed.
- PlatformSharedMemoryRegion(PlatformSharedMemoryRegion&&);
- PlatformSharedMemoryRegion& operator=(PlatformSharedMemoryRegion&&);
- PlatformSharedMemoryRegion(const PlatformSharedMemoryRegion&) = delete;
- PlatformSharedMemoryRegion& operator=(const PlatformSharedMemoryRegion&) =
- delete;
- // Destructor closes the platform handle. Does nothing if the handle is
- // invalid.
- ~PlatformSharedMemoryRegion();
- // Passes ownership of the platform handle to the caller. The current instance
- // becomes invalid. It's the responsibility of the caller to close the
- // handle. If the current instance is invalid, ScopedPlatformHandle will also
- // be invalid.
- [[nodiscard]] ScopedPlatformSharedMemoryHandle PassPlatformHandle();
- // Returns the platform handle. The current instance keeps ownership of this
- // handle.
- PlatformSharedMemoryHandle GetPlatformHandle() const;
- // Whether the platform handle is valid.
- bool IsValid() const;
- // Duplicates the platform handle and creates a new PlatformSharedMemoryRegion
- // with the same |mode_|, |size_| and |guid_| that owns this handle. Returns
- // invalid region on failure, the current instance remains valid.
- // Can be called only in kReadOnly and kUnsafe modes, CHECK-fails if is
- // called in kWritable mode.
- PlatformSharedMemoryRegion Duplicate() const;
- // Converts the region to read-only. Returns whether the operation succeeded.
- // Makes the current instance invalid on failure. Can be called only in
- // kWritable mode, all other modes will CHECK-fail. The object will have
- // kReadOnly mode after this call on success.
- bool ConvertToReadOnly();
- #if BUILDFLAG(IS_APPLE)
- // Same as above, but |mapped_addr| is used as a hint to avoid additional
- // mapping of the memory object.
- // |mapped_addr| must be mapped location of |memory_object_|. If the location
- // is unknown, |mapped_addr| should be |nullptr|.
- bool ConvertToReadOnly(void* mapped_addr);
- #endif // BUILDFLAG(IS_APPLE)
- // Converts the region to unsafe. Returns whether the operation succeeded.
- // Makes the current instance invalid on failure. Can be called only in
- // kWritable mode, all other modes will CHECK-fail. The object will have
- // kUnsafe mode after this call on success.
- bool ConvertToUnsafe();
- // Maps |size| bytes of the shared memory region starting with the given
- // |offset| into the caller's address space using the provided
- // |SharedMemoryMapper|. |offset| must be aligned to value of
- // |SysInfo::VMAllocationGranularity()|. Fails if requested bytes are out of
- // the region limits. Returns the mapping as span on success, or absl::nullopt
- // on failure. The mapped address is guaranteed to have an alignment of at
- // least |kMapMinimumAlignment|.
- absl::optional<span<uint8_t>> MapAt(uint64_t offset,
- size_t size,
- SharedMemoryMapper* mapper) const;
- const UnguessableToken& GetGUID() const { return guid_; }
- size_t GetSize() const { return size_; }
- Mode GetMode() const { return mode_; }
- private:
- FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
- CreateReadOnlyRegionDeathTest);
- FRIEND_TEST_ALL_PREFIXES(PlatformSharedMemoryRegionTest,
- CheckPlatformHandlePermissionsCorrespondToMode);
- static PlatformSharedMemoryRegion Create(Mode mode,
- size_t size
- #if BUILDFLAG(IS_LINUX) || BUILDFLAG(IS_CHROMEOS)
- ,
- bool executable = false
- #endif
- );
- static bool CheckPlatformHandlePermissionsCorrespondToMode(
- PlatformSharedMemoryHandle handle,
- Mode mode,
- size_t size);
- PlatformSharedMemoryRegion(ScopedPlatformSharedMemoryHandle handle,
- Mode mode,
- size_t size,
- const UnguessableToken& guid);
- ScopedPlatformSharedMemoryHandle handle_;
- Mode mode_ = Mode::kReadOnly;
- size_t size_ = 0;
- UnguessableToken guid_;
- };
- } // namespace subtle
- } // namespace base
- #endif // BASE_MEMORY_PLATFORM_SHARED_MEMORY_REGION_H_
|