xref: /aosp_15_r20/external/cronet/base/memory/platform_shared_memory_region_fuchsia.cc (revision 6777b5387eb2ff775bb5750e3f5d96f37fb7352b)
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 <lib/zx/vmar.h>
8 #include <zircon/process.h>
9 #include <zircon/rights.h>
10 
11 #include "base/bits.h"
12 #include "base/check_op.h"
13 #include "base/fuchsia/fuchsia_logging.h"
14 #include "base/memory/page_size.h"
15 
16 namespace base {
17 namespace subtle {
18 
19 static constexpr int kNoWriteOrExec =
20     ZX_DEFAULT_VMO_RIGHTS &
21     ~(ZX_RIGHT_WRITE | ZX_RIGHT_EXECUTE | ZX_RIGHT_SET_PROPERTY);
22 
23 // static
Take(zx::vmo handle,Mode mode,size_t size,const UnguessableToken & guid)24 PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Take(
25     zx::vmo handle,
26     Mode mode,
27     size_t size,
28     const UnguessableToken& guid) {
29   if (!handle.is_valid())
30     return {};
31 
32   if (size == 0)
33     return {};
34 
35   if (size > static_cast<size_t>(std::numeric_limits<int>::max()))
36     return {};
37 
38   CHECK(CheckPlatformHandlePermissionsCorrespondToMode(zx::unowned_vmo(handle),
39                                                        mode, size));
40 
41   return PlatformSharedMemoryRegion(std::move(handle), mode, size, guid);
42 }
43 
GetPlatformHandle() const44 zx::unowned_vmo PlatformSharedMemoryRegion::GetPlatformHandle() const {
45   return zx::unowned_vmo(handle_);
46 }
47 
IsValid() const48 bool PlatformSharedMemoryRegion::IsValid() const {
49   return handle_.is_valid();
50 }
51 
Duplicate() const52 PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Duplicate() const {
53   if (!IsValid())
54     return {};
55 
56   CHECK_NE(mode_, Mode::kWritable)
57       << "Duplicating a writable shared memory region is prohibited";
58 
59   zx::vmo duped_handle;
60   zx_status_t status = handle_.duplicate(ZX_RIGHT_SAME_RIGHTS, &duped_handle);
61   if (status != ZX_OK) {
62     ZX_DLOG(ERROR, status) << "zx_handle_duplicate";
63     return {};
64   }
65 
66   return PlatformSharedMemoryRegion(std::move(duped_handle), mode_, size_,
67                                     guid_);
68 }
69 
ConvertToReadOnly()70 bool PlatformSharedMemoryRegion::ConvertToReadOnly() {
71   if (!IsValid())
72     return false;
73 
74   CHECK_EQ(mode_, Mode::kWritable)
75       << "Only writable shared memory region can be converted to read-only";
76 
77   zx_status_t status = handle_.replace(kNoWriteOrExec, &handle_);
78   if (status != ZX_OK) {
79     ZX_DLOG(ERROR, status) << "zx_handle_replace";
80     return false;
81   }
82 
83   mode_ = Mode::kReadOnly;
84   return true;
85 }
86 
ConvertToUnsafe()87 bool PlatformSharedMemoryRegion::ConvertToUnsafe() {
88   if (!IsValid())
89     return false;
90 
91   CHECK_EQ(mode_, Mode::kWritable)
92       << "Only writable shared memory region can be converted to unsafe";
93 
94   mode_ = Mode::kUnsafe;
95   return true;
96 }
97 
98 // static
Create(Mode mode,size_t size)99 PlatformSharedMemoryRegion PlatformSharedMemoryRegion::Create(Mode mode,
100                                                               size_t size) {
101   if (size == 0)
102     return {};
103 
104   // Aligning may overflow so check that the result doesn't decrease.
105   size_t rounded_size = bits::AlignUp(size, GetPageSize());
106   if (rounded_size < size ||
107       rounded_size > static_cast<size_t>(std::numeric_limits<int>::max())) {
108     return {};
109   }
110 
111   CHECK_NE(mode, Mode::kReadOnly) << "Creating a region in read-only mode will "
112                                      "lead to this region being non-modifiable";
113 
114   zx::vmo vmo;
115   zx_status_t status = zx::vmo::create(rounded_size, 0, &vmo);
116   if (status != ZX_OK) {
117     ZX_DLOG(ERROR, status) << "zx_vmo_create";
118     return {};
119   }
120 
121   // TODO(crbug.com/991805): Take base::Location from the caller and use it to
122   // generate the name here.
123   constexpr char kVmoName[] = "cr-shared-memory-region";
124   status = vmo.set_property(ZX_PROP_NAME, kVmoName, strlen(kVmoName));
125   ZX_DCHECK(status == ZX_OK, status);
126 
127   const int kNoExecFlags = ZX_DEFAULT_VMO_RIGHTS & ~ZX_RIGHT_EXECUTE;
128   status = vmo.replace(kNoExecFlags, &vmo);
129   if (status != ZX_OK) {
130     ZX_DLOG(ERROR, status) << "zx_handle_replace";
131     return {};
132   }
133 
134   return PlatformSharedMemoryRegion(std::move(vmo), mode, size,
135                                     UnguessableToken::Create());
136 }
137 
138 // static
CheckPlatformHandlePermissionsCorrespondToMode(PlatformSharedMemoryHandle handle,Mode mode,size_t size)139 bool PlatformSharedMemoryRegion::CheckPlatformHandlePermissionsCorrespondToMode(
140     PlatformSharedMemoryHandle handle,
141     Mode mode,
142     size_t size) {
143   zx_info_handle_basic_t basic = {};
144   zx_status_t status = handle->get_info(ZX_INFO_HANDLE_BASIC, &basic,
145                                         sizeof(basic), nullptr, nullptr);
146   ZX_CHECK(status == ZX_OK, status) << "zx_object_get_info";
147 
148   if (basic.type != ZX_OBJ_TYPE_VMO) {
149     // TODO(crbug.com/838365): convert to DLOG when bug fixed.
150     LOG(ERROR) << "Received zircon handle is not a VMO";
151     return false;
152   }
153 
154   bool is_read_only = (basic.rights & (ZX_RIGHT_WRITE | ZX_RIGHT_EXECUTE)) == 0;
155   bool expected_read_only = mode == Mode::kReadOnly;
156 
157   if (is_read_only != expected_read_only) {
158     // TODO(crbug.com/838365): convert to DLOG when bug fixed.
159     LOG(ERROR) << "VMO object has wrong access rights: it is"
160                << (is_read_only ? " " : " not ") << "read-only but it should"
161                << (expected_read_only ? " " : " not ") << "be";
162     return false;
163   }
164 
165   return true;
166 }
167 
PlatformSharedMemoryRegion(zx::vmo handle,Mode mode,size_t size,const UnguessableToken & guid)168 PlatformSharedMemoryRegion::PlatformSharedMemoryRegion(
169     zx::vmo handle,
170     Mode mode,
171     size_t size,
172     const UnguessableToken& guid)
173     : handle_(std::move(handle)), mode_(mode), size_(size), guid_(guid) {}
174 
175 }  // namespace subtle
176 }  // namespace base
177