twizzler_security/sec_ctx/
user.rs

1use core::fmt::Display;
2
3use heapless::Vec;
4use twizzler::object::{Object, ObjectBuilder, RawObject, TypedObject};
5use twizzler_abi::{
6    object::{ObjID, Protections},
7    syscall::{
8        sys_sctx_attach, sys_thread_active_sctx_id, sys_thread_set_active_sctx_id, ObjectCreate,
9    },
10};
11use twizzler_rt_abi::{
12    error::{ResourceError, TwzError},
13    object::MapFlags,
14};
15
16use super::{CtxMapItem, CtxMapItemType, SecCtxBase, SecCtxFlags};
17use crate::{
18    sec_ctx::{MAP_ITEMS_PER_OBJ, OBJECT_ROOT_OFFSET},
19    Cap, Del,
20};
21
22#[derive(Debug)]
23/// A User-space representation of a Security Context.
24pub struct SecCtx {
25    uobj: Object<SecCtxBase>,
26}
27
28impl Default for SecCtx {
29    fn default() -> Self {
30        let obj = ObjectBuilder::default()
31            .build(SecCtxBase::default())
32            .unwrap();
33
34        Self { uobj: obj }
35    }
36}
37
38impl Display for SecCtx {
39    fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
40        let binding = self.uobj.clone();
41        let base = binding.base();
42
43        write!(f, "Sec Ctx ObjID: {} {{\n", self.uobj.id())?;
44        write!(f, "base: {:?}", base)?;
45        Ok(())
46    }
47}
48
49impl SecCtx {
50    /// Returns the currently active `SecCtx`.
51    pub fn active_ctx() -> SecCtx {
52        let curr_sec_ctx_id = sys_thread_active_sctx_id();
53
54        Self::try_from(curr_sec_ctx_id)
55            .expect("We should always be able to parse the currently attached security context")
56    }
57
58    /// Attaches the current process to this `SecCtx`.
59    pub fn attach(&self) -> Result<(), TwzError> {
60        sys_sctx_attach(self.id())
61    }
62
63    /// Sets this `SecCtx` as the active Security Context.
64    pub fn set_active(&self) -> Result<(), TwzError> {
65        sys_sctx_attach(self.id())?;
66        sys_thread_set_active_sctx_id(self.id())
67    }
68
69    /// Returns the `SecCtxBase` of this `SecCtx`.
70    pub fn base(&self) -> &SecCtxBase {
71        self.uobj.base()
72    }
73
74    /// Create a new `SecCtx`.
75    pub fn new(
76        object_create_spec: ObjectCreate,
77        global_mask: Protections,
78        flags: SecCtxFlags,
79    ) -> Result<Self, TwzError> {
80        let new_obj =
81            ObjectBuilder::new(object_create_spec).build(SecCtxBase::new(global_mask, flags))?;
82
83        Ok(Self { uobj: new_obj })
84    }
85
86    /// Insert a `Cap` into this `SecCtx`.
87    pub fn insert_cap(&mut self, cap: Cap) -> Result<(), TwzError> {
88        let mut tx = self.uobj.clone().into_tx()?;
89        let mut base = tx.base_mut();
90
91        let mut map_item = {
92            base.offset += size_of::<Cap>();
93
94            CtxMapItem {
95                item_type: CtxMapItemType::Cap,
96                offset: base.offset + OBJECT_ROOT_OFFSET,
97            }
98        };
99
100        let alignment = 0x10 - (map_item.offset % 0x10);
101        map_item.offset += alignment;
102        // also have to fix the length in the offset
103        base.offset += alignment;
104
105        #[cfg(feature = "log")]
106        log::debug!("write offset into object for entry: {:#X}", map_item.offset);
107
108        // seeing if a vec already exists for target obj, else create new
109        if let Some(vec) = base.map.get_mut(&cap.target) {
110            vec.push(map_item).map_err(|_| {
111                // only possible error case is it being full
112                TwzError::Resource(ResourceError::OutOfResources)
113            })?;
114        } else {
115            let mut new_vec = Vec::<CtxMapItem, MAP_ITEMS_PER_OBJ>::new();
116            let _ = new_vec.push(map_item);
117            let _ = base.map.insert(cap.target, new_vec).map_err(|_| {
118                // only possible error case is it being full
119                TwzError::Resource(ResourceError::OutOfResources)
120            })?;
121        };
122
123        let ptr = tx
124            .lea_mut(map_item.offset, size_of::<Cap>())
125            .expect("Write offset should not result in a pointer outside of the object")
126            .cast::<Cap>();
127
128        // SAFETY: copies the capability into the object, we check that the pointer is valid above /
129        // fix its alignment
130        unsafe {
131            *ptr = cap;
132        }
133
134        tx.commit()?;
135
136        #[cfg(feature = "log")]
137        log::debug!("Added capability at ptr: {:#?}", ptr);
138        Ok(())
139    }
140
141    /// Insert a `Del` into this `SecCtx`.
142    ///
143    /// # Panics
144    /// is not implemented yet
145    pub fn insert_del(&mut self, _del: Del) -> Result<(), TwzError> {
146        unimplemented!()
147    }
148
149    /// Returns the `ObjID` of this `SecCtx`.
150    pub fn id(&self) -> ObjID {
151        self.uobj.id()
152    }
153
154    /// Remove a `Cap` from this `SecCtx`.
155    ///
156    /// # Panics
157    /// is not implemented yet
158    pub fn remove_cap(&mut self) {
159        unimplemented!()
160    }
161
162    /// Remove a `Del` from this `SecCtx`.
163    ///
164    /// # Panics
165    /// is not implemented yet
166    pub fn remove_del(&mut self) {
167        unimplemented!()
168    }
169}
170
171impl TryFrom<ObjID> for SecCtx {
172    type Error = TwzError;
173    fn try_from(value: ObjID) -> Result<Self, Self::Error> {
174        let uobj = Object::<SecCtxBase>::map(value, MapFlags::READ | MapFlags::WRITE)?;
175
176        Ok(Self { uobj })
177    }
178}
179#[cfg(test)]
180#[cfg(feature = "user")]
181mod tests {
182    use super::*;
183    use crate::sec_ctx::SecCtxFlags;
184
185    extern crate test;
186
187    #[test]
188    #[test]
189    fn test_security_context_creation() {
190        let _default_sec_ctx = SecCtx::default();
191        let _new_sec_ctx =
192            SecCtx::new(Default::default(), Protections::all(), SecCtxFlags::empty())
193                .expect("new context should have been created!");
194    }
195}