Skip to main content

ruvix_types/
capability.rs

1//! Capability types for kernel object access control.
2//!
3//! Every kernel object is accessed exclusively through capabilities.
4//! A capability is an unforgeable kernel-managed token comprising an
5//! object identifier, type, rights bitmap, badge, and epoch.
6
7use crate::handle::Handle;
8use crate::object::ObjectType;
9
10/// Handle to a capability entry in the capability table.
11#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
12#[repr(transparent)]
13pub struct CapHandle(pub Handle);
14
15impl CapHandle {
16    /// Creates a new capability handle.
17    #[inline]
18    #[must_use]
19    pub const fn new(id: u32, generation: u32) -> Self {
20        Self(Handle::new(id, generation))
21    }
22
23    /// Creates a null (invalid) capability handle.
24    #[inline]
25    #[must_use]
26    pub const fn null() -> Self {
27        Self(Handle::null())
28    }
29
30    /// Checks if this handle is null.
31    #[inline]
32    #[must_use]
33    pub const fn is_null(&self) -> bool {
34        self.0.is_null()
35    }
36
37    /// Returns the raw handle.
38    #[inline]
39    #[must_use]
40    pub const fn raw(&self) -> Handle {
41        self.0
42    }
43}
44
45impl Default for CapHandle {
46    fn default() -> Self {
47        Self::null()
48    }
49}
50
51/// Capability rights bitmap.
52///
53/// Rights determine what operations are permitted on the capability's target object.
54/// Rights are checked at syscall time and cannot be escalated.
55#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
56#[repr(transparent)]
57pub struct CapRights(u32);
58
59impl CapRights {
60    /// Right to read from the object (e.g., `vector_get`, `queue_recv`).
61    pub const READ: Self = Self(0b0000_0001);
62
63    /// Right to write to the object (e.g., `queue_send`, region writes).
64    pub const WRITE: Self = Self(0b0000_0010);
65
66    /// Right to grant this capability to other tasks via `cap_grant`.
67    pub const GRANT: Self = Self(0b0000_0100);
68
69    /// Right to revoke capabilities derived from this one.
70    pub const REVOKE: Self = Self(0b0000_1000);
71
72    /// Right to execute (e.g., task entry point, RVF component).
73    pub const EXECUTE: Self = Self(0b0001_0000);
74
75    /// Right to generate proof tokens for this object.
76    /// Required for `vector_put_proved` and `graph_apply_proved`.
77    pub const PROVE: Self = Self(0b0010_0000);
78
79    /// Non-transitive grant right (cannot be further delegated).
80    /// See Section 20.2 of ADR-087.
81    pub const GRANT_ONCE: Self = Self(0b0100_0000);
82
83    /// No rights.
84    pub const NONE: Self = Self(0);
85
86    /// All rights.
87    pub const ALL: Self = Self(0b0111_1111);
88
89    /// Creates a new `CapRights` from a raw value.
90    #[inline]
91    #[must_use]
92    pub const fn from_bits(bits: u32) -> Self {
93        Self(bits)
94    }
95
96    /// Returns the raw bits.
97    #[inline]
98    #[must_use]
99    pub const fn bits(&self) -> u32 {
100        self.0
101    }
102
103    /// Checks if no rights are set.
104    #[inline]
105    #[must_use]
106    pub const fn is_empty(&self) -> bool {
107        self.0 == 0
108    }
109
110    /// Checks if all specified rights are set.
111    #[inline]
112    #[must_use]
113    pub const fn contains(&self, other: Self) -> bool {
114        (self.0 & other.0) == other.0
115    }
116
117    /// Returns the union of two rights sets.
118    #[inline]
119    #[must_use]
120    pub const fn union(self, other: Self) -> Self {
121        Self(self.0 | other.0)
122    }
123
124    /// Returns the intersection of two rights sets.
125    #[inline]
126    #[must_use]
127    pub const fn intersection(self, other: Self) -> Self {
128        Self(self.0 & other.0)
129    }
130
131    /// Returns the difference (rights in self but not in other).
132    #[inline]
133    #[must_use]
134    pub const fn difference(self, other: Self) -> Self {
135        Self(self.0 & !other.0)
136    }
137
138    /// Checks if this rights set is a subset of another (can be derived from it).
139    #[inline]
140    #[must_use]
141    pub const fn is_subset_of(&self, other: Self) -> bool {
142        (self.0 & other.0) == self.0
143    }
144}
145
146impl Default for CapRights {
147    fn default() -> Self {
148        Self::NONE
149    }
150}
151
152impl core::ops::BitOr for CapRights {
153    type Output = Self;
154
155    fn bitor(self, rhs: Self) -> Self::Output {
156        self.union(rhs)
157    }
158}
159
160impl core::ops::BitAnd for CapRights {
161    type Output = Self;
162
163    fn bitand(self, rhs: Self) -> Self::Output {
164        self.intersection(rhs)
165    }
166}
167
168impl core::ops::BitOrAssign for CapRights {
169    fn bitor_assign(&mut self, rhs: Self) {
170        self.0 |= rhs.0;
171    }
172}
173
174impl core::ops::BitAndAssign for CapRights {
175    fn bitand_assign(&mut self, rhs: Self) {
176        self.0 &= rhs.0;
177    }
178}
179
180/// A capability is a kernel-managed, unforgeable access token.
181///
182/// Capabilities follow seL4's design principles:
183/// - No syscall succeeds without an appropriate capability handle
184/// - A task can only grant capabilities it holds, with equal or fewer rights
185/// - Revoking a capability invalidates all derived capabilities
186#[derive(Debug, Clone, Copy, PartialEq, Eq)]
187#[repr(C)]
188pub struct Capability {
189    /// Unique identifier for the kernel object.
190    pub object_id: u64,
191
192    /// The type of kernel object.
193    pub object_type: ObjectType,
194
195    /// Rights bitmap determining permitted operations.
196    pub rights: CapRights,
197
198    /// Caller-visible identifier for demultiplexing.
199    /// Allows a task to distinguish between multiple capabilities
200    /// to the same underlying object.
201    pub badge: u64,
202
203    /// Epoch counter for capability revocation.
204    /// Invalidated if the object is destroyed or the capability is revoked.
205    pub epoch: u64,
206}
207
208impl Capability {
209    /// Creates a new capability.
210    #[inline]
211    #[must_use]
212    pub const fn new(
213        object_id: u64,
214        object_type: ObjectType,
215        rights: CapRights,
216        badge: u64,
217        epoch: u64,
218    ) -> Self {
219        Self {
220            object_id,
221            object_type,
222            rights,
223            badge,
224            epoch,
225        }
226    }
227
228    /// Checks if this capability has the specified rights.
229    #[inline]
230    #[must_use]
231    pub const fn has_rights(&self, required: CapRights) -> bool {
232        self.rights.contains(required)
233    }
234
235    /// Creates a derived capability with reduced rights.
236    ///
237    /// Returns `None` if the requested rights are not a subset of current rights,
238    /// or if attempting to derive from a `GRANT_ONCE` capability.
239    #[inline]
240    #[must_use]
241    pub fn derive(&self, new_rights: CapRights, new_badge: u64) -> Option<Self> {
242        // Cannot derive if we don't have GRANT right
243        if !self.has_rights(CapRights::GRANT) {
244            return None;
245        }
246
247        // Cannot derive with more rights than we have
248        if !new_rights.is_subset_of(self.rights) {
249            return None;
250        }
251
252        // GRANT_ONCE means the derived capability cannot have GRANT
253        let final_rights = if self.rights.contains(CapRights::GRANT_ONCE) {
254            new_rights.difference(CapRights::GRANT).difference(CapRights::GRANT_ONCE)
255        } else {
256            new_rights
257        };
258
259        Some(Self {
260            object_id: self.object_id,
261            object_type: self.object_type,
262            rights: final_rights,
263            badge: new_badge,
264            epoch: self.epoch,
265        })
266    }
267}
268
269#[cfg(test)]
270mod tests {
271    use super::*;
272
273    #[test]
274    fn test_cap_rights_operations() {
275        let rw = CapRights::READ | CapRights::WRITE;
276        assert!(rw.contains(CapRights::READ));
277        assert!(rw.contains(CapRights::WRITE));
278        assert!(!rw.contains(CapRights::GRANT));
279    }
280
281    #[test]
282    fn test_cap_rights_subset() {
283        let read = CapRights::READ;
284        let read_write = CapRights::READ | CapRights::WRITE;
285        assert!(read.is_subset_of(read_write));
286        assert!(!read_write.is_subset_of(read));
287    }
288
289    #[test]
290    fn test_capability_derive() {
291        let cap = Capability::new(
292            1,
293            ObjectType::Region,
294            CapRights::READ | CapRights::WRITE | CapRights::GRANT,
295            0,
296            1,
297        );
298
299        // Can derive with fewer rights
300        let derived = cap.derive(CapRights::READ, 42).unwrap();
301        assert_eq!(derived.rights, CapRights::READ);
302        assert_eq!(derived.badge, 42);
303        assert_eq!(derived.object_id, cap.object_id);
304    }
305
306    #[test]
307    fn test_capability_derive_fails_without_grant() {
308        let cap = Capability::new(1, ObjectType::Region, CapRights::READ, 0, 1);
309        assert!(cap.derive(CapRights::READ, 0).is_none());
310    }
311
312    #[test]
313    fn test_capability_derive_fails_with_more_rights() {
314        let cap = Capability::new(
315            1,
316            ObjectType::Region,
317            CapRights::READ | CapRights::GRANT,
318            0,
319            1,
320        );
321        assert!(cap.derive(CapRights::READ | CapRights::WRITE, 0).is_none());
322    }
323
324    #[test]
325    fn test_grant_once() {
326        let cap = Capability::new(
327            1,
328            ObjectType::Region,
329            CapRights::READ | CapRights::GRANT | CapRights::GRANT_ONCE,
330            0,
331            1,
332        );
333
334        // Derived capability should not have GRANT
335        let derived = cap.derive(CapRights::READ | CapRights::GRANT, 0).unwrap();
336        assert!(!derived.rights.contains(CapRights::GRANT));
337    }
338}