⚠️ VeridianOS Kernel Documentation - This is low-level kernel code. All functions are unsafe unless explicitly marked otherwise. no_std

veridian_kernel/ipc/
capability.rs

1//! IPC capability management
2//!
3//! Capabilities are unforgeable tokens that grant specific permissions
4//! for IPC operations. They are the foundation of VeridianOS security model.
5// IPC capability management
6#[cfg(feature = "alloc")]
7extern crate alloc;
8
9use core::sync::atomic::{AtomicU64, Ordering};
10
11use crate::error::KernelError;
12
13/// Global capability ID generator
14static CAPABILITY_COUNTER: AtomicU64 = AtomicU64::new(1);
15
16// Use ProcessId from process module
17pub use crate::process::ProcessId;
18
19/// Endpoint ID type
20pub type EndpointId = u64;
21
22/// IPC capability structure
23///
24/// 64-bit capability token format:
25/// - Bits 63-48: Generation counter (for revocation)
26/// - Bits 47-32: Capability type
27/// - Bits 31-0: Unique ID
28#[repr(C)]
29#[derive(Debug, Clone, Copy, PartialEq, Eq)]
30pub struct IpcCapability {
31    /// Packed capability value
32    value: u64,
33    /// Target process or endpoint
34    target: EndpointId,
35    /// Permissions for this capability
36    permissions: IpcPermissions,
37    /// Usage limits and restrictions
38    limits: IpcLimits,
39}
40
41impl IpcCapability {
42    /// Create a new capability
43    pub fn new(target: EndpointId, permissions: IpcPermissions) -> Self {
44        let id = CAPABILITY_COUNTER.fetch_add(1, Ordering::Relaxed);
45        let generation = 0u64; // Start with generation 0
46        let cap_type = CapabilityType::Endpoint as u64;
47
48        let value = (generation << 48) | (cap_type << 32) | (id & 0xFFFFFFFF);
49
50        Self {
51            value,
52            target,
53            permissions,
54            limits: IpcLimits::default(),
55        }
56    }
57
58    /// Get the capability ID
59    pub fn id(&self) -> u64 {
60        self.value & 0xFFFFFFFF
61    }
62
63    /// Get the generation counter
64    pub fn generation(&self) -> u16 {
65        ((self.value >> 48) & 0xFFFF) as u16
66    }
67
68    /// Get the capability type
69    pub fn cap_type(&self) -> CapabilityType {
70        let type_val = ((self.value >> 32) & 0xFFFF) as u16;
71        CapabilityType::from_u16(type_val).unwrap_or(CapabilityType::Invalid)
72    }
73
74    /// Get the target endpoint/process
75    pub fn target(&self) -> EndpointId {
76        self.target
77    }
78
79    /// Get the owner (same as target for compatibility)
80    pub fn owner(&self) -> ProcessId {
81        ProcessId(self.target)
82    }
83
84    /// Check if capability has specific permission
85    pub fn has_permission(&self, perm: Permission) -> bool {
86        match perm {
87            Permission::Send => self.permissions.can_send,
88            Permission::Receive => self.permissions.can_receive,
89            Permission::Share => self.permissions.can_share,
90        }
91    }
92
93    /// Derive a new capability with reduced permissions
94    pub fn derive(&self, new_perms: IpcPermissions) -> Option<Self> {
95        // Can only reduce permissions, not increase them
96        if new_perms.can_send && !self.permissions.can_send {
97            return None;
98        }
99        if new_perms.can_receive && !self.permissions.can_receive {
100            return None;
101        }
102        if new_perms.can_share && !self.permissions.can_share {
103            return None;
104        }
105        if new_perms.max_message_size > self.permissions.max_message_size {
106            return None;
107        }
108
109        let mut derived = *self;
110        derived.permissions = new_perms;
111        Some(derived)
112    }
113
114    /// Revoke this capability by incrementing generation
115    pub fn revoke(&mut self) {
116        let generation = self.generation().wrapping_add(1);
117        let cap_type = self.cap_type() as u64;
118        let id = self.id();
119        self.value = ((generation as u64) << 48) | (cap_type << 32) | id;
120    }
121}
122
123/// Capability types
124#[repr(u16)]
125#[derive(Debug, Clone, Copy, PartialEq, Eq)]
126pub enum CapabilityType {
127    /// Invalid capability
128    Invalid = 0,
129    /// Endpoint capability for message passing
130    Endpoint = 1,
131    /// Memory region capability
132    Memory = 2,
133    /// Process capability
134    Process = 3,
135    /// Interrupt capability
136    Interrupt = 4,
137    /// Channel capability for async IPC
138    Channel = 5,
139}
140
141impl CapabilityType {
142    fn from_u16(val: u16) -> Option<Self> {
143        match val {
144            0 => Some(Self::Invalid),
145            1 => Some(Self::Endpoint),
146            2 => Some(Self::Memory),
147            3 => Some(Self::Process),
148            4 => Some(Self::Interrupt),
149            5 => Some(Self::Channel),
150            _ => None,
151        }
152    }
153}
154
155/// Individual permissions
156#[derive(Debug, Clone, Copy, PartialEq, Eq)]
157pub enum Permission {
158    /// Can send messages
159    Send,
160    /// Can receive messages
161    Receive,
162    /// Can share capability with others
163    Share,
164}
165
166/// IPC permissions structure
167#[repr(C)]
168#[derive(Debug, Clone, Copy, PartialEq, Eq)]
169pub struct IpcPermissions {
170    /// Can send messages to target
171    pub can_send: bool,
172    /// Can receive messages from target
173    pub can_receive: bool,
174    /// Can share this capability with other processes
175    pub can_share: bool,
176    /// Maximum message size allowed (0 = unlimited)
177    pub max_message_size: usize,
178}
179
180impl IpcPermissions {
181    /// Create permissions with all rights
182    pub const fn all() -> Self {
183        Self {
184            can_send: true,
185            can_receive: true,
186            can_share: true,
187            max_message_size: 0, // Unlimited
188        }
189    }
190
191    /// Create send-only permissions
192    pub const fn send_only() -> Self {
193        Self {
194            can_send: true,
195            can_receive: false,
196            can_share: false,
197            max_message_size: 0,
198        }
199    }
200
201    /// Create receive-only permissions
202    pub const fn receive_only() -> Self {
203        Self {
204            can_send: false,
205            can_receive: true,
206            can_share: false,
207            max_message_size: 0,
208        }
209    }
210}
211
212/// IPC usage limits and restrictions
213#[repr(C)]
214#[derive(Debug, Clone, Copy, PartialEq, Eq, Default)]
215pub struct IpcLimits {
216    /// Maximum messages per second (0 = unlimited)
217    pub rate_limit: u32,
218    /// Maximum bandwidth in bytes per second (0 = unlimited)
219    pub bandwidth_limit: u64,
220    /// Expiration time in seconds since epoch (0 = no expiration)
221    pub expiration: u64,
222}
223
224impl IpcLimits {
225    /// Create unlimited limits
226    pub const fn unlimited() -> Self {
227        Self {
228            rate_limit: 0,
229            bandwidth_limit: 0,
230            expiration: 0,
231        }
232    }
233
234    /// Create limits with rate limiting
235    pub const fn with_rate_limit(messages_per_sec: u32) -> Self {
236        Self {
237            rate_limit: messages_per_sec,
238            bandwidth_limit: 0,
239            expiration: 0,
240        }
241    }
242}
243
244/// Capability lookup table with BTreeMap-backed storage
245///
246/// Provides O(log n) lookup for capability tokens. Uses BTreeMap
247/// when the alloc feature is available, with a no-op fallback.
248pub struct CapabilityTable {
249    /// Capability storage keyed by capability ID
250    #[cfg(feature = "alloc")]
251    capabilities: alloc::collections::BTreeMap<u64, IpcCapability>,
252}
253
254impl CapabilityTable {
255    /// Create a new capability table
256    pub fn new() -> Self {
257        Self {
258            #[cfg(feature = "alloc")]
259            capabilities: alloc::collections::BTreeMap::new(),
260        }
261    }
262
263    /// Insert a capability into the table
264    #[cfg(feature = "alloc")]
265    pub fn insert(&mut self, cap: IpcCapability) -> Result<(), KernelError> {
266        let id = cap.id();
267        if self.capabilities.contains_key(&id) {
268            return Err(KernelError::AlreadyExists {
269                resource: "ipc_capability",
270                id,
271            });
272        }
273        self.capabilities.insert(id, cap);
274        Ok(())
275    }
276
277    /// Insert a capability into the table (no-alloc stub)
278    #[cfg(not(feature = "alloc"))]
279    pub fn insert(&mut self, _cap: IpcCapability) -> Result<(), KernelError> {
280        Ok(())
281    }
282
283    /// Lookup a capability by ID
284    #[cfg(feature = "alloc")]
285    pub fn lookup(&self, id: u64) -> Option<&IpcCapability> {
286        self.capabilities.get(&id)
287    }
288
289    /// Lookup a capability by ID (no-alloc stub)
290    #[cfg(not(feature = "alloc"))]
291    pub fn lookup(&self, _id: u64) -> Option<&IpcCapability> {
292        None
293    }
294
295    /// Remove a capability from the table
296    #[cfg(feature = "alloc")]
297    pub fn remove(&mut self, id: u64) -> Option<IpcCapability> {
298        self.capabilities.remove(&id)
299    }
300
301    /// Remove a capability from the table (no-alloc stub)
302    #[cfg(not(feature = "alloc"))]
303    pub fn remove(&mut self, _id: u64) -> Option<IpcCapability> {
304        None
305    }
306
307    /// Validate that a capability has the specified permission
308    #[cfg(feature = "alloc")]
309    pub fn validate_permission(&self, cap_id: u64, perm: Permission) -> bool {
310        self.capabilities
311            .get(&cap_id)
312            .map(|cap| cap.has_permission(perm))
313            .unwrap_or(false)
314    }
315
316    /// Validate permission (no-alloc stub)
317    #[cfg(not(feature = "alloc"))]
318    pub fn validate_permission(&self, _cap_id: u64, _perm: Permission) -> bool {
319        false
320    }
321
322    /// Get number of capabilities in the table
323    #[cfg(feature = "alloc")]
324    pub fn len(&self) -> usize {
325        self.capabilities.len()
326    }
327
328    /// Get number of capabilities (no-alloc stub)
329    #[cfg(not(feature = "alloc"))]
330    pub fn len(&self) -> usize {
331        0
332    }
333
334    /// Check if table is empty
335    pub fn is_empty(&self) -> bool {
336        self.len() == 0
337    }
338}
339
340impl Default for CapabilityTable {
341    fn default() -> Self {
342        Self::new()
343    }
344}
345
346#[cfg(all(test, not(target_os = "none")))]
347mod tests {
348    use super::*;
349
350    #[test]
351    fn test_capability_creation() {
352        let cap = IpcCapability::new(42, IpcPermissions::all());
353        assert_eq!(cap.target(), 42);
354        assert_eq!(cap.generation(), 0);
355        assert_eq!(cap.cap_type(), CapabilityType::Endpoint);
356    }
357
358    #[test]
359    fn test_capability_permissions() {
360        let cap = IpcCapability::new(1, IpcPermissions::send_only());
361        assert!(cap.has_permission(Permission::Send));
362        assert!(!cap.has_permission(Permission::Receive));
363        assert!(!cap.has_permission(Permission::Share));
364    }
365
366    #[test]
367    fn test_capability_derive() {
368        let cap = IpcCapability::new(1, IpcPermissions::all());
369        let derived = cap.derive(IpcPermissions::send_only());
370        assert!(derived.is_some());
371
372        let restricted = IpcCapability::new(1, IpcPermissions::send_only());
373        let invalid_derive = restricted.derive(IpcPermissions::all());
374        assert!(invalid_derive.is_none());
375    }
376}