1use crate::derivation::DerivationTree;
7use crate::error::{CapError, CapResult};
8use crate::table::CapabilityTable;
9
10#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub struct RevokeResult {
13 pub revoked_count: usize,
15}
16
17impl RevokeResult {
18 #[must_use]
20 pub const fn new(revoked_count: usize) -> Self {
21 Self { revoked_count }
22 }
23}
24
25pub fn revoke_capability<const N: usize>(
38 table: &mut CapabilityTable<N>,
39 tree: &mut DerivationTree<N>,
40 index: u32,
41 generation: u32,
42) -> CapResult<RevokeResult> {
43 let _ = table.lookup(index, generation)?;
45
46 let revoked_indices = tree.collect_subtree(index);
49
50 let revoked = tree.revoke(index).map_err(|_| CapError::Revoked)?;
52
53 for &idx in &revoked_indices {
56 table.force_invalidate(idx);
57 }
58
59 Ok(RevokeResult::new(revoked))
60}
61
62pub fn revoke_single<const N: usize>(
69 table: &mut CapabilityTable<N>,
70 index: u32,
71 generation: u32,
72) -> CapResult<()> {
73 table.remove(index, generation)
74}
75
76#[cfg(test)]
77mod tests {
78 use super::*;
79 use rvm_types::{CapRights, CapToken, CapType, PartitionId};
80
81 fn all_rights() -> CapRights {
82 CapRights::READ
83 .union(CapRights::WRITE)
84 .union(CapRights::EXECUTE)
85 .union(CapRights::GRANT)
86 .union(CapRights::REVOKE)
87 }
88
89 #[test]
90 fn test_revoke_propagation() {
91 let mut table = CapabilityTable::<64>::new();
92 let mut tree = DerivationTree::<64>::new();
93 let owner = PartitionId::new(1);
94 let token = CapToken::new(1, CapType::Region, all_rights(), 0);
95
96 let (r_idx, r_gen) = table.insert_root(token, owner, 0).unwrap();
97 tree.add_root(r_idx, 0).unwrap();
98
99 let (c1_idx, _) = table.insert_derived(token, owner, 1, r_idx, 0).unwrap();
100 tree.add_child(r_idx, c1_idx, 1, 0).unwrap();
101
102 let (c2_idx, _) = table.insert_derived(token, owner, 1, r_idx, 0).unwrap();
103 tree.add_child(r_idx, c2_idx, 1, 0).unwrap();
104
105 let (gc_idx, _) = table.insert_derived(token, owner, 2, c1_idx, 0).unwrap();
106 tree.add_child(c1_idx, gc_idx, 2, 0).unwrap();
107
108 let result = revoke_capability(&mut table, &mut tree, r_idx, r_gen).unwrap();
109 assert_eq!(result.revoked_count, 4);
110
111 assert!(!tree.is_valid(r_idx));
112 assert!(!tree.is_valid(c1_idx));
113 assert!(!tree.is_valid(c2_idx));
114 assert!(!tree.is_valid(gc_idx));
115 }
116
117 #[test]
118 fn test_revoke_single() {
119 let mut table = CapabilityTable::<64>::new();
120 let owner = PartitionId::new(1);
121 let token = CapToken::new(1, CapType::Region, all_rights(), 0);
122
123 let (idx, gen) = table.insert_root(token, owner, 0).unwrap();
124 revoke_single(&mut table, idx, gen).unwrap();
125 assert!(table.lookup(idx, gen).is_err());
126 }
127
128 #[test]
129 fn test_revoke_invalid_handle() {
130 let mut table = CapabilityTable::<64>::new();
131 let mut tree = DerivationTree::<64>::new();
132 let result = revoke_capability(&mut table, &mut tree, 99, 0);
133 assert!(result.is_err());
134 }
135}