feat(kernel): add Revoke syscall for generation-based capability revocation

This commit is contained in:
2026-10-18 01:23:24 +02:00
parent 241fefe2d4
commit 4833f2e2bb
4 changed files with 65 additions and 0 deletions

View File

@@ -67,6 +67,9 @@ pub enum Syscall {
Kill { Kill {
process: CapSlot, process: CapSlot,
}, },
Revoke {
slot: CapSlot,
},
SpawnThread { SpawnThread {
entry: EntryPoint, entry: EntryPoint,
stack: StackPointer, stack: StackPointer,

View File

@@ -44,4 +44,22 @@ impl<P: Platform> Kernel<P> {
Err(e) => SyscallOutcome::Complete(SyscallResult::Error(e)), 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)
}
} }

View File

@@ -44,6 +44,7 @@ impl<P: Platform> Kernel<P> {
Syscall::SpawnThread { entry, stack } => self.handle_spawn_thread(pid, entry, stack), 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::CreateProcess { create_cap, image } => self.handle_create_process(pid, create_cap, image),
Syscall::Kill { process } => self.handle_kill(pid, process), Syscall::Kill { process } => self.handle_kill(pid, process),
Syscall::Revoke { slot } => self.handle_revoke(pid, slot),
Syscall::Delegate { slot, to_endpoint, permissions } => { Syscall::Delegate { slot, to_endpoint, permissions } => {
self.handle_delegate(pid, slot, to_endpoint, permissions) self.handle_delegate(pid, slot, to_endpoint, permissions)
} }

View File

@@ -143,3 +143,46 @@ fn revoke_does_not_affect_other_resources() {
let outcome = k.handle_syscall(Syscall::Receive { endpoint: slot2 }); let outcome = k.handle_syscall(Syscall::Receive { endpoint: slot2 });
assert!(matches!(outcome, SyscallOutcome::BlockCaller(_))); 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(_))
));
}