1use crate::{
10 ipc::{self, MultiHandleResource},
11 process::TaskId,
12 sync::SpinLock,
13 vfs,
14};
15use alloc::{collections::BTreeMap, vec::Vec};
16use core::sync::atomic::{AtomicU64, AtomicUsize, Ordering};
17
18#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
20pub struct CapId(u64);
21
22#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
24struct ResourceKey(ResourceType, usize);
25
26impl CapId {
27 pub fn new() -> Self {
29 static NEXT_ID: AtomicU64 = AtomicU64::new(0);
30 CapId(NEXT_ID.fetch_add(1, Ordering::SeqCst))
31 }
32
33 pub fn from_raw(raw: u64) -> Self {
35 CapId(raw)
36 }
37
38 pub fn as_u64(self) -> u64 {
40 self.0
41 }
42}
43
44#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
46pub enum ResourceType {
47 MemoryRegion,
48 IoPortRange,
49 InterruptLine,
50 IpcPort,
51 Channel,
53 SharedRing,
55 Semaphore,
57 Device,
58 AddressSpace,
59 Silo,
60 Module,
61 File,
62 Nic,
63 FileSystem,
64 Console,
65 Keyboard,
66 Volume,
67 Namespace,
68 IpcTransport,
70}
71
72#[derive(Debug, Clone, Copy, PartialEq, Eq)]
74pub struct CapPermissions {
75 pub read: bool,
76 pub write: bool,
77 pub execute: bool,
78 pub grant: bool,
80 pub revoke: bool,
82}
83
84impl CapPermissions {
85 pub const fn none() -> Self {
87 CapPermissions {
88 read: false,
89 write: false,
90 execute: false,
91 grant: false,
92 revoke: false,
93 }
94 }
95
96 pub const fn read_write() -> Self {
98 CapPermissions {
99 read: true,
100 write: true,
101 execute: false,
102 grant: false,
103 revoke: false,
104 }
105 }
106
107 pub const fn all() -> Self {
109 CapPermissions {
110 read: true,
111 write: true,
112 execute: true,
113 grant: true,
114 revoke: true,
115 }
116 }
117}
118
119#[derive(Debug, Clone)]
121pub struct Capability {
122 pub id: CapId,
124 pub resource_type: ResourceType,
126 pub permissions: CapPermissions,
128 pub resource: usize, pub badge: u64,
141}
142
143pub struct CapabilityTable {
145 capabilities: BTreeMap<CapId, Capability>,
147}
148
149impl Clone for CapabilityTable {
150 fn clone(&self) -> Self {
152 Self {
153 capabilities: self.capabilities.clone(),
154 }
155 }
156}
157
158impl CapabilityTable {
159 pub fn new() -> Self {
161 CapabilityTable {
162 capabilities: BTreeMap::new(),
163 }
164 }
165
166 pub fn insert(&mut self, cap: Capability) -> CapId {
168 let id = cap.id;
169 get_capability_manager().register_capability(cap.clone());
170 self.capabilities.insert(id, cap);
171 id
172 }
173
174 pub fn remove(&mut self, id: CapId) -> Option<Capability> {
176 let removed = self.capabilities.remove(&id);
177 if removed.is_some() {
178 let _ = get_capability_manager().revoke_capability(id);
179 }
180 removed
181 }
182
183 pub fn get(&self, id: CapId) -> Option<&Capability> {
185 self.capabilities.get(&id)
186 }
187
188 pub fn revoke_all(&mut self) {
191 let capabilities = self.take_all();
192 for capability in &capabilities {
193 release_capability(capability, None);
194 }
195 }
196
197 pub fn take_all(&mut self) -> Vec<Capability> {
199 core::mem::take(&mut self.capabilities)
200 .into_values()
201 .collect()
202 }
203
204 pub fn has_resource_type_with_permissions(
206 &self,
207 resource_type: ResourceType,
208 required: CapPermissions,
209 ) -> bool {
210 self.capabilities.values().any(|cap| {
211 cap.resource_type == resource_type
212 && (!required.read || cap.permissions.read)
213 && (!required.write || cap.permissions.write)
214 && (!required.execute || cap.permissions.execute)
215 && (!required.grant || cap.permissions.grant)
216 && (!required.revoke || cap.permissions.revoke)
217 })
218 }
219
220 pub fn has_resource_with_permissions(
222 &self,
223 resource_type: ResourceType,
224 resource: usize,
225 required: CapPermissions,
226 ) -> bool {
227 self.capabilities.values().any(|cap| {
228 cap.resource_type == resource_type
229 && cap.resource == resource
230 && (!required.read || cap.permissions.read)
231 && (!required.write || cap.permissions.write)
232 && (!required.execute || cap.permissions.execute)
233 && (!required.grant || cap.permissions.grant)
234 && (!required.revoke || cap.permissions.revoke)
235 })
236 }
237
238 pub fn get_with_permissions(&self, id: CapId, required: CapPermissions) -> Option<&Capability> {
240 self.capabilities.get(&id).filter(|cap| {
241 (!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 }
249
250 pub fn get_mut_with_permissions(
252 &mut self,
253 id: CapId,
254 required: CapPermissions,
255 ) -> Option<&mut Capability> {
256 if let Some(cap) = self.capabilities.get_mut(&id) {
257 if (!required.read || cap.permissions.read)
259 && (!required.write || cap.permissions.write)
260 && (!required.execute || cap.permissions.execute)
261 && (!required.grant || cap.permissions.grant)
262 && (!required.revoke || cap.permissions.revoke)
263 {
264 Some(cap)
265 } else {
266 None
267 }
268 } else {
269 None
270 }
271 }
272
273 pub fn duplicate(&mut self, id: CapId) -> Option<Capability> {
279 if let Some(cap) = self.capabilities.get(&id) {
280 if cap.permissions.grant {
281 Some(Capability {
282 id: CapId::new(),
283 resource_type: cap.resource_type,
284 permissions: cap.permissions,
285 resource: cap.resource,
286 badge: cap.badge,
287 })
288 } else {
289 None
290 }
291 } else {
292 None
293 }
294 }
295
296 pub fn duplicate_with_badge(&mut self, id: CapId, new_badge: u64) -> Option<Capability> {
303 if let Some(cap) = self.capabilities.get(&id) {
304 if cap.permissions.grant {
305 Some(Capability {
306 id: CapId::new(),
307 resource_type: cap.resource_type,
308 permissions: cap.permissions,
309 resource: cap.resource,
310 badge: new_badge,
311 })
312 } else {
313 None
314 }
315 } else {
316 None
317 }
318 }
319}
320
321pub struct CapabilityManager {
323 all_capabilities: SpinLock<BTreeMap<CapId, Capability>>,
325 resource_refcounts: SpinLock<BTreeMap<ResourceKey, AtomicUsize>>,
332}
333
334impl CapabilityManager {
335 pub fn new() -> Self {
337 CapabilityManager {
338 all_capabilities: SpinLock::new(BTreeMap::new()),
339 resource_refcounts: SpinLock::new(BTreeMap::new()),
340 }
341 }
342
343 pub fn create_capability(
345 &self,
346 resource_type: ResourceType,
347 resource: usize,
348 permissions: CapPermissions,
349 ) -> Capability {
350 let id = CapId::new();
351 let cap = Capability {
352 badge: id.as_u64(),
353 id,
354 resource_type,
355 permissions,
356 resource,
357 };
358
359 self.all_capabilities.lock().insert(cap.id, cap.clone());
360 self.increment_resource_refcount(resource_type, resource);
361 cap
362 }
363
364 pub fn register_capability(&self, cap: Capability) {
366 let key = ResourceKey(cap.resource_type, cap.resource);
367 self.all_capabilities.lock().insert(cap.id, cap);
368 self.increment_resource_refcount_key(&key);
369 }
370
371 pub fn revoke_capability(&self, id: CapId) -> Option<Capability> {
373 let removed = {
374 let mut caps = self.all_capabilities.lock();
375 caps.remove(&id)
376 };
377 if let Some(ref cap) = removed {
378 let key = ResourceKey(cap.resource_type, cap.resource);
379 self.decrement_resource_refcount(&key);
380 }
381 removed
382 }
383
384 pub fn resource_capability_count(&self, resource_type: ResourceType, resource: usize) -> usize {
387 let key = ResourceKey(resource_type, resource);
388 self.resource_refcounts
389 .lock()
390 .get(&key)
391 .map(|rc| rc.load(Ordering::Relaxed))
392 .unwrap_or(0)
393 }
394
395 fn increment_resource_refcount(&self, resource_type: ResourceType, resource: usize) {
398 let key = ResourceKey(resource_type, resource);
399 self.increment_resource_refcount_key(&key);
400 }
401
402 fn increment_resource_refcount_key(&self, key: &ResourceKey) {
403 let mut refcounts = self.resource_refcounts.lock();
404 let entry = refcounts.entry(*key).or_insert_with(|| AtomicUsize::new(0));
405 entry.fetch_add(1, Ordering::Relaxed);
406 }
407
408 fn decrement_resource_refcount(&self, key: &ResourceKey) {
409 let mut refcounts = self.resource_refcounts.lock();
410 let should_remove = if let Some(rc) = refcounts.get(key) {
414 rc.fetch_sub(1, Ordering::Relaxed) == 1
415 } else {
416 false
417 };
418 if should_remove {
419 refcounts.remove(key);
420 }
421 }
422}
423
424use spin::Once;
425
426static CAPABILITY_MANAGER: Once<CapabilityManager> = Once::new();
427
428pub fn get_capability_manager() -> &'static CapabilityManager {
430 CAPABILITY_MANAGER.call_once(CapabilityManager::new)
431}
432
433pub fn release_capability(cap: &Capability, owner_task: Option<TaskId>) {
435 let _ = get_capability_manager().revoke_capability(cap.id);
436 let remaining_caps =
437 get_capability_manager().resource_capability_count(cap.resource_type, cap.resource);
438
439 let shared_resource = match cap.resource_type {
440 ResourceType::SharedRing => Some(MultiHandleResource::SharedRing(ipc::RingId::from_u64(
441 cap.resource as u64,
442 ))),
443 ResourceType::Semaphore => Some(MultiHandleResource::Semaphore(ipc::SemId::from_u64(
444 cap.resource as u64,
445 ))),
446 ResourceType::Channel => Some(MultiHandleResource::Channel(ipc::ChanId::from_u64(
447 cap.resource as u64,
448 ))),
449 ResourceType::IpcPort => Some(MultiHandleResource::IpcPort {
450 id: ipc::PortId::from_u64(cap.resource as u64),
451 owner: owner_task,
452 }),
453 _ => None,
454 };
455
456 if let Some(resource) = shared_resource {
457 if remaining_caps == 0 {
458 let _ = resource.destroy();
459 }
460 return;
461 }
462
463 match cap.resource_type {
464 ResourceType::File => {
465 if let Ok(fd) = u32::try_from(cap.resource) {
466 let _ = vfs::close(fd);
467 }
468 }
469 ResourceType::MemoryRegion => {
470 let _ =
471 crate::memory::memory_region_registry().release_handle(cap.resource as u64, cap.id);
472 }
473 ResourceType::IpcTransport => {
474 if remaining_caps == 0 {
475 let tid = crate::ipc::transport::TransportId::from_u64(cap.resource as u64);
476 let _ = crate::syscall::transport::TRANSPORT_MANAGER.close(tid);
477 }
478 }
479 _ => {}
480 }
481}