1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Google LLC 2024.
//! Defines the CapabilityPtr type
use core::fmt::{Formatter, LowerHex, UpperHex};
use core::ops::AddAssign;
/// A pointer to userspace memory with implied authority.
///
/// A [`CapabilityPtr`] points to memory a userspace process may be
/// permitted to read, write, or execute. It is sized exactly to a
/// CPU register that can pass values between userspace and the kernel.
/// Because it is register sized, [`CapabilityPtr`] is guaranteed to be
/// at least the size of a word ([usize]) [^note1]. Operations on the
/// pointer may affect permissions, e.g. offsetting the pointer beyond
/// the bounds of the memory object invalidates it. Like a `*const
/// ()`, a [`CapabilityPtr`] may also "hide" information by storing a
/// word of data with no memory access permissions.
///
/// [`CapabilityPtr`] should be used to store or pass a value between the
/// kernel and userspace that may represent a valid userspace reference,
/// when one party intends the other to access it.
///
/// [^note1]: Depending on the architecture, the size of a
/// [`CapabilityPtr`] may be a word size or larger, e.g., if registers
/// can store metadata such as access permissions.
#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug)]
#[repr(transparent)]
pub struct CapabilityPtr {
ptr: *const (),
}
impl Default for CapabilityPtr {
fn default() -> Self {
Self {
ptr: core::ptr::null(),
}
}
}
/// Permission sets a [`CapabilityPtr`] may grant.
/// These may not be enforced or exist on a given platform.
#[derive(Copy, Clone, PartialEq)]
pub enum CapabilityPtrPermissions {
None,
Read,
Write,
ReadWrite,
Execute,
}
impl From<CapabilityPtr> for usize {
/// Returns the address of the [`CapabilityPtr`].
/// Provenance note: may not expose provenance.
#[inline]
fn from(from: CapabilityPtr) -> Self {
from.ptr as usize
}
}
impl From<usize> for CapabilityPtr {
/// Constructs a [`CapabilityPtr`] with a given address and no authority
///
/// Provenance note: may have null provenance.
#[inline]
fn from(from: usize) -> Self {
Self {
ptr: from as *const (),
}
}
}
impl UpperHex for CapabilityPtr {
/// Format the capability as an uppercase hex string.
/// Will print at least the address, and any platform specific metadata if it exists.
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
UpperHex::fmt(&(self.ptr as usize), f)
}
}
impl LowerHex for CapabilityPtr {
/// Format the capability as a lowercase hex string.
/// Will print at least the address, and any platform specific metadata if it exists.
#[inline]
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
LowerHex::fmt(&(self.ptr as usize), f)
}
}
impl AddAssign<usize> for CapabilityPtr {
/// Increments the address of a [`CapabilityPtr`]
#[inline]
fn add_assign(&mut self, rhs: usize) {
self.ptr = (self.ptr as *const u8).wrapping_add(rhs) as *const ();
}
}
impl CapabilityPtr {
/// Returns the pointer component of a [`CapabilityPtr`] but without any of the authority.
pub fn as_ptr<T>(&self) -> *const T {
self.ptr as *const T
}
/// Construct a [`CapabilityPtr`] from a raw pointer, with authority ranging over
/// [`base`, `base + length`) and permissions `perms`.
///
/// Provenance note: may derive from a pointer other than the input to provide something with
/// valid provenance to justify the other arguments.
///
/// ## Safety
///
/// Constructing a [`CapabilityPtr`] with metadata may convey authority to
/// dereference this pointer, such as in userspace. When these pointers
/// serve as the only memory isolation primitive in the system, this method
/// can thus break Tock's isolation model. As semi-trusted kernel code can
/// name this type and method, it is thus marked as `unsafe`.
///
// TODO: Once Tock supports hardware that uses the [`CapabilityPtr`]'s
// metdata to convey authority, this comment should incorporate the exact
// safety conditions of this function.
#[inline]
pub unsafe fn new_with_authority(
ptr: *const (),
_base: usize,
_length: usize,
_perms: CapabilityPtrPermissions,
) -> Self {
Self { ptr }
}
/// If the [`CapabilityPtr`] is null returns `default`, otherwise applies `f` to `self`.
#[inline]
pub fn map_or<U, F>(&self, default: U, f: F) -> U
where
F: FnOnce(&Self) -> U,
{
if self.ptr.is_null() {
default
} else {
f(self)
}
}
/// If the [`CapabilityPtr`] is null returns `default`, otherwise applies `f` to `self`.
/// default is only evaluated if `self` is not null.
#[inline]
pub fn map_or_else<U, D, F>(&self, default: D, f: F) -> U
where
D: FnOnce() -> U,
F: FnOnce(&Self) -> U,
{
if self.ptr.is_null() {
default()
} else {
f(self)
}
}
}