use super::*; use types::generation::Generation; use types::id::{EndpointId, RegionId}; use types::permission::{Permission, PermissionSet}; fn perms(permissions: &[Permission]) -> PermissionSet { permissions .iter() .fold(PermissionSet::empty(), |set, &p| set.with(p)) } fn endpoint_cap(id: u16, permissions: &[Permission]) -> Capability { Capability::new( Resource::Endpoint(EndpointId::from_raw(id)), perms(permissions), Generation::initial(), ) } fn memory_cap(id: u16, permissions: &[Permission]) -> Capability { Capability::new( Resource::Memory(RegionId::from_raw(id)), perms(permissions), Generation::initial(), ) } #[test] fn new_table_is_empty() { let table = CapabilityTable::new(); let slot = CapSlot::new(0).unwrap(); assert!(table.get(slot).is_err()); } #[test] fn insert_and_get() { let mut table = CapabilityTable::new(); let slot = table.insert(endpoint_cap(1, &[Permission::Read])).unwrap(); let retrieved = table.get(slot).unwrap(); assert!(retrieved.permissions().allows(Permission::Read)); assert!(!retrieved.permissions().allows(Permission::Write)); } #[test] fn remove_then_get_fails() { let mut table = CapabilityTable::new(); let slot = table.insert(endpoint_cap(1, &[Permission::Read])).unwrap(); table.remove(slot).unwrap(); assert!(table.get(slot).is_err()); } #[test] fn remove_invalid_slot_fails() { let mut table = CapabilityTable::new(); let slot = CapSlot::new(5).unwrap(); assert!(table.remove(slot).is_err()); } #[test] fn insert_reuses_removed_slot() { let mut table = CapabilityTable::new(); let slot = table.insert(endpoint_cap(1, &[Permission::Read])).unwrap(); table.remove(slot).unwrap(); let new_slot = table.insert(endpoint_cap(2, &[Permission::Write])).unwrap(); assert_eq!(slot, new_slot); } #[test] fn full_table_returns_no_free_slot() { let mut table = CapabilityTable::new(); for i in 0..MAX_CAPS_PER_PROCESS { assert!( table .insert(endpoint_cap(i as u16, &[Permission::Read])) .is_ok() ); } assert!(table.insert(endpoint_cap(999, &[])).is_err()); } #[test] fn generation_mismatch_detected() { let gen_v1 = Generation::initial(); let gen_v2 = gen_v1.next().unwrap(); assert!(gen_v1.is_valid_against(&gen_v1)); assert!(!gen_v1.is_valid_against(&gen_v2)); } #[test] fn restrict_to_never_escalates() { let full = perms(&[Permission::Read, Permission::Write, Permission::Execute]); let read_only = perms(&[Permission::Read]); let restricted = full.restrict_to(&read_only); assert!(restricted.allows(Permission::Read)); assert!(!restricted.allows(Permission::Write)); assert!(!restricted.allows(Permission::Execute)); } #[test] fn restrict_to_cannot_add_permissions() { let read_only = perms(&[Permission::Read]); let wants_everything = perms(&[ Permission::Read, Permission::Write, Permission::Execute, Permission::Delegate, ]); let result = read_only.restrict_to(&wants_everything); assert!(result.allows(Permission::Read)); assert!(!result.allows(Permission::Write)); assert!(!result.allows(Permission::Execute)); assert!(!result.allows(Permission::Delegate)); } #[test] fn is_subset_of() { let rw = perms(&[Permission::Read, Permission::Write]); let read_only = perms(&[Permission::Read]); assert!(read_only.is_subset_of(&rw)); assert!(!rw.is_subset_of(&read_only)); } #[test] fn empty_permission_set_allows_nothing() { let empty = PermissionSet::empty(); assert!(!empty.allows(Permission::Read)); assert!(!empty.allows(Permission::Write)); assert!(!empty.allows(Permission::Execute)); assert!(!empty.allows(Permission::Delegate)); } #[test] fn capability_preserves_resource_and_permissions() { let permissions = [Permission::Read, Permission::Write]; let expected_permissions = perms(&permissions); let cap = memory_cap(42, &permissions); assert_eq!(cap.permissions(), &expected_permissions); assert_eq!(cap.generation(), &Generation::initial()); } #[test] fn removing_a_cap_changes_its_slot_generation() { let mut table = CapabilityTable::new(); let slot = table.insert(endpoint_cap(1, &[Permission::Read])).unwrap(); let before = table.slot_generation(slot).unwrap(); table.remove(slot).unwrap(); assert_eq!( table.slot_generation(slot), None, "empty slots have no generation" ); let again = table.insert(endpoint_cap(2, &[Permission::Read])).unwrap(); assert_eq!(again, slot); assert!(!before.is_valid_against(&table.slot_generation(again).unwrap())); } #[test] fn iter_lists_occupied_slots() { let mut table = CapabilityTable::new(); let a = table.insert(endpoint_cap(1, &[])).unwrap(); let b = table.insert(endpoint_cap(2, &[])).unwrap(); table.remove(a).unwrap(); let slots: [Option; 2] = { let mut it = table.iter().map(|(s, _)| s); [it.next(), it.next()] }; assert_eq!(slots, [Some(b), None]); } #[test] fn caps_record_their_parent() { let parent = CapRef { process: types::id::ProcessId::from_raw(3), process_generation: Generation::initial(), slot: types::bounded::CapSlot::new(4).unwrap(), slot_generation: Generation::initial(), }; let cap = endpoint_cap(1, &[]).with_parent(Some(parent)); assert_eq!(cap.parent(), Some(parent)); assert_eq!(endpoint_cap(1, &[]).parent(), None); }