kernel/utilities/capability_ptr.rs
1// Licensed under the Apache License, Version 2.0 or the MIT License.
2// SPDX-License-Identifier: Apache-2.0 OR MIT
3// Copyright Google LLC 2024.
4
5//! Defines the CapabilityPtr type
6
7use core::fmt::{Formatter, LowerHex, UpperHex};
8use core::ops::AddAssign;
9use core::ptr::null;
10
11use super::machine_register::MachineRegister;
12
13/// A pointer to userspace memory with implied authority.
14///
15/// A [`CapabilityPtr`] points to memory a userspace process may be permitted to
16/// read, write, or execute. It is sized exactly to a CPU register that can pass
17/// values between userspace and the kernel [^note1]. Operations on the pointer
18/// may affect permissions, e.g. offsetting the pointer beyond the bounds of the
19/// memory object may invalidate it.
20///
21/// [`CapabilityPtr`] should be used to store or pass a value between the
22/// kernel and userspace that may represent a valid userspace reference,
23/// when one party intends the other to access it.
24///
25/// [^note1]: Depending on the architecture, the size of a
26/// [`CapabilityPtr`] may be a word size or larger, e.g., if registers
27/// can store metadata such as access permissions.
28#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
29#[repr(transparent)]
30pub struct CapabilityPtr {
31 ptr: *const (),
32}
33
34/// Permission sets a [`CapabilityPtr`] may grant.
35/// These may not be enforced or exist on a given platform.
36#[derive(Copy, Clone, PartialEq)]
37pub enum CapabilityPtrPermissions {
38 None,
39 Read,
40 Write,
41 ReadWrite,
42 Execute,
43}
44
45impl Default for CapabilityPtr {
46 /// Returns a null CapabilityPtr.
47 fn default() -> Self {
48 Self { ptr: null() }
49 }
50}
51
52impl From<usize> for CapabilityPtr {
53 /// Constructs a [`CapabilityPtr`] with a given address but no authority or
54 /// provenance.
55 #[inline]
56 fn from(from: usize) -> Self {
57 Self {
58 // Ideally this would be core::ptr::without_provenance(from), but
59 // the CHERI toolchain is too old for without_provenance. This is
60 // equivalent.
61 ptr: null::<()>().with_addr(from),
62 }
63 }
64}
65
66// In addition to its publicly-documented capabilities, CapabilityPtr's
67// implementation can also store integers. MachineRegister uses that ability to
68// simplify its implementation. No other user of CapabilityPtr should rely on
69// that ability.
70
71impl From<usize> for MachineRegister {
72 fn from(from: usize) -> Self {
73 Self::from(CapabilityPtr::from(from))
74 }
75}
76
77impl UpperHex for CapabilityPtr {
78 #[inline]
79 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
80 UpperHex::fmt(&self.ptr.addr(), f)
81 }
82}
83
84impl LowerHex for CapabilityPtr {
85 #[inline]
86 fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
87 LowerHex::fmt(&self.ptr.addr(), f)
88 }
89}
90
91impl AddAssign<usize> for CapabilityPtr {
92 /// Increments the address of a [`CapabilityPtr`]. If the pointer is offset
93 /// past its bounds, its authority may be invalidated.
94 #[inline]
95 fn add_assign(&mut self, rhs: usize) {
96 self.ptr = self.ptr.wrapping_byte_add(rhs);
97 }
98}
99
100impl CapabilityPtr {
101 /// Returns the address of this pointer. Does not expose provenance.
102 pub fn addr(self) -> usize {
103 self.ptr.addr()
104 }
105
106 /// Returns the pointer component of a [`CapabilityPtr`] but without any of the authority.
107 pub fn as_ptr<T>(&self) -> *const T {
108 self.ptr.cast()
109 }
110
111 /// Construct a [`CapabilityPtr`] from a raw pointer, with authority
112 /// ranging over [`base`, `base + length`) and permissions `perms`.
113 ///
114 /// [`CapabilityPtr`]s can be the sole memory isolation primitive in the
115 /// system, thus great care must be taken with this method, as errors can
116 /// break Tock's isolation model.
117 ///
118 /// Provenance note: may derive from a pointer other than the input to
119 /// provide something with valid provenance to justify the other arguments.
120 ///
121 /// # Safety
122 ///
123 /// NOTE: Hardware capability support is **experimental** in Tock. The
124 /// intent of this type is to capture semantics general to any hardware
125 /// capability implementation, however, there is no upstream support for
126 /// any such hardware today. As such, the exact safety conditions may
127 /// change in the future.
128 ///
129 /// Callers are responsible for ensuring that the authority conveyed by this
130 /// pointer does not violate Tock's isolation model, under an assumption
131 /// that hardware capabilities are the sole memory isolation mechanism.
132 ///
133 /// Authority is conveyed solely by the `base`, `length`, and `perms`.
134 /// The value in `ptr` may be freely changed by untrusted code. When
135 /// executing on a platform with hardware capability enforcement, callers
136 /// may assume that on any attempt to use `ptr`, hardware will verify that:
137 /// - `ptr` is within the bounds [`base`, `base + length`).
138 /// - The access type is allowed by `perms`.
139 ///
140 /// Callers are responsible for restricting access to this pointer, i.e.,
141 /// ensuring that a pointer which allows access to process memory is only
142 /// given to the *correct* process.
143 #[inline]
144 pub unsafe fn new_with_authority(
145 ptr: *const (),
146 _base: usize,
147 _length: usize,
148 _perms: CapabilityPtrPermissions,
149 ) -> Self {
150 Self { ptr }
151 }
152
153 /// If the [`CapabilityPtr`] is null returns `default`, otherwise applies `f` to `self`.
154 #[inline]
155 pub fn map_or<U, F>(&self, default: U, f: F) -> U
156 where
157 F: FnOnce(&Self) -> U,
158 {
159 if self.ptr.is_null() { default } else { f(self) }
160 }
161
162 /// If the [`CapabilityPtr`] is null returns `default`, otherwise applies `f` to `self`.
163 /// default is only evaluated if `self` is not null.
164 #[inline]
165 pub fn map_or_else<U, D, F>(&self, default: D, f: F) -> U
166 where
167 D: FnOnce() -> U,
168 F: FnOnce(&Self) -> U,
169 {
170 if self.ptr.is_null() {
171 default()
172 } else {
173 f(self)
174 }
175 }
176}