Skip to main content

strat9_kernel/
capability.rs

1//! Capability-based Security System
2//!
3//! Implements a capability-based security model for Strat9-OS.
4//! All kernel resources are accessed through unforgeable tokens (capabilities).
5
6use crate::sync::SpinLock;
7use alloc::collections::BTreeMap;
8use core::sync::atomic::{AtomicU64, Ordering};
9
10/// Unique identifier for a capability
11#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
12pub struct CapId(u64);
13
14impl CapId {
15    /// Generate a new unique capability ID
16    pub fn new() -> Self {
17        static NEXT_ID: AtomicU64 = AtomicU64::new(0);
18        CapId(NEXT_ID.fetch_add(1, Ordering::SeqCst))
19    }
20
21    /// Convert a raw u64 into a CapId (used for syscall handles).
22    pub fn from_raw(raw: u64) -> Self {
23        CapId(raw)
24    }
25
26    /// Get the raw u64 value (for syscall return values).
27    pub fn as_u64(self) -> u64 {
28        self.0
29    }
30}
31
32/// Types of kernel resources that can be accessed via capabilities
33#[derive(Debug, Clone, Copy, PartialEq, Eq)]
34pub enum ResourceType {
35    MemoryRegion,
36    IoPortRange,
37    InterruptLine,
38    IpcPort,
39    /// A typed MPMC sync-channel (SyncChan), accessed via SYS_CHAN_* syscalls.
40    Channel,
41    /// Shared-memory ring buffer for bulk IPC (SYS_IPC_RING_*).
42    SharedRing,
43    /// POSIX-like counting semaphore (SYS_SEM_*).
44    Semaphore,
45    Device,
46    AddressSpace,
47    Silo,
48    Module,
49    File,
50    Nic,
51    FileSystem,
52    Console,
53    Keyboard,
54    Volume,
55    Namespace,
56}
57
58/// Permissions associated with a capability
59#[derive(Debug, Clone, Copy, PartialEq, Eq)]
60pub struct CapPermissions {
61    pub read: bool,
62    pub write: bool,
63    pub execute: bool,
64    /// Allow granting this capability to other processes
65    pub grant: bool,
66    /// Allow revoking this capability
67    pub revoke: bool,
68}
69
70impl CapPermissions {
71    /// Create permissions with all rights disabled
72    pub const fn none() -> Self {
73        CapPermissions {
74            read: false,
75            write: false,
76            execute: false,
77            grant: false,
78            revoke: false,
79        }
80    }
81
82    /// Create permissions with read and write rights
83    pub const fn read_write() -> Self {
84        CapPermissions {
85            read: true,
86            write: true,
87            execute: false,
88            grant: false,
89            revoke: false,
90        }
91    }
92
93    /// Create permissions with all rights enabled
94    pub const fn all() -> Self {
95        CapPermissions {
96            read: true,
97            write: true,
98            execute: true,
99            grant: true,
100            revoke: true,
101        }
102    }
103}
104
105/// A capability token that grants access to a kernel resource
106#[derive(Debug, Clone)]
107pub struct Capability {
108    /// Unique identifier for this capability
109    pub id: CapId,
110    /// Type of resource this capability grants access to
111    pub resource_type: ResourceType,
112    /// Permissions associated with this capability
113    pub permissions: CapPermissions,
114    /// Reference to the actual resource (opaque to prevent direct access)
115    pub resource: usize, // Actually a pointer to the resource, cast to usize
116}
117
118/// Table of capabilities for a process
119pub struct CapabilityTable {
120    /// Mapping from capability ID to capability
121    capabilities: BTreeMap<CapId, Capability>,
122}
123
124impl Clone for CapabilityTable {
125    /// Performs the clone operation.
126    fn clone(&self) -> Self {
127        Self {
128            capabilities: self.capabilities.clone(),
129        }
130    }
131}
132
133impl CapabilityTable {
134    /// Create a new empty capability table
135    pub fn new() -> Self {
136        CapabilityTable {
137            capabilities: BTreeMap::new(),
138        }
139    }
140
141    /// Insert a capability into the table
142    pub fn insert(&mut self, cap: Capability) -> CapId {
143        let id = cap.id;
144        self.capabilities.insert(id, cap);
145        id
146    }
147
148    /// Remove a capability from the table
149    pub fn remove(&mut self, id: CapId) -> Option<Capability> {
150        self.capabilities.remove(&id)
151    }
152
153    /// Get a reference to a capability (no permission check).
154    pub fn get(&self, id: CapId) -> Option<&Capability> {
155        self.capabilities.get(&id)
156    }
157
158    /// Revoke all capabilities in this table and clear it.
159    /// Does not allocate memory.
160    pub fn revoke_all(&mut self) {
161        let mgr = get_capability_manager();
162        // BTreeMap::clear() does not allocate
163        for (id, _) in self.capabilities.iter() {
164            mgr.revoke_capability(*id);
165        }
166        self.capabilities.clear();
167    }
168
169    /// Check whether any capability of the given resource type has required permissions.
170    pub fn has_resource_type_with_permissions(
171        &self,
172        resource_type: ResourceType,
173        required: CapPermissions,
174    ) -> bool {
175        self.capabilities.values().any(|cap| {
176            cap.resource_type == resource_type
177                && (!required.read || cap.permissions.read)
178                && (!required.write || cap.permissions.write)
179                && (!required.execute || cap.permissions.execute)
180                && (!required.grant || cap.permissions.grant)
181                && (!required.revoke || cap.permissions.revoke)
182        })
183    }
184
185    /// Check whether a specific resource has required permissions.
186    pub fn has_resource_with_permissions(
187        &self,
188        resource_type: ResourceType,
189        resource: usize,
190        required: CapPermissions,
191    ) -> bool {
192        self.capabilities.values().any(|cap| {
193            cap.resource_type == resource_type
194                && cap.resource == resource
195                && (!required.read || cap.permissions.read)
196                && (!required.write || cap.permissions.write)
197                && (!required.execute || cap.permissions.execute)
198                && (!required.grant || cap.permissions.grant)
199                && (!required.revoke || cap.permissions.revoke)
200        })
201    }
202
203    /// Get a reference to a capability if it exists and has the required permissions
204    pub fn get_with_permissions(&self, id: CapId, required: CapPermissions) -> Option<&Capability> {
205        self.capabilities.get(&id).filter(|cap| {
206            // Check if the capability has all required permissions
207            (!required.read || cap.permissions.read)
208                && (!required.write || cap.permissions.write)
209                && (!required.execute || cap.permissions.execute)
210                && (!required.grant || cap.permissions.grant)
211                && (!required.revoke || cap.permissions.revoke)
212        })
213    }
214
215    /// Get a mutable reference to a capability if it exists and has the required permissions
216    pub fn get_mut_with_permissions(
217        &mut self,
218        id: CapId,
219        required: CapPermissions,
220    ) -> Option<&mut Capability> {
221        if let Some(cap) = self.capabilities.get_mut(&id) {
222            // Check if the capability has all required permissions
223            if (!required.read || cap.permissions.read)
224                && (!required.write || cap.permissions.write)
225                && (!required.execute || cap.permissions.execute)
226                && (!required.grant || cap.permissions.grant)
227                && (!required.revoke || cap.permissions.revoke)
228            {
229                Some(cap)
230            } else {
231                None
232            }
233        } else {
234            None
235        }
236    }
237
238    /// Duplicate a capability (grant permission required)
239    pub fn duplicate(&mut self, id: CapId) -> Option<Capability> {
240        if let Some(cap) = self.capabilities.get(&id) {
241            if cap.permissions.grant {
242                // Create a new capability with the same properties
243                Some(Capability {
244                    id: CapId::new(),
245                    resource_type: cap.resource_type,
246                    permissions: cap.permissions,
247                    resource: cap.resource,
248                })
249            } else {
250                None
251            }
252        } else {
253            None
254        }
255    }
256}
257
258/// Global capability manager
259pub struct CapabilityManager {
260    /// All capabilities in the system
261    all_capabilities: SpinLock<BTreeMap<CapId, Capability>>,
262}
263
264impl CapabilityManager {
265    /// Create a new capability manager
266    pub fn new() -> Self {
267        CapabilityManager {
268            all_capabilities: SpinLock::new(BTreeMap::new()),
269        }
270    }
271
272    /// Register a new resource and return a capability to access it
273    pub fn create_capability(
274        &self,
275        resource_type: ResourceType,
276        resource: usize,
277        permissions: CapPermissions,
278    ) -> Capability {
279        let cap = Capability {
280            id: CapId::new(),
281            resource_type,
282            permissions,
283            resource,
284        };
285
286        self.all_capabilities.lock().insert(cap.id, cap.clone());
287        cap
288    }
289
290    /// Revoke a capability (removes it from the global table)
291    pub fn revoke_capability(&self, id: CapId) -> Option<Capability> {
292        self.all_capabilities.lock().remove(&id)
293    }
294}
295
296use spin::Once;
297
298static CAPABILITY_MANAGER: Once<CapabilityManager> = Once::new();
299
300/// Get a reference to the global capability manager
301pub fn get_capability_manager() -> &'static CapabilityManager {
302    CAPABILITY_MANAGER.call_once(CapabilityManager::new)
303}