1 // Copyright 2018 The Chromium Authors
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "base/memory/platform_shared_memory_region.h"
6
7 #include "base/bits.h"
8 #include "base/memory/aligned_memory.h"
9 #include "base/memory/shared_memory_mapping.h"
10 #include "base/memory/shared_memory_security_policy.h"
11 #include "base/metrics/histogram_functions.h"
12 #include "base/numerics/checked_math.h"
13 #include "base/system/sys_info.h"
14
15 namespace base {
16 namespace subtle {
17
18 // static
CreateWritable(size_t size)19 PlatformSharedMemoryRegion PlatformSharedMemoryRegion::CreateWritable(
20 size_t size) {
21 return Create(Mode::kWritable, size);
22 }
23
24 // static
CreateUnsafe(size_t size)25 PlatformSharedMemoryRegion PlatformSharedMemoryRegion::CreateUnsafe(
26 size_t size) {
27 return Create(Mode::kUnsafe, size);
28 }
29
30 PlatformSharedMemoryRegion::PlatformSharedMemoryRegion() = default;
31 PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
32 PlatformSharedMemoryRegion&& other) = default;
33 PlatformSharedMemoryRegion& PlatformSharedMemoryRegion::operator=(
34 PlatformSharedMemoryRegion&& other) = default;
35 PlatformSharedMemoryRegion::~PlatformSharedMemoryRegion() = default;
36
37 ScopedPlatformSharedMemoryHandle
PassPlatformHandle()38 PlatformSharedMemoryRegion::PassPlatformHandle() {
39 return std::move(handle_);
40 }
41
MapAt(uint64_t offset,size_t size,SharedMemoryMapper * mapper) const42 absl::optional<span<uint8_t>> PlatformSharedMemoryRegion::MapAt(
43 uint64_t offset,
44 size_t size,
45 SharedMemoryMapper* mapper) const {
46 if (!IsValid())
47 return absl::nullopt;
48
49 if (size == 0)
50 return absl::nullopt;
51
52 size_t end_byte;
53 if (!CheckAdd(offset, size).AssignIfValid(&end_byte) || end_byte > size_) {
54 return absl::nullopt;
55 }
56
57 // TODO(dcheng): Presumably the actual size of the mapping is rounded to
58 // `SysInfo::VMAllocationGranularity()`. Should this accounting be done with
59 // that in mind?
60 if (!SharedMemorySecurityPolicy::AcquireReservationForMapping(size)) {
61 return absl::nullopt;
62 }
63
64 if (!mapper)
65 mapper = SharedMemoryMapper::GetDefaultInstance();
66
67 // The backing mapper expects offset to be aligned to
68 // `SysInfo::VMAllocationGranularity()`.
69 uint64_t aligned_offset =
70 bits::AlignDown(offset, uint64_t{SysInfo::VMAllocationGranularity()});
71 size_t adjustment_for_alignment =
72 static_cast<size_t>(offset - aligned_offset);
73
74 bool write_allowed = mode_ != Mode::kReadOnly;
75 auto result = mapper->Map(GetPlatformHandle(), write_allowed, aligned_offset,
76 size + adjustment_for_alignment);
77
78 if (result.has_value()) {
79 DCHECK(IsAligned(result.value().data(), kMapMinimumAlignment));
80 if (offset != 0) {
81 // Undo the previous adjustment so the returned mapping respects the exact
82 // requested `offset` and `size`.
83 result = result->subspan(adjustment_for_alignment);
84 }
85 } else {
86 SharedMemorySecurityPolicy::ReleaseReservationForMapping(size);
87 }
88
89 return result;
90 }
91
Unmap(span<uint8_t> mapping,SharedMemoryMapper * mapper)92 void PlatformSharedMemoryRegion::Unmap(span<uint8_t> mapping,
93 SharedMemoryMapper* mapper) {
94 if (!mapper) {
95 mapper = SharedMemoryMapper::GetDefaultInstance();
96 }
97
98 mapper->Unmap(mapping);
99
100 SharedMemorySecurityPolicy::ReleaseReservationForMapping(mapping.size());
101 }
102
103 } // namespace subtle
104 } // namespace base
105