Skip to main content

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}