1use crate::{
7 ipc::{self, MultiHandleResource},
8 process::TaskId,
9 sync::SpinLock,
10 vfs,
11};
12use alloc::{collections::BTreeMap, vec::Vec};
13use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
14
15#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
17pub struct CapId(u64);
18
19#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
21struct ResourceKey(ResourceType, usize);
22
23impl CapId {
24 pub fn new() -> Self {
26 static NEXT_ID: AtomicU64 = AtomicU64::new(0);
27 CapId(NEXT_ID.fetch_add(1, Ordering::SeqCst))
28 }
29
30 pub fn from_raw(raw: u64) -> Self {
32 CapId(raw)
33 }
34
35 pub fn as_u64(self) -> u64 {
37 self.0
38 }
39}
40
41#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
43pub enum ResourceType {
44 MemoryRegion,
45 IoPortRange,
46 InterruptLine,
47 IpcPort,
48 Channel,
50 SharedRing,
52 Semaphore,
54 Device,
55 AddressSpace,
56 Silo,
57 Module,
58 File,
59 Nic,
60 FileSystem,
61 Console,
62 Keyboard,
63 Volume,
64 Namespace,
65}
66
67#[derive(Debug, Clone, Copy, PartialEq, Eq)]
69pub struct CapPermissions {
70 pub read: bool,
71 pub write: bool,
72 pub execute: bool,
73 pub grant: bool,
75 pub revoke: bool,
77}
78
79impl CapPermissions {
80 pub const fn none() -> Self {
82 CapPermissions {
83 read: false,
84 write: false,
85 execute: false,
86 grant: false,
87 revoke: false,
88 }
89 }
90
91 pub const fn read_write() -> Self {
93 CapPermissions {
94 read: true,
95 write: true,
96 execute: false,
97 grant: false,
98 revoke: false,
99 }
100 }
101
102 pub const fn all() -> Self {
104 CapPermissions {
105 read: true,
106 write: true,
107 execute: true,
108 grant: true,
109 revoke: true,
110 }
111 }
112}
113
114#[derive(Debug, Clone)]
116pub struct Capability {
117 pub id: CapId,
119 pub resource_type: ResourceType,
121 pub permissions: CapPermissions,
123 pub resource: usize, }
126
127pub struct CapabilityTable {
129 capabilities: BTreeMap<CapId, Capability>,
131}
132
133impl Clone for CapabilityTable {
134 fn clone(&self) -> Self {
136 Self {
137 capabilities: self.capabilities.clone(),
138 }
139 }
140}
141
142impl CapabilityTable {
143 pub fn new() -> Self {
145 CapabilityTable {
146 capabilities: BTreeMap::new(),
147 }
148 }
149
150 pub fn insert(&mut self, cap: Capability) -> CapId {
152 let id = cap.id;
153 get_capability_manager().register_capability(cap.clone());
154 self.capabilities.insert(id, cap);
155 id
156 }
157
158 pub fn remove(&mut self, id: CapId) -> Option<Capability> {
160 let removed = self.capabilities.remove(&id);
161 if removed.is_some() {
162 let _ = get_capability_manager().revoke_capability(id);
163 }
164 removed
165 }
166
167 pub fn get(&self, id: CapId) -> Option<&Capability> {
169 self.capabilities.get(&id)
170 }
171
172 pub fn revoke_all(&mut self) {
175 let capabilities = self.take_all();
176 for capability in &capabilities {
177 release_capability(capability, None);
178 }
179 }
180
181 pub fn take_all(&mut self) -> Vec<Capability> {
183 core::mem::take(&mut self.capabilities)
184 .into_values()
185 .collect()
186 }
187
188 pub fn has_resource_type_with_permissions(
190 &self,
191 resource_type: ResourceType,
192 required: CapPermissions,
193 ) -> bool {
194 self.capabilities.values().any(|cap| {
195 cap.resource_type == resource_type
196 && (!required.read || cap.permissions.read)
197 && (!required.write || cap.permissions.write)
198 && (!required.execute || cap.permissions.execute)
199 && (!required.grant || cap.permissions.grant)
200 && (!required.revoke || cap.permissions.revoke)
201 })
202 }
203
204 pub fn has_resource_with_permissions(
206 &self,
207 resource_type: ResourceType,
208 resource: usize,
209 required: CapPermissions,
210 ) -> bool {
211 self.capabilities.values().any(|cap| {
212 cap.resource_type == resource_type
213 && cap.resource == resource
214 && (!required.read || cap.permissions.read)
215 && (!required.write || cap.permissions.write)
216 && (!required.execute || cap.permissions.execute)
217 && (!required.grant || cap.permissions.grant)
218 && (!required.revoke || cap.permissions.revoke)
219 })
220 }
221
222 pub fn get_with_permissions(&self, id: CapId, required: CapPermissions) -> Option<&Capability> {
224 self.capabilities.get(&id).filter(|cap| {
225 (!required.read || cap.permissions.read)
227 && (!required.write || cap.permissions.write)
228 && (!required.execute || cap.permissions.execute)
229 && (!required.grant || cap.permissions.grant)
230 && (!required.revoke || cap.permissions.revoke)
231 })
232 }
233
234 pub fn get_mut_with_permissions(
236 &mut self,
237 id: CapId,
238 required: CapPermissions,
239 ) -> Option<&mut Capability> {
240 if let Some(cap) = self.capabilities.get_mut(&id) {
241 if (!required.read || cap.permissions.read)
243 && (!required.write || cap.permissions.write)
244 && (!required.execute || cap.permissions.execute)
245 && (!required.grant || cap.permissions.grant)
246 && (!required.revoke || cap.permissions.revoke)
247 {
248 Some(cap)
249 } else {
250 None
251 }
252 } else {
253 None
254 }
255 }
256
257 pub fn duplicate(&mut self, id: CapId) -> Option<Capability> {
259 if let Some(cap) = self.capabilities.get(&id) {
260 if cap.permissions.grant {
261 Some(Capability {
263 id: CapId::new(),
264 resource_type: cap.resource_type,
265 permissions: cap.permissions,
266 resource: cap.resource,
267 })
268 } else {
269 None
270 }
271 } else {
272 None
273 }
274 }
275}
276
277pub struct CapabilityManager {
279 all_capabilities: SpinLock<BTreeMap<CapId, Capability>>,
281 resource_refcounts: SpinLock<BTreeMap<ResourceKey, AtomicUsize>>,
283}
284
285impl CapabilityManager {
286 pub fn new() -> Self {
288 CapabilityManager {
289 all_capabilities: SpinLock::new(BTreeMap::new()),
290 resource_refcounts: SpinLock::new(BTreeMap::new()),
291 }
292 }
293
294 pub fn create_capability(
296 &self,
297 resource_type: ResourceType,
298 resource: usize,
299 permissions: CapPermissions,
300 ) -> Capability {
301 let cap = Capability {
302 id: CapId::new(),
303 resource_type,
304 permissions,
305 resource,
306 };
307
308 self.all_capabilities.lock().insert(cap.id, cap.clone());
309 self.increment_resource_refcount(resource_type, resource);
310 cap
311 }
312
313 pub fn register_capability(&self, cap: Capability) {
315 let key = ResourceKey(cap.resource_type, cap.resource);
316 self.all_capabilities.lock().insert(cap.id, cap);
317 self.increment_resource_refcount_key(&key);
318 }
319
320 pub fn revoke_capability(&self, id: CapId) -> Option<Capability> {
322 let removed = {
323 let mut caps = self.all_capabilities.lock();
324 caps.remove(&id)
325 };
326 if let Some(ref cap) = removed {
327 let key = ResourceKey(cap.resource_type, cap.resource);
328 self.decrement_resource_refcount(&key);
329 }
330 removed
331 }
332
333 pub fn resource_capability_count(&self, resource_type: ResourceType, resource: usize) -> usize {
336 let key = ResourceKey(resource_type, resource);
337 self.resource_refcounts
338 .lock()
339 .get(&key)
340 .map(|rc| rc.load(Ordering::Relaxed))
341 .unwrap_or(0)
342 }
343
344 fn increment_resource_refcount(&self, resource_type: ResourceType, resource: usize) {
347 let key = ResourceKey(resource_type, resource);
348 self.increment_resource_refcount_key(&key);
349 }
350
351 fn increment_resource_refcount_key(&self, key: &ResourceKey) {
352 let mut refcounts = self.resource_refcounts.lock();
353 let entry = refcounts.entry(*key).or_insert_with(|| AtomicUsize::new(0));
354 entry.fetch_add(1, Ordering::Relaxed);
355 }
356
357 fn decrement_resource_refcount(&self, key: &ResourceKey) {
358 let mut refcounts = self.resource_refcounts.lock();
359 let should_remove = if let Some(rc) = refcounts.get(key) {
363 rc.fetch_sub(1, Ordering::Relaxed) == 1
364 } else {
365 false
366 };
367 if should_remove {
368 refcounts.remove(key);
369 }
370 }
371}
372
373use spin::Once;
374
375static CAPABILITY_MANAGER: Once<CapabilityManager> = Once::new();
376
377pub fn get_capability_manager() -> &'static CapabilityManager {
379 CAPABILITY_MANAGER.call_once(CapabilityManager::new)
380}
381
382pub fn release_capability(cap: &Capability, owner_task: Option<TaskId>) {
384 let _ = get_capability_manager().revoke_capability(cap.id);
385 let remaining_caps =
386 get_capability_manager().resource_capability_count(cap.resource_type, cap.resource);
387
388 let shared_resource = match cap.resource_type {
389 ResourceType::SharedRing => Some(MultiHandleResource::SharedRing(ipc::RingId::from_u64(
390 cap.resource as u64,
391 ))),
392 ResourceType::Semaphore => Some(MultiHandleResource::Semaphore(ipc::SemId::from_u64(
393 cap.resource as u64,
394 ))),
395 ResourceType::Channel => Some(MultiHandleResource::Channel(ipc::ChanId::from_u64(
396 cap.resource as u64,
397 ))),
398 ResourceType::IpcPort => Some(MultiHandleResource::IpcPort {
399 id: ipc::PortId::from_u64(cap.resource as u64),
400 owner: owner_task,
401 }),
402 _ => None,
403 };
404
405 if let Some(resource) = shared_resource {
406 if remaining_caps == 0 {
407 let _ = resource.destroy();
408 }
409 return;
410 }
411
412 match cap.resource_type {
413 ResourceType::File => {
414 if let Ok(fd) = u32::try_from(cap.resource) {
415 let _ = vfs::close(fd);
416 }
417 }
418 ResourceType::MemoryRegion => {
419 let _ =
420 crate::memory::memory_region_registry().release_handle(cap.resource as u64, cap.id);
421 }
422 _ => {}
423 }
424}