Skip to main content

byteflow/scheduler/
delegate.rs

1//! Opcode DELEGATE — attenuation as a first-class ISA operation.
2//!
3//! `DELEGATE dst, src_cap, rights_mask, native_mask_cap?`
4//!
5//! The entire semantics are guaranteed inside [`Cap::attenuate`]: the result
6//! is `min(src.rights, rights_mask)` — bitwise AND. Hostile operands cannot
7//! escalate because there is no separate "grant"; only intersection.
8
9use crate::bytecode::{Cap, CapRights, NativeMask, RevocationCell};
10
11#[derive(Debug, Clone, Copy, PartialEq, Eq)]
12pub enum DelegateError {
13    SourceRevoked,
14    /// Caller asked to narrow a native mask but `src` has no `NATIVE` right.
15    SourceLacksNative,
16}
17
18impl std::fmt::Display for DelegateError {
19    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
20        match self {
21            DelegateError::SourceRevoked => f.write_str("delegate: source capability revoked"),
22            DelegateError::SourceLacksNative => {
23                f.write_str("delegate: source lacks NATIVE right")
24            }
25        }
26    }
27}
28
29impl std::error::Error for DelegateError {}
30
31pub fn exec_delegate(
32    src: &Cap,
33    src_cell: &RevocationCell,
34    want_rights: CapRights,
35    want_native: Option<&NativeMask>,
36) -> Result<Cap, DelegateError> {
37    if !src.is_valid(src_cell) {
38        return Err(DelegateError::SourceRevoked);
39    }
40    if want_native.is_some() && !src.rights.contains(CapRights::NATIVE) {
41        return Err(DelegateError::SourceLacksNative);
42    }
43    Ok(src.attenuate(want_rights, want_native))
44}
45
46#[cfg(test)]
47mod tests {
48    use super::*;
49    use crate::bytecode::{CapTarget, RevocationCell};
50
51    #[test]
52    fn cannot_escalate_via_delegate_regardless_of_requested_mask() {
53        let cell = RevocationCell::new();
54        let src = Cap::root(CapTarget::Flow(1), CapRights::SEND, None, &cell);
55        let out = match exec_delegate(
56            &src,
57            &cell,
58            CapRights::SEND.union(CapRights::ADMIN).union(CapRights::NATIVE),
59            None,
60        ) {
61            Ok(c) => c,
62            Err(_) => {
63                assert!(false, "delegate of live SEND cap must succeed");
64                return;
65            }
66        };
67        assert!(out.rights.contains(CapRights::SEND));
68        assert!(!out.rights.contains(CapRights::ADMIN));
69        assert!(!out.rights.contains(CapRights::NATIVE));
70    }
71
72    #[test]
73    fn revoked_source_cannot_delegate() {
74        let cell = RevocationCell::new();
75        let src = Cap::root(CapTarget::Flow(1), CapRights::SEND, None, &cell);
76        cell.revoke();
77        assert!(matches!(
78            exec_delegate(&src, &cell, CapRights::SEND, None),
79            Err(DelegateError::SourceRevoked)
80        ));
81    }
82}