use crate::derivation::DerivationTree;
use crate::error::{CapError, CapResult};
use crate::table::CapabilityTable;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct RevokeResult {
pub revoked_count: usize,
}
impl RevokeResult {
#[must_use]
pub const fn new(revoked_count: usize) -> Self {
Self { revoked_count }
}
}
pub fn revoke_capability<const N: usize>(
table: &mut CapabilityTable<N>,
tree: &mut DerivationTree<N>,
index: u32,
generation: u32,
) -> CapResult<RevokeResult> {
let _ = table.lookup(index, generation)?;
let revoked_indices = tree.collect_subtree(index);
let revoked = tree.revoke(index).map_err(|_| CapError::Revoked)?;
for &idx in &revoked_indices {
table.force_invalidate(idx);
}
Ok(RevokeResult::new(revoked))
}
pub fn revoke_single<const N: usize>(
table: &mut CapabilityTable<N>,
index: u32,
generation: u32,
) -> CapResult<()> {
table.remove(index, generation)
}
#[cfg(test)]
mod tests {
use super::*;
use rvm_types::{CapRights, CapToken, CapType, PartitionId};
fn all_rights() -> CapRights {
CapRights::READ
.union(CapRights::WRITE)
.union(CapRights::EXECUTE)
.union(CapRights::GRANT)
.union(CapRights::REVOKE)
}
#[test]
fn test_revoke_propagation() {
let mut table = CapabilityTable::<64>::new();
let mut tree = DerivationTree::<64>::new();
let owner = PartitionId::new(1);
let token = CapToken::new(1, CapType::Region, all_rights(), 0);
let (r_idx, r_gen) = table.insert_root(token, owner, 0).unwrap();
tree.add_root(r_idx, 0).unwrap();
let (c1_idx, _) = table.insert_derived(token, owner, 1, r_idx, 0).unwrap();
tree.add_child(r_idx, c1_idx, 1, 0).unwrap();
let (c2_idx, _) = table.insert_derived(token, owner, 1, r_idx, 0).unwrap();
tree.add_child(r_idx, c2_idx, 1, 0).unwrap();
let (gc_idx, _) = table.insert_derived(token, owner, 2, c1_idx, 0).unwrap();
tree.add_child(c1_idx, gc_idx, 2, 0).unwrap();
let result = revoke_capability(&mut table, &mut tree, r_idx, r_gen).unwrap();
assert_eq!(result.revoked_count, 4);
assert!(!tree.is_valid(r_idx));
assert!(!tree.is_valid(c1_idx));
assert!(!tree.is_valid(c2_idx));
assert!(!tree.is_valid(gc_idx));
}
#[test]
fn test_revoke_single() {
let mut table = CapabilityTable::<64>::new();
let owner = PartitionId::new(1);
let token = CapToken::new(1, CapType::Region, all_rights(), 0);
let (idx, gen) = table.insert_root(token, owner, 0).unwrap();
revoke_single(&mut table, idx, gen).unwrap();
assert!(table.lookup(idx, gen).is_err());
}
#[test]
fn test_revoke_invalid_handle() {
let mut table = CapabilityTable::<64>::new();
let mut tree = DerivationTree::<64>::new();
let result = revoke_capability(&mut table, &mut tree, 99, 0);
assert!(result.is_err());
}
}