twizzler_security/sec_ctx/
user.rs1use alloc::collections::btree_map::BTreeMap;
2use core::fmt::Display;
3
4use heapless::Vec;
5use log::debug;
6use twizzler::{
7 marker::BaseType,
8 object::{Object, ObjectBuilder, RawObject, TypedObject},
9};
10use twizzler_abi::{
11 object::{ObjID, Protections},
12 syscall::ObjectCreate,
13};
14use twizzler_rt_abi::{
15 error::{ResourceError, TwzError},
16 object::MapFlags,
17};
18
19use super::{CtxMapItem, CtxMapItemType, PermsInfo, SecCtxBase, SecCtxFlags};
20use crate::{
21 sec_ctx::{MAP_ITEMS_PER_OBJ, OBJECT_ROOT_OFFSET},
22 Cap, Del, VerifyingKey,
23};
24
25pub struct SecCtx {
26 uobj: Object<SecCtxBase>,
27 cache: BTreeMap<ObjID, PermsInfo>,
28}
29
30impl Default for SecCtx {
31 fn default() -> Self {
32 let obj = ObjectBuilder::default()
33 .build(SecCtxBase::default())
34 .unwrap();
35
36 Self {
37 uobj: obj,
38 cache: BTreeMap::new(),
39 }
40 }
41}
42
43impl Display for SecCtx {
44 fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
45 let binding = self.uobj.clone();
46 let base = binding.base();
47
48 write!(f, "Sec Ctx ObjID: {} {{\n", self.uobj.id())?;
49 write!(f, "base: {:?}", base)?;
50 Ok(())
51 }
52}
53
54impl SecCtx {
55 pub fn attached_ctx() -> SecCtx {
56 todo!("unsure how to get attached sec_ctx as of rn")
57 }
58
59 pub fn new(
60 object_create_spec: ObjectCreate,
61 global_mask: Protections,
62 flags: SecCtxFlags,
63 ) -> Result<Self, TwzError> {
64 let new_obj =
65 ObjectBuilder::new(object_create_spec).build(SecCtxBase::new(global_mask, flags))?;
66
67 Ok(Self {
68 uobj: new_obj,
69 cache: BTreeMap::new(),
70 })
71 }
72
73 pub fn insert_cap(&self, cap: Cap) -> Result<(), TwzError> {
74 let mut tx = self.uobj.clone().into_tx()?;
75 let mut base = tx.base_mut();
76
77 let mut map_item = {
78 base.offset += size_of::<Cap>();
79
80 CtxMapItem {
81 item_type: CtxMapItemType::Cap,
82 offset: base.offset + OBJECT_ROOT_OFFSET,
83 }
84 };
85
86 let alignment = 0x10 - (map_item.offset % 0x10);
87 map_item.offset += alignment;
88 base.offset += alignment;
90
91 #[cfg(feature = "log")]
92 debug!("write offset into object for entry: {:#X}", map_item.offset);
93
94 if let Some(vec) = base.map.get_mut(&cap.target) {
96 vec.push(map_item).map_err(|_| {
97 TwzError::Resource(ResourceError::OutOfResources)
99 })?;
100 } else {
101 let mut new_vec = Vec::<CtxMapItem, MAP_ITEMS_PER_OBJ>::new();
102 let _ = new_vec.push(map_item);
103 let _ = base.map.insert(cap.target, new_vec).map_err(|_| {
104 TwzError::Resource(ResourceError::OutOfResources)
106 })?;
107 };
108
109 let ptr = tx
110 .lea_mut(map_item.offset, size_of::<Cap>())
111 .expect("Write offset should not result in a pointer outside of the object")
112 .cast::<Cap>();
113
114 unsafe {
117 *ptr = cap;
118 }
119
120 tx.commit()?;
121
122 #[cfg(feature = "log")]
123 debug!("Added capability at ptr: {:#?}", ptr);
124 Ok(())
125 }
126
127 pub fn insert_del(&self, _del: Del) -> Result<(), TwzError> {
128 todo!("implement later")
129 }
130
131 pub fn id(&self) -> ObjID {
132 self.uobj.id()
133 }
134
135 pub fn remove_cap(&mut self) {
136 todo!("implement later")
137 }
138
139 pub fn remove_del(&mut self) {
140 todo!("implement later")
141 }
142
143 pub fn lookup<T: BaseType>(&mut self, target_id: ObjID) -> PermsInfo {
145 if let Some(cache_entry) = self.cache.get(&target_id) {
147 return *cache_entry;
148 };
149
150 let base = self.uobj.base();
151
152 let target_object = Object::<T>::map(target_id, MapFlags::READ)
154 .expect("target object should exist!")
155 .meta_ptr();
156
157 let target_obj_default_prot;
158 let v_key_obj_id;
159
160 unsafe {
161 let metadata = *target_object;
162 v_key_obj_id = metadata.kuid;
163
164 target_obj_default_prot = metadata.default_prot;
165 }
166
167 let v_obj = Object::<VerifyingKey>::map(v_key_obj_id, MapFlags::READ | MapFlags::WRITE)
168 .expect("failed to open verifying key for this object");
169 let v_key = v_obj.base();
170
171 let mut granted_perms =
173 PermsInfo::new(self.id(), target_obj_default_prot, Protections::empty());
174
175 let Some(results) = base.map.get(&target_id) else {
177 return granted_perms;
180 };
181
182 for entry in results {
183 match entry.item_type {
184 CtxMapItemType::Del => {
185 todo!("Delegations not supported yet for lookup")
187 }
188
189 CtxMapItemType::Cap => {
190 let ptr = self
193 .uobj
194 .lea(entry.offset, size_of::<Cap>())
195 .expect("address should be inside of object!")
196 .cast::<Cap>();
197
198 unsafe {
199 let cap = *ptr;
200
201 if cap.verify_sig(v_key).is_ok() {
202 granted_perms.provide |= cap.protections;
203 }
204 }
205 }
206 }
207 }
208
209 let Some(mask) = base.masks.get(&target_id) else {
210 granted_perms.provide &= base.global_mask;
214
215 self.cache.insert(target_id, granted_perms.clone());
216 return granted_perms;
217 };
218
219 granted_perms.provide =
222 granted_perms.provide & mask.permmask & (base.global_mask | mask.ovrmask);
223
224 self.cache.insert(target_id, granted_perms.clone());
225 granted_perms
226 }
227}
228
229impl TryFrom<ObjID> for SecCtx {
230 type Error = TwzError;
231 fn try_from(value: ObjID) -> Result<Self, Self::Error> {
232 let uobj = Object::<SecCtxBase>::map(value, MapFlags::READ | MapFlags::WRITE)?;
233
234 Ok(Self {
235 uobj,
236 cache: BTreeMap::new(),
237 })
238 }
239}
240
241mod tests {
242 use super::*;
243 use crate::sec_ctx::SecCtxFlags;
244
245 extern crate test;
246
247 fn test_security_context_creation() {
248 let _default_sec_ctx = SecCtx::default();
249 let _new_sec_ctx =
250 SecCtx::new(Default::default(), Protections::all(), SecCtxFlags::empty())
251 .expect("new context should have been created!");
252 }
253}