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}