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, }
131
132pub struct CapabilityTable {
134 capabilities: BTreeMap<CapId, Capability>,
136}
137
138impl Clone for CapabilityTable {
139 fn clone(&self) -> Self {
141 Self {
142 capabilities: self.capabilities.clone(),
143 }
144 }
145}
146
147impl CapabilityTable {
148 pub fn new() -> Self {
150 CapabilityTable {
151 capabilities: BTreeMap::new(),
152 }
153 }
154
155 pub fn insert(&mut self, cap: Capability) -> CapId {
157 let id = cap.id;
158 get_capability_manager().register_capability(cap.clone());
159 self.capabilities.insert(id, cap);
160 id
161 }
162
163 pub fn remove(&mut self, id: CapId) -> Option<Capability> {
165 let removed = self.capabilities.remove(&id);
166 if removed.is_some() {
167 let _ = get_capability_manager().revoke_capability(id);
168 }
169 removed
170 }
171
172 pub fn get(&self, id: CapId) -> Option<&Capability> {
174 self.capabilities.get(&id)
175 }
176
177 pub fn revoke_all(&mut self) {
180 let capabilities = self.take_all();
181 for capability in &capabilities {
182 release_capability(capability, None);
183 }
184 }
185
186 pub fn take_all(&mut self) -> Vec<Capability> {
188 core::mem::take(&mut self.capabilities)
189 .into_values()
190 .collect()
191 }
192
193 pub fn has_resource_type_with_permissions(
195 &self,
196 resource_type: ResourceType,
197 required: CapPermissions,
198 ) -> bool {
199 self.capabilities.values().any(|cap| {
200 cap.resource_type == resource_type
201 && (!required.read || cap.permissions.read)
202 && (!required.write || cap.permissions.write)
203 && (!required.execute || cap.permissions.execute)
204 && (!required.grant || cap.permissions.grant)
205 && (!required.revoke || cap.permissions.revoke)
206 })
207 }
208
209 pub fn has_resource_with_permissions(
211 &self,
212 resource_type: ResourceType,
213 resource: usize,
214 required: CapPermissions,
215 ) -> bool {
216 self.capabilities.values().any(|cap| {
217 cap.resource_type == resource_type
218 && cap.resource == resource
219 && (!required.read || cap.permissions.read)
220 && (!required.write || cap.permissions.write)
221 && (!required.execute || cap.permissions.execute)
222 && (!required.grant || cap.permissions.grant)
223 && (!required.revoke || cap.permissions.revoke)
224 })
225 }
226
227 pub fn get_with_permissions(&self, id: CapId, required: CapPermissions) -> Option<&Capability> {
229 self.capabilities.get(&id).filter(|cap| {
230 (!required.read || cap.permissions.read)
232 && (!required.write || cap.permissions.write)
233 && (!required.execute || cap.permissions.execute)
234 && (!required.grant || cap.permissions.grant)
235 && (!required.revoke || cap.permissions.revoke)
236 })
237 }
238
239 pub fn get_mut_with_permissions(
241 &mut self,
242 id: CapId,
243 required: CapPermissions,
244 ) -> Option<&mut Capability> {
245 if let Some(cap) = self.capabilities.get_mut(&id) {
246 if (!required.read || cap.permissions.read)
248 && (!required.write || cap.permissions.write)
249 && (!required.execute || cap.permissions.execute)
250 && (!required.grant || cap.permissions.grant)
251 && (!required.revoke || cap.permissions.revoke)
252 {
253 Some(cap)
254 } else {
255 None
256 }
257 } else {
258 None
259 }
260 }
261
262 pub fn duplicate(&mut self, id: CapId) -> Option<Capability> {
264 if let Some(cap) = self.capabilities.get(&id) {
265 if cap.permissions.grant {
266 Some(Capability {
268 id: CapId::new(),
269 resource_type: cap.resource_type,
270 permissions: cap.permissions,
271 resource: cap.resource,
272 })
273 } else {
274 None
275 }
276 } else {
277 None
278 }
279 }
280}
281
282pub struct CapabilityManager {
284 all_capabilities: SpinLock<BTreeMap<CapId, Capability>>,
286 resource_refcounts: SpinLock<BTreeMap<ResourceKey, AtomicUsize>>,
293}
294
295impl CapabilityManager {
296 pub fn new() -> Self {
298 CapabilityManager {
299 all_capabilities: SpinLock::new(BTreeMap::new()),
300 resource_refcounts: SpinLock::new(BTreeMap::new()),
301 }
302 }
303
304 pub fn create_capability(
306 &self,
307 resource_type: ResourceType,
308 resource: usize,
309 permissions: CapPermissions,
310 ) -> Capability {
311 let cap = Capability {
312 id: CapId::new(),
313 resource_type,
314 permissions,
315 resource,
316 };
317
318 self.all_capabilities.lock().insert(cap.id, cap.clone());
319 self.increment_resource_refcount(resource_type, resource);
320 cap
321 }
322
323 pub fn register_capability(&self, cap: Capability) {
325 let key = ResourceKey(cap.resource_type, cap.resource);
326 self.all_capabilities.lock().insert(cap.id, cap);
327 self.increment_resource_refcount_key(&key);
328 }
329
330 pub fn revoke_capability(&self, id: CapId) -> Option<Capability> {
332 let removed = {
333 let mut caps = self.all_capabilities.lock();
334 caps.remove(&id)
335 };
336 if let Some(ref cap) = removed {
337 let key = ResourceKey(cap.resource_type, cap.resource);
338 self.decrement_resource_refcount(&key);
339 }
340 removed
341 }
342
343 pub fn resource_capability_count(&self, resource_type: ResourceType, resource: usize) -> usize {
346 let key = ResourceKey(resource_type, resource);
347 self.resource_refcounts
348 .lock()
349 .get(&key)
350 .map(|rc| rc.load(Ordering::Relaxed))
351 .unwrap_or(0)
352 }
353
354 fn increment_resource_refcount(&self, resource_type: ResourceType, resource: usize) {
357 let key = ResourceKey(resource_type, resource);
358 self.increment_resource_refcount_key(&key);
359 }
360
361 fn increment_resource_refcount_key(&self, key: &ResourceKey) {
362 let mut refcounts = self.resource_refcounts.lock();
363 let entry = refcounts.entry(*key).or_insert_with(|| AtomicUsize::new(0));
364 entry.fetch_add(1, Ordering::Relaxed);
365 }
366
367 fn decrement_resource_refcount(&self, key: &ResourceKey) {
368 let mut refcounts = self.resource_refcounts.lock();
369 let should_remove = if let Some(rc) = refcounts.get(key) {
373 rc.fetch_sub(1, Ordering::Relaxed) == 1
374 } else {
375 false
376 };
377 if should_remove {
378 refcounts.remove(key);
379 }
380 }
381}
382
383use spin::Once;
384
385static CAPABILITY_MANAGER: Once<CapabilityManager> = Once::new();
386
387pub fn get_capability_manager() -> &'static CapabilityManager {
389 CAPABILITY_MANAGER.call_once(CapabilityManager::new)
390}
391
392pub fn release_capability(cap: &Capability, owner_task: Option<TaskId>) {
394 let _ = get_capability_manager().revoke_capability(cap.id);
395 let remaining_caps =
396 get_capability_manager().resource_capability_count(cap.resource_type, cap.resource);
397
398 let shared_resource = match cap.resource_type {
399 ResourceType::SharedRing => Some(MultiHandleResource::SharedRing(ipc::RingId::from_u64(
400 cap.resource as u64,
401 ))),
402 ResourceType::Semaphore => Some(MultiHandleResource::Semaphore(ipc::SemId::from_u64(
403 cap.resource as u64,
404 ))),
405 ResourceType::Channel => Some(MultiHandleResource::Channel(ipc::ChanId::from_u64(
406 cap.resource as u64,
407 ))),
408 ResourceType::IpcPort => Some(MultiHandleResource::IpcPort {
409 id: ipc::PortId::from_u64(cap.resource as u64),
410 owner: owner_task,
411 }),
412 _ => None,
413 };
414
415 if let Some(resource) = shared_resource {
416 if remaining_caps == 0 {
417 let _ = resource.destroy();
418 }
419 return;
420 }
421
422 match cap.resource_type {
423 ResourceType::File => {
424 if let Ok(fd) = u32::try_from(cap.resource) {
425 let _ = vfs::close(fd);
426 }
427 }
428 ResourceType::MemoryRegion => {
429 let _ =
430 crate::memory::memory_region_registry().release_handle(cap.resource as u64, cap.id);
431 }
432 ResourceType::IpcTransport => {
433 if remaining_caps == 0 {
434 let tid =
435 crate::ipc::transport::TransportId::from_u64(cap.resource as u64);
436 let _ = crate::syscall::transport::TRANSPORT_MANAGER.close(tid);
437 }
438 }
439 _ => {}
440 }
441}