1use 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#[derive(Debug, Clone, Copy, PartialEq, Eq)]
17pub struct CapManagerConfig {
18 pub max_delegation_depth: u8,
20 pub track_derivation: bool,
22 pub initial_epoch: u32,
24}
25
26impl CapManagerConfig {
27 #[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 #[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#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
55pub struct ManagerStats {
56 pub caps_created: u64,
58 pub caps_granted: u64,
60 pub caps_revoked: u64,
62 pub revoke_operations: u64,
64 pub max_depth_reached: u8,
66}
67
68pub 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 #[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 #[must_use]
110 pub const fn with_defaults() -> Self {
111 Self::new(CapManagerConfig::new())
112 }
113
114 #[inline]
116 #[must_use]
117 pub const fn config(&self) -> &CapManagerConfig {
118 &self.config
119 }
120
121 #[inline]
123 #[must_use]
124 pub const fn stats(&self) -> &ManagerStats {
125 &self.stats
126 }
127
128 #[inline]
130 #[must_use]
131 pub const fn epoch(&self) -> u32 {
132 self.epoch
133 }
134
135 #[inline]
137 #[must_use]
138 pub const fn len(&self) -> usize {
139 self.table.len()
140 }
141
142 #[inline]
144 #[must_use]
145 pub const fn is_empty(&self) -> bool {
146 self.table.is_empty()
147 }
148
149 pub fn increment_epoch(&mut self) {
151 self.epoch = self.epoch.wrapping_add(1);
152 self.verifier.set_epoch(self.epoch);
153 }
154
155 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 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 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 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 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 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 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 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 self.table.force_invalidate(child_index);
319 return Err(e);
320 }
321 }
322
323 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 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 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 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 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 #[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 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), );
588 assert_eq!(result, Err(CapError::GrantNotPermitted));
589 }
590}