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 ranging over
112 /// [`base`, `base + length`) and permissions `perms`.
113 ///
114 /// Provenance note: may derive from a pointer other than the input to provide something with
115 /// valid provenance to justify the other arguments.
116 ///
117 /// ## Safety
118 ///
119 /// Constructing a [`CapabilityPtr`] with metadata may convey authority to
120 /// dereference this pointer, such as in userspace. When these pointers
121 /// serve as the only memory isolation primitive in the system, this method
122 /// can thus break Tock's isolation model. As semi-trusted kernel code can
123 /// name this type and method, it is thus marked as `unsafe`.
124 ///
125 // TODO: Once Tock supports hardware that uses the [`CapabilityPtr`]'s
126 // metdata to convey authority, this comment should incorporate the exact
127 // safety conditions of this function.
128 #[inline]
129 pub unsafe fn new_with_authority(
130 ptr: *const (),
131 _base: usize,
132 _length: usize,
133 _perms: CapabilityPtrPermissions,
134 ) -> Self {
135 Self { ptr }
136 }
137
138 /// If the [`CapabilityPtr`] is null returns `default`, otherwise applies `f` to `self`.
139 #[inline]
140 pub fn map_or<U, F>(&self, default: U, f: F) -> U
141 where
142 F: FnOnce(&Self) -> U,
143 {
144 if self.ptr.is_null() {
145 default
146 } else {
147 f(self)
148 }
149 }
150
151 /// If the [`CapabilityPtr`] is null returns `default`, otherwise applies `f` to `self`.
152 /// default is only evaluated if `self` is not null.
153 #[inline]
154 pub fn map_or_else<U, D, F>(&self, default: D, f: F) -> U
155 where
156 D: FnOnce() -> U,
157 F: FnOnce(&Self) -> U,
158 {
159 if self.ptr.is_null() {
160 default()
161 } else {
162 f(self)
163 }
164 }
165}