feat(kernel): add Revoke syscall for generation-based capability revocation
This commit is contained in:
@@ -44,4 +44,22 @@ impl<P: Platform> Kernel<P> {
|
||||
Err(e) => SyscallOutcome::Complete(SyscallResult::Error(e)),
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn handle_revoke(
|
||||
&mut self,
|
||||
caller_pid: types::id::ProcessId,
|
||||
slot: types::bounded::CapSlot,
|
||||
) -> SyscallOutcome {
|
||||
let resource = match self.check_cap(
|
||||
caller_pid,
|
||||
slot,
|
||||
types::permission::Permission::Revoke,
|
||||
) {
|
||||
Ok(cap) => cap.resource().clone(),
|
||||
Err(e) => return SyscallOutcome::Complete(SyscallResult::Error(e)),
|
||||
};
|
||||
|
||||
self.revoke_resource(&resource);
|
||||
SyscallOutcome::Complete(SyscallResult::Ok)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,6 +44,7 @@ impl<P: Platform> Kernel<P> {
|
||||
Syscall::SpawnThread { entry, stack } => self.handle_spawn_thread(pid, entry, stack),
|
||||
Syscall::CreateProcess { create_cap, image } => self.handle_create_process(pid, create_cap, image),
|
||||
Syscall::Kill { process } => self.handle_kill(pid, process),
|
||||
Syscall::Revoke { slot } => self.handle_revoke(pid, slot),
|
||||
Syscall::Delegate { slot, to_endpoint, permissions } => {
|
||||
self.handle_delegate(pid, slot, to_endpoint, permissions)
|
||||
}
|
||||
|
||||
@@ -143,3 +143,46 @@ fn revoke_does_not_affect_other_resources() {
|
||||
let outcome = k.handle_syscall(Syscall::Receive { endpoint: slot2 });
|
||||
assert!(matches!(outcome, SyscallOutcome::BlockCaller(_)));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn revoke_syscall_invalidates_via_generation() {
|
||||
let (mut k, pid) = kernel_with_process();
|
||||
let ep_id = k.create_endpoint_for_test();
|
||||
|
||||
let cap_slot = k.grant_cap_for_test(
|
||||
pid,
|
||||
Resource::Endpoint(ep_id),
|
||||
PermissionSet::empty()
|
||||
.with(Permission::Read)
|
||||
.with(Permission::Revoke),
|
||||
);
|
||||
|
||||
// Revoke via syscall
|
||||
let outcome = k.handle_syscall(Syscall::Revoke { slot: cap_slot });
|
||||
assert!(matches!(outcome, SyscallOutcome::Complete(SyscallResult::Ok)));
|
||||
|
||||
// The cap itself is now revoked (generation mismatch)
|
||||
let outcome = k.handle_syscall(Syscall::Receive { endpoint: cap_slot });
|
||||
assert!(matches!(
|
||||
outcome,
|
||||
SyscallOutcome::Complete(SyscallResult::Error(domain::error::KernelError::RevokedCapability(_)))
|
||||
));
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn revoke_syscall_without_revoke_permission_fails() {
|
||||
let (mut k, pid) = kernel_with_process();
|
||||
let ep_id = k.create_endpoint_for_test();
|
||||
|
||||
let cap_slot = k.grant_cap_for_test(
|
||||
pid,
|
||||
Resource::Endpoint(ep_id),
|
||||
PermissionSet::empty().with(Permission::Read),
|
||||
);
|
||||
|
||||
let outcome = k.handle_syscall(Syscall::Revoke { slot: cap_slot });
|
||||
assert!(matches!(
|
||||
outcome,
|
||||
SyscallOutcome::Complete(SyscallResult::Error(_))
|
||||
));
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user