Skip to main content

rvm_cap/
manager.rs

1//! Main capability manager tying together table, derivation tree, and verifier.
2//!
3//! The `CapabilityManager` is the single integration point for all
4//! capability operations: create, grant, revoke, verify.
5
6use crate::derivation::DerivationTree;
7use crate::error::{CapError, CapResult, ProofError};
8use crate::grant::{validate_grant, GrantPolicy};
9use crate::revoke::{revoke_capability, RevokeResult};
10use crate::table::CapabilityTable;
11use crate::verify::{PolicyContext, ProofVerifier};
12use crate::DEFAULT_CAP_TABLE_CAPACITY;
13use rvm_types::{CapRights, CapToken, CapType, PartitionId};
14
15/// Configuration for the capability manager.
16#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct CapManagerConfig {
18    /// Maximum delegation depth (default: 8).
19    pub max_delegation_depth: u8,
20    /// Whether to track derivation chains (for revocation propagation).
21    pub track_derivation: bool,
22    /// Initial epoch value.
23    pub initial_epoch: u32,
24}
25
26impl CapManagerConfig {
27    /// Creates a new configuration with default values.
28    #[inline]
29    #[must_use]
30    pub const fn new() -> Self {
31        Self {
32            max_delegation_depth: crate::DEFAULT_MAX_DELEGATION_DEPTH,
33            track_derivation: true,
34            initial_epoch: 0,
35        }
36    }
37
38    /// Sets a custom maximum delegation depth.
39    #[inline]
40    #[must_use]
41    pub const fn with_max_depth(mut self, depth: u8) -> Self {
42        self.max_delegation_depth = depth;
43        self
44    }
45}
46
47impl Default for CapManagerConfig {
48    fn default() -> Self {
49        Self::new()
50    }
51}
52
53/// Statistics about capability manager operations.
54#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
55pub struct ManagerStats {
56    /// Total capabilities created.
57    pub caps_created: u64,
58    /// Total capabilities granted (derived).
59    pub caps_granted: u64,
60    /// Total capabilities revoked.
61    pub caps_revoked: u64,
62    /// Total revoke operations.
63    pub revoke_operations: u64,
64    /// Maximum derivation depth reached.
65    pub max_depth_reached: u8,
66}
67
68/// The main capability manager.
69///
70/// Coordinates capability table, derivation tree, and proof verifier
71/// to provide complete capability lifecycle management.
72pub struct CapabilityManager<const N: usize = DEFAULT_CAP_TABLE_CAPACITY> {
73    table: CapabilityTable<N>,
74    derivation: DerivationTree<N>,
75    verifier: ProofVerifier<N>,
76    config: CapManagerConfig,
77    grant_policy: GrantPolicy,
78    epoch: u32,
79    next_id: u64,
80    stats: ManagerStats,
81}
82
83impl<const N: usize> CapabilityManager<N> {
84    /// Creates a new capability manager with the given configuration.
85    #[must_use]
86    pub const fn new(config: CapManagerConfig) -> Self {
87        Self {
88            table: CapabilityTable::new(),
89            derivation: DerivationTree::new(),
90            verifier: ProofVerifier::new(config.initial_epoch),
91            grant_policy: GrantPolicy {
92                max_depth: config.max_delegation_depth,
93                allow_grant_once: true,
94            },
95            epoch: config.initial_epoch,
96            next_id: 1,
97            config,
98            stats: ManagerStats {
99                caps_created: 0,
100                caps_granted: 0,
101                caps_revoked: 0,
102                revoke_operations: 0,
103                max_depth_reached: 0,
104            },
105        }
106    }
107
108    /// Creates a new capability manager with default configuration.
109    #[must_use]
110    pub const fn with_defaults() -> Self {
111        Self::new(CapManagerConfig::new())
112    }
113
114    /// Returns the current configuration.
115    #[inline]
116    #[must_use]
117    pub const fn config(&self) -> &CapManagerConfig {
118        &self.config
119    }
120
121    /// Returns the current statistics.
122    #[inline]
123    #[must_use]
124    pub const fn stats(&self) -> &ManagerStats {
125        &self.stats
126    }
127
128    /// Returns the current epoch.
129    #[inline]
130    #[must_use]
131    pub const fn epoch(&self) -> u32 {
132        self.epoch
133    }
134
135    /// Returns the number of active capabilities.
136    #[inline]
137    #[must_use]
138    pub const fn len(&self) -> usize {
139        self.table.len()
140    }
141
142    /// Returns true if there are no active capabilities.
143    #[inline]
144    #[must_use]
145    pub const fn is_empty(&self) -> bool {
146        self.table.is_empty()
147    }
148
149    /// Increments the global epoch, invalidating stale handles.
150    pub fn increment_epoch(&mut self) {
151        self.epoch = self.epoch.wrapping_add(1);
152        self.verifier.set_epoch(self.epoch);
153    }
154
155    /// Creates a root capability for a new kernel object (unchecked).
156    ///
157    /// This is the kernel-internal path; for authorization-checked
158    /// creation, use [`create_root_capability_checked`](Self::create_root_capability_checked).
159    ///
160    /// # Errors
161    ///
162    /// Returns a [`CapError`] if the table is full or the derivation tree cannot be updated.
163    pub fn create_root_capability(
164        &mut self,
165        cap_type: CapType,
166        rights: CapRights,
167        badge: u64,
168        owner: PartitionId,
169    ) -> CapResult<(u32, u32)> {
170        self.create_root_capability_inner(cap_type, rights, badge, owner)
171    }
172
173    /// Creates a root capability with authorization check.
174    ///
175    /// Only `PartitionId::HYPERVISOR` (the hypervisor itself) is
176    /// authorized to create root capabilities. All other callers are
177    /// rejected with [`CapError::GrantNotPermitted`].
178    ///
179    /// # Errors
180    ///
181    /// Returns [`CapError::GrantNotPermitted`] if `caller_id` is not the hypervisor.
182    /// Returns a [`CapError`] if the table is full or the derivation tree cannot be updated.
183    pub fn create_root_capability_checked(
184        &mut self,
185        cap_type: CapType,
186        rights: CapRights,
187        badge: u64,
188        owner: PartitionId,
189        caller_id: PartitionId,
190    ) -> CapResult<(u32, u32)> {
191        if !caller_id.is_hypervisor() {
192            return Err(CapError::GrantNotPermitted);
193        }
194        self.create_root_capability_inner(cap_type, rights, badge, owner)
195    }
196
197    /// Internal root capability creation (shared implementation).
198    fn create_root_capability_inner(
199        &mut self,
200        cap_type: CapType,
201        rights: CapRights,
202        badge: u64,
203        owner: PartitionId,
204    ) -> CapResult<(u32, u32)> {
205        let id = self.next_id;
206        self.next_id = self.next_id.checked_add(1).ok_or(CapError::TableFull)?;
207
208        let token = CapToken::new(id, cap_type, rights, self.epoch);
209        let (index, generation) = self.table.insert_root(token, owner, badge)?;
210
211        if self.config.track_derivation {
212            self.derivation.add_root(index, u64::from(self.epoch))?;
213        }
214
215        self.stats.caps_created = self.stats.caps_created.wrapping_add(1);
216        Ok((index, generation))
217    }
218
219    /// Grants a derived capability to another partition.
220    ///
221    /// `caller_id` identifies the partition performing the grant and is
222    /// checked against the source capability's owner. Pass `None` to
223    /// skip the owner check (kernel-internal use only).
224    ///
225    /// # Errors
226    ///
227    /// Returns a [`CapError`] if the source is invalid, the caller does
228    /// not own the source, rights escalation is attempted, or the
229    /// delegation depth limit is exceeded.
230    pub fn grant(
231        &mut self,
232        source_index: u32,
233        source_generation: u32,
234        requested_rights: CapRights,
235        badge: u64,
236        target_owner: PartitionId,
237    ) -> CapResult<(u32, u32)> {
238        self.grant_with_caller(
239            source_index,
240            source_generation,
241            requested_rights,
242            badge,
243            target_owner,
244            None,
245        )
246    }
247
248    /// Like [`grant`](Self::grant) but verifies the caller owns the
249    /// source capability.
250    ///
251    /// # Errors
252    ///
253    /// Returns a [`CapError`] if the source capability is invalid, stale,
254    /// or not owned by `caller_id`, or if the requested rights exceed those
255    /// of the source capability.
256    pub fn grant_checked(
257        &mut self,
258        source_index: u32,
259        source_generation: u32,
260        requested_rights: CapRights,
261        badge: u64,
262        target_owner: PartitionId,
263        caller_id: PartitionId,
264    ) -> CapResult<(u32, u32)> {
265        self.grant_with_caller(
266            source_index,
267            source_generation,
268            requested_rights,
269            badge,
270            target_owner,
271            Some(caller_id),
272        )
273    }
274
275    /// Internal grant implementation with optional caller verification.
276    fn grant_with_caller(
277        &mut self,
278        source_index: u32,
279        source_generation: u32,
280        requested_rights: CapRights,
281        badge: u64,
282        target_owner: PartitionId,
283        caller_id: Option<PartitionId>,
284    ) -> CapResult<(u32, u32)> {
285        let source_slot = self.table.lookup(source_index, source_generation)?;
286        let source_copy = *source_slot;
287
288        // Fix 6: verify the caller owns the source capability.
289        if let Some(caller) = caller_id {
290            if source_copy.owner != caller {
291                return Err(CapError::GrantNotPermitted);
292            }
293        }
294
295        let id = self.next_id;
296        self.next_id = self.next_id.checked_add(1).ok_or(CapError::TableFull)?;
297
298        let (derived_token, depth, consume_grant_once) = validate_grant(
299            &source_copy,
300            requested_rights,
301            id,
302            badge,
303            self.epoch,
304            self.grant_policy,
305        )?;
306
307        let (child_index, child_generation) =
308            self.table
309                .insert_derived(derived_token, target_owner, depth, source_index, badge)?;
310
311        // Fix 7: if derivation tracking fails, roll back the table insertion.
312        if self.config.track_derivation {
313            if let Err(e) =
314                self.derivation
315                    .add_child(source_index, child_index, depth, u64::from(self.epoch))
316            {
317                // Roll back the table insertion to prevent a slot leak.
318                self.table.force_invalidate(child_index);
319                return Err(e);
320            }
321        }
322
323        // Fix 5: consume GRANT_ONCE from the source after successful grant.
324        if consume_grant_once {
325            if let Ok(slot) = self.table.lookup_mut(source_index, source_generation) {
326                let new_rights = slot.token.rights().difference(CapRights::GRANT_ONCE);
327                slot.token = CapToken::new(
328                    slot.token.id(),
329                    slot.token.cap_type(),
330                    new_rights,
331                    slot.token.epoch(),
332                );
333            }
334        }
335
336        self.stats.caps_granted = self.stats.caps_granted.wrapping_add(1);
337        if depth > self.stats.max_depth_reached {
338            self.stats.max_depth_reached = depth;
339        }
340
341        Ok((child_index, child_generation))
342    }
343
344    /// Revokes a capability and all its descendants.
345    ///
346    /// # Errors
347    ///
348    /// Returns a [`CapError`] if the handle is invalid or already revoked.
349    pub fn revoke(&mut self, index: u32, generation: u32) -> CapResult<RevokeResult> {
350        let result = revoke_capability(&mut self.table, &mut self.derivation, index, generation)?;
351
352        self.stats.caps_revoked = self
353            .stats
354            .caps_revoked
355            .wrapping_add(result.revoked_count as u64);
356        self.stats.revoke_operations = self.stats.revoke_operations.wrapping_add(1);
357
358        Ok(result)
359    }
360
361    /// P1 verification: capability existence + rights check (< 1 us).
362    ///
363    /// # Errors
364    ///
365    /// Returns [`ProofError`] if the handle is invalid, stale, or lacks the required rights.
366    pub fn verify_p1(
367        &self,
368        cap_index: u32,
369        cap_generation: u32,
370        required_rights: CapRights,
371    ) -> Result<(), ProofError> {
372        self.verifier
373            .verify_p1(&self.table, cap_index, cap_generation, required_rights)
374    }
375
376    /// P2 verification: structural invariant validation (< 100 us).
377    ///
378    /// # Errors
379    ///
380    /// Returns [`ProofError::PolicyViolation`] if any structural check fails.
381    pub fn verify_p2(
382        &mut self,
383        cap_index: u32,
384        cap_generation: u32,
385        ctx: &PolicyContext,
386    ) -> Result<(), ProofError> {
387        self.verifier.verify_p2(
388            &self.table,
389            &self.derivation,
390            cap_index,
391            cap_generation,
392            ctx,
393        )
394    }
395
396    /// P3: Deep proof — derivation chain integrity verification.
397    ///
398    /// Walks the derivation tree from the capability back to its root,
399    /// verifying that every ancestor is valid, depth is monotonic, and
400    /// epochs are non-decreasing.
401    ///
402    /// # Errors
403    ///
404    /// Returns [`ProofError::DerivationChainBroken`] if the chain is invalid.
405    pub fn verify_p3(
406        &self,
407        cap_index: u32,
408        cap_generation: u32,
409        max_depth: u8,
410    ) -> Result<(), ProofError> {
411        self.verifier.verify_p3(
412            &self.table,
413            &self.derivation,
414            cap_index,
415            cap_generation,
416            max_depth,
417        )
418    }
419
420    /// Returns a reference to the underlying table.
421    #[must_use]
422    pub fn table(&self) -> &CapabilityTable<N> {
423        &self.table
424    }
425}
426
427impl<const N: usize> Default for CapabilityManager<N> {
428    fn default() -> Self {
429        Self::with_defaults()
430    }
431}
432
433#[cfg(test)]
434mod tests {
435    use super::*;
436    use crate::error::CapError;
437
438    fn all_rights() -> CapRights {
439        CapRights::READ
440            .union(CapRights::WRITE)
441            .union(CapRights::EXECUTE)
442            .union(CapRights::GRANT)
443            .union(CapRights::REVOKE)
444    }
445
446    #[test]
447    fn test_create_root_capability() {
448        let mut mgr = CapabilityManager::<64>::with_defaults();
449        let owner = PartitionId::new(1);
450
451        let (idx, gen) = mgr
452            .create_root_capability(CapType::Region, all_rights(), 0, owner)
453            .unwrap();
454
455        assert_eq!(mgr.len(), 1);
456        assert!(mgr.table().lookup(idx, gen).is_ok());
457        assert_eq!(mgr.stats().caps_created, 1);
458    }
459
460    #[test]
461    fn test_grant_and_verify() {
462        let mut mgr = CapabilityManager::<64>::with_defaults();
463        let owner = PartitionId::new(1);
464        let target = PartitionId::new(2);
465
466        let (root_idx, root_gen) = mgr
467            .create_root_capability(CapType::Region, all_rights(), 0, owner)
468            .unwrap();
469
470        let (child_idx, child_gen) = mgr
471            .grant(root_idx, root_gen, CapRights::READ, 42, target)
472            .unwrap();
473
474        assert_eq!(mgr.len(), 2);
475        let child = mgr.table().lookup(child_idx, child_gen).unwrap();
476        assert_eq!(child.token.rights(), CapRights::READ);
477        assert_eq!(child.depth, 1);
478    }
479
480    #[test]
481    fn test_revoke_propagation() {
482        let mut mgr = CapabilityManager::<64>::with_defaults();
483        let owner = PartitionId::new(1);
484        let target = PartitionId::new(2);
485
486        let (root_idx, root_gen) = mgr
487            .create_root_capability(CapType::Region, all_rights(), 0, owner)
488            .unwrap();
489
490        let (c1_idx, c1_gen) = mgr
491            .grant(
492                root_idx,
493                root_gen,
494                CapRights::READ.union(CapRights::GRANT),
495                1,
496                target,
497            )
498            .unwrap();
499
500        let _ = mgr
501            .grant(c1_idx, c1_gen, CapRights::READ, 2, target)
502            .unwrap();
503
504        assert_eq!(mgr.len(), 3);
505        let result = mgr.revoke(root_idx, root_gen).unwrap();
506        assert_eq!(result.revoked_count, 3);
507    }
508
509    #[test]
510    fn test_delegation_depth_limit() {
511        let config = CapManagerConfig::new().with_max_depth(2);
512        let mut mgr = CapabilityManager::<64>::new(config);
513        let owner = PartitionId::new(1);
514
515        let (i0, g0) = mgr
516            .create_root_capability(CapType::Region, all_rights(), 0, owner)
517            .unwrap();
518        let (i1, g1) = mgr.grant(i0, g0, all_rights(), 1, owner).unwrap();
519        let (i2, g2) = mgr.grant(i1, g1, all_rights(), 2, owner).unwrap();
520
521        let result = mgr.grant(i2, g2, CapRights::READ, 3, owner);
522        assert_eq!(result, Err(CapError::DelegationDepthExceeded));
523    }
524
525    #[test]
526    fn test_epoch_invalidation() {
527        let mut mgr = CapabilityManager::<64>::with_defaults();
528        let owner = PartitionId::new(1);
529
530        let (idx, gen) = mgr
531            .create_root_capability(CapType::Region, all_rights(), 0, owner)
532            .unwrap();
533        assert!(mgr.verify_p1(idx, gen, CapRights::READ).is_ok());
534
535        mgr.increment_epoch();
536        assert_eq!(
537            mgr.verify_p1(idx, gen, CapRights::READ),
538            Err(ProofError::StaleCapability)
539        );
540    }
541
542    #[test]
543    fn test_p3_root_capability_passes() {
544        let mut mgr = CapabilityManager::<64>::with_defaults();
545        let owner = PartitionId::new(1);
546        let (idx, gen) = mgr
547            .create_root_capability(CapType::Region, all_rights(), 0, owner)
548            .unwrap();
549
550        // Root capability should pass P3 (trivial chain).
551        assert!(mgr.verify_p3(idx, gen, 8).is_ok());
552    }
553
554    #[test]
555    fn test_p3_nonexistent_fails() {
556        let mgr = CapabilityManager::<64>::with_defaults();
557        assert_eq!(
558            mgr.verify_p3(99, 0, 8),
559            Err(ProofError::DerivationChainBroken),
560        );
561    }
562
563    #[test]
564    fn test_create_root_checked_hypervisor_allowed() {
565        let mut mgr = CapabilityManager::<64>::with_defaults();
566        let owner = PartitionId::new(1);
567        let result = mgr.create_root_capability_checked(
568            CapType::Region,
569            all_rights(),
570            0,
571            owner,
572            PartitionId::hypervisor(),
573        );
574        assert!(result.is_ok());
575    }
576
577    #[test]
578    fn test_create_root_checked_non_hypervisor_denied() {
579        let mut mgr = CapabilityManager::<64>::with_defaults();
580        let owner = PartitionId::new(1);
581        let result = mgr.create_root_capability_checked(
582            CapType::Region,
583            all_rights(),
584            0,
585            owner,
586            PartitionId::new(1), // non-hypervisor caller
587        );
588        assert_eq!(result, Err(CapError::GrantNotPermitted));
589    }
590}