veridian_kernel/ipc/
cap_transfer.rs1use super::{
7 error::{IpcError, Result},
8 message::Message,
9};
10use crate::{
11 cap::{
12 manager::{cap_manager, CapError},
13 space::CapabilitySpace,
14 token::{CapabilityToken, Rights},
15 },
16 process::ProcessId,
17};
18
19pub fn transfer_capability(
24 msg: &Message,
25 sender_cap_space: &CapabilitySpace,
26 receiver_pid: ProcessId,
27) -> Result<Option<CapabilityToken>> {
28 let cap_id = msg.capability();
29
30 if cap_id == 0 {
32 return Ok(None);
33 }
34
35 let cap_token = CapabilityToken::from_u64(cap_id);
37
38 match crate::cap::manager::check_capability(cap_token, Rights::GRANT, sender_cap_space) {
40 Ok(()) => {}
41 Err(CapError::InvalidCapability) => return Err(IpcError::InvalidCapability),
42 Err(CapError::InsufficientRights) => return Err(IpcError::PermissionDenied),
43 Err(CapError::CapabilityRevoked) => return Err(IpcError::InvalidCapability),
44 Err(_) => return Err(IpcError::InvalidCapability),
45 }
46
47 let receiver_process = match crate::process::table::get_process(receiver_pid) {
49 Some(process) => process,
50 None => return Err(IpcError::ProcessNotFound),
51 };
52 let receiver_cap_space = receiver_process.capability_space.lock();
53
54 let sender_rights = sender_cap_space
56 .lookup(cap_token)
57 .ok_or(IpcError::InvalidCapability)?;
58 let transfer_rights = sender_rights.difference(Rights::GRANT);
59
60 match cap_manager().delegate(
62 cap_token,
63 sender_cap_space,
64 &receiver_cap_space,
65 transfer_rights,
66 ) {
67 Ok(new_cap) => Ok(Some(new_cap)),
68 Err(CapError::OutOfMemory) => Err(IpcError::OutOfMemory),
69 Err(_) => Err(IpcError::PermissionDenied),
70 }
71}
72
73#[allow(dead_code)] pub fn receive_capability(
79 msg: &Message,
80 receiver_cap_space: &CapabilitySpace,
81) -> Result<Option<CapabilityToken>> {
82 let cap_id = msg.capability();
83
84 if cap_id == 0 {
86 return Ok(None);
87 }
88
89 let cap_token = CapabilityToken::from_u64(cap_id);
91
92 if receiver_cap_space.lookup(cap_token).is_some() {
95 Ok(Some(cap_token))
96 } else {
97 Err(IpcError::InvalidCapability)
99 }
100}
101
102#[allow(dead_code)] pub fn revoke_transferred_capability(
108 cap_token: CapabilityToken,
109 owner_cap_space: &CapabilitySpace,
110) -> Result<()> {
111 if owner_cap_space.lookup(cap_token).is_none() {
113 return Err(IpcError::InvalidCapability);
114 }
115
116 match cap_manager().revoke(cap_token) {
118 Ok(()) => Ok(()),
119 Err(CapError::InvalidCapability) => Err(IpcError::InvalidCapability),
120 Err(_) => Err(IpcError::PermissionDenied),
121 }
122}
123
124#[cfg(test)]
125mod tests {
126 }