Skip to main content

tpt_archon_kernel/
ipc.rs

1//! Capability-bearing IPC message passing.
2//!
3//! The microkernel handles only IPC, scheduling, and memory. Services
4//! (filesystems, network, drivers) run as isolated user-space endpoints and
5//! communicate exclusively through capability-bearing [`Message`]s routed by
6//! the [`MessageRouter`]. A message can only be delivered to a channel the
7//! sender holds a write [`Capability`] for, so resource access is mediated by
8//! the capability system rather than ambient authority.
9
10use alloc::collections::BTreeMap;
11use alloc::vec::Vec;
12
13use tpt_archon_bridge::capability::{Capability, Resource, Right, SharedIssuer};
14
15/// A capability-bearing message addressed to a channel.
16#[derive(Debug, Clone, PartialEq, Eq)]
17pub struct Message {
18    /// The destination channel id.
19    pub channel: u64,
20    /// The message payload.
21    pub payload: Vec<u8>,
22}
23
24/// Errors from message routing.
25#[derive(Debug, Clone, PartialEq, Eq)]
26pub enum IpcError {
27    /// The sender's capability does not authorize writing this channel.
28    Denied,
29    /// No such channel is registered.
30    NoSuchChannel,
31}
32
33/// Routes messages between registered channels.
34///
35/// Each channel has an inbox; [`send`](Self::send) enqueues a message iff the
36/// sender presents a capability authorizing a write to that channel.
37#[derive(Debug)]
38pub struct MessageRouter {
39    inboxes: BTreeMap<u64, Vec<Message>>,
40    issuer: SharedIssuer,
41}
42
43impl MessageRouter {
44    /// Creates an empty router gated by `issuer` — capabilities presented to
45    /// `send`/`receive` are checked for live revocation against it, not just
46    /// their structural (resource, right) shape.
47    pub fn new(issuer: SharedIssuer) -> Self {
48        Self {
49            inboxes: BTreeMap::new(),
50            issuer,
51        }
52    }
53
54    /// Registers a channel with an empty inbox.
55    pub fn register_channel(&mut self, channel: u64) {
56        self.inboxes.entry(channel).or_default();
57    }
58
59    /// Sends `message` if `cap` authorizes writing `message.channel`.
60    pub fn send(&mut self, cap: &Capability, message: Message) -> Result<(), IpcError> {
61        if !self
62            .issuer
63            .borrow()
64            .authorizes(cap, Resource::Channel(message.channel), Right::Write)
65        {
66            return Err(IpcError::Denied);
67        }
68        let inbox = self
69            .inboxes
70            .get_mut(&message.channel)
71            .ok_or(IpcError::NoSuchChannel)?;
72        inbox.push(message);
73        Ok(())
74    }
75
76    /// Receives (drains) all messages for `channel` if `cap` authorizes reading
77    /// it.
78    pub fn receive(&mut self, cap: &Capability, channel: u64) -> Result<Vec<Message>, IpcError> {
79        if !self
80            .issuer
81            .borrow()
82            .authorizes(cap, Resource::Channel(channel), Right::Read)
83        {
84            return Err(IpcError::Denied);
85        }
86        let inbox = self
87            .inboxes
88            .get_mut(&channel)
89            .ok_or(IpcError::NoSuchChannel)?;
90        Ok(core::mem::take(inbox))
91    }
92}
93
94#[cfg(test)]
95mod tests {
96    use super::*;
97    use alloc::rc::Rc;
98    use core::cell::RefCell;
99    use tpt_archon_bridge::capability::CapabilityIssuer;
100
101    fn shared_issuer() -> Rc<RefCell<CapabilityIssuer>> {
102        Rc::new(RefCell::new(CapabilityIssuer::new()))
103    }
104
105    #[test]
106    fn authorized_send_and_receive() {
107        let issuer = shared_issuer();
108        let mut router = MessageRouter::new(issuer.clone());
109        router.register_channel(7);
110
111        let send_cap = issuer.borrow_mut().mint(Resource::Channel(7), Right::Write);
112        let recv_cap = issuer.borrow_mut().mint(Resource::Channel(7), Right::Read);
113
114        router
115            .send(
116                &send_cap,
117                Message {
118                    channel: 7,
119                    payload: alloc::vec![1, 2, 3],
120                },
121            )
122            .unwrap();
123
124        let msgs = router.receive(&recv_cap, 7).unwrap();
125        assert_eq!(msgs.len(), 1);
126        assert_eq!(msgs[0].payload, alloc::vec![1, 2, 3]);
127        // Drained.
128        assert!(router.receive(&recv_cap, 7).unwrap().is_empty());
129    }
130
131    #[test]
132    fn send_without_write_capability_is_denied() {
133        let issuer = shared_issuer();
134        let mut router = MessageRouter::new(issuer.clone());
135        router.register_channel(1);
136        let read_only = issuer.borrow_mut().mint(Resource::Channel(1), Right::Read);
137        assert_eq!(
138            router.send(
139                &read_only,
140                Message {
141                    channel: 1,
142                    payload: alloc::vec![]
143                }
144            ),
145            Err(IpcError::Denied)
146        );
147    }
148
149    #[test]
150    fn unknown_channel_errors() {
151        let issuer = shared_issuer();
152        let mut router = MessageRouter::new(issuer.clone());
153        let cap = issuer
154            .borrow_mut()
155            .mint(Resource::Channel(99), Right::Write);
156        assert_eq!(
157            router.send(
158                &cap,
159                Message {
160                    channel: 99,
161                    payload: alloc::vec![]
162                }
163            ),
164            Err(IpcError::NoSuchChannel)
165        );
166    }
167
168    #[test]
169    fn revoked_capability_is_denied_at_send_and_receive() {
170        // Regression test for security-audit finding 1: `revoke` must be
171        // enforced by `MessageRouter` itself, not only by calling
172        // `CapabilityIssuer::validate` out-of-band.
173        let issuer = shared_issuer();
174        let mut router = MessageRouter::new(issuer.clone());
175        router.register_channel(3);
176        let cap = issuer
177            .borrow_mut()
178            .mint(Resource::Channel(3), Right::ReadWrite);
179
180        router
181            .send(
182                &cap,
183                Message {
184                    channel: 3,
185                    payload: alloc::vec![9],
186                },
187            )
188            .unwrap();
189
190        issuer.borrow_mut().revoke(&cap);
191        assert_eq!(
192            router.send(
193                &cap,
194                Message {
195                    channel: 3,
196                    payload: alloc::vec![9]
197                }
198            ),
199            Err(IpcError::Denied)
200        );
201        assert_eq!(router.receive(&cap, 3), Err(IpcError::Denied));
202    }
203}