monitor/secapi/
gates.rs

1use std::fmt::Debug;
2
3use dynlink::context::NewCompartmentFlags;
4use secgate::{util::Descriptor, Crossing};
5use twizzler_rt_abi::{
6    debug::{DlPhdrInfo, LinkMap},
7    error::{ArgumentError, ResourceError, TwzError},
8    object::ObjID,
9    thread::ThreadSpawnArgs,
10};
11
12extern "C-unwind" {
13    fn __is_monitor_ready() -> bool;
14}
15
16/// Reserved instance ID for the security monitor.
17pub const MONITOR_INSTANCE_ID: ObjID = ObjID::new(0);
18
19#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
20#[cfg_attr(
21    not(feature = "secgate-impl"),
22    secgate::secure_gate(options(info, api))
23)]
24pub fn monitor_rt_spawn_thread(
25    info: &secgate::GateCallInfo,
26    args: ThreadSpawnArgs,
27    thread_pointer: usize,
28    stack_pointer: usize,
29) -> Result<ObjID, TwzError> {
30    let monitor = crate::mon::get_monitor();
31    monitor.spawn_compartment_thread(
32        info.source_context().unwrap_or(0.into()),
33        args,
34        stack_pointer,
35        thread_pointer,
36    )
37}
38
39#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
40#[cfg_attr(
41    not(feature = "secgate-impl"),
42    secgate::secure_gate(options(info, api))
43)]
44pub fn monitor_rt_get_comp_config(info: &secgate::GateCallInfo) -> Result<usize, TwzError> {
45    let monitor = crate::mon::get_monitor();
46    Ok(monitor
47        .get_comp_config(info.source_context().unwrap_or(MONITOR_INSTANCE_ID))
48        .map(|ptr| ptr as usize)
49        .unwrap_or(0))
50}
51
52#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
53#[cfg_attr(
54    not(feature = "secgate-impl"),
55    secgate::secure_gate(options(info, api))
56)]
57pub fn monitor_rt_get_library_info(
58    info: &secgate::GateCallInfo,
59    desc: Descriptor,
60) -> Result<LibraryInfo, TwzError> {
61    let monitor = crate::mon::get_monitor();
62    let instance = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
63    let thread = info.thread_id();
64    monitor.get_library_info(instance, thread, desc)
65}
66
67#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
68#[cfg_attr(
69    not(feature = "secgate-impl"),
70    secgate::secure_gate(options(info, api))
71)]
72pub fn monitor_rt_get_library_handle(
73    info: &secgate::GateCallInfo,
74    compartment: Option<Descriptor>,
75    lib_n: usize,
76) -> Result<Descriptor, TwzError> {
77    let monitor = crate::mon::get_monitor();
78    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
79    monitor.get_library_handle(caller, compartment, lib_n)
80}
81
82#[repr(C)]
83#[derive(Clone, Copy, Debug)]
84pub struct LibraryInfo {
85    pub name_len: usize,
86    pub compartment_id: ObjID,
87    pub objid: ObjID,
88    pub slot: usize,
89    pub start: *const u8,
90    pub len: usize,
91    pub dl_info: DlPhdrInfo,
92    pub link_map: LinkMap,
93    pub desc: Descriptor,
94}
95
96#[repr(C)]
97#[derive(Clone, Copy, Debug)]
98pub struct CompartmentInfo {
99    pub name_len: usize,
100    pub id: ObjID,
101    pub sctx: ObjID,
102    pub flags: u64,
103    pub nr_libs: usize,
104}
105
106#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
107#[cfg_attr(
108    not(feature = "secgate-impl"),
109    secgate::secure_gate(options(info, api))
110)]
111pub fn monitor_rt_get_compartment_handle(
112    info: &secgate::GateCallInfo,
113    compartment: ObjID,
114) -> Result<Descriptor, TwzError> {
115    let monitor = crate::mon::get_monitor();
116    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
117    let compartment = if compartment.raw() == 0 {
118        caller
119    } else {
120        compartment
121    };
122    monitor.get_compartment_handle(caller, compartment)
123}
124
125#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
126#[cfg_attr(
127    not(feature = "secgate-impl"),
128    secgate::secure_gate(options(info, api))
129)]
130pub fn monitor_rt_get_compartment_info(
131    info: &secgate::GateCallInfo,
132    desc: Option<Descriptor>,
133) -> Result<CompartmentInfo, TwzError> {
134    let monitor = crate::mon::get_monitor();
135    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
136    monitor.get_compartment_info(caller, info.thread_id(), desc)
137}
138
139#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
140#[cfg_attr(
141    not(feature = "secgate-impl"),
142    secgate::secure_gate(options(info, api))
143)]
144pub fn monitor_rt_compartment_dynamic_gate(
145    info: &secgate::GateCallInfo,
146    desc: Option<Descriptor>,
147    name_len: usize,
148) -> Result<usize, TwzError> {
149    let monitor = crate::mon::get_monitor();
150    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
151    monitor.get_compartment_gate_address(caller, info.thread_id(), desc, name_len)
152}
153
154#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
155#[cfg_attr(
156    not(feature = "secgate-impl"),
157    secgate::secure_gate(options(info, api))
158)]
159pub fn monitor_rt_get_compartment_deps(
160    info: &secgate::GateCallInfo,
161    desc: Option<Descriptor>,
162    dep_n: usize,
163) -> Result<Descriptor, TwzError> {
164    let monitor = crate::mon::get_monitor();
165    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
166    monitor.get_compartment_deps(caller, desc, dep_n)
167}
168
169#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash, Copy)]
170#[repr(C)]
171pub struct ThreadInfo {
172    pub repr_id: ObjID,
173}
174
175#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
176#[cfg_attr(
177    not(feature = "secgate-impl"),
178    secgate::secure_gate(options(info, api))
179)]
180pub fn monitor_rt_get_compartment_thread(
181    info: &secgate::GateCallInfo,
182    desc: Option<Descriptor>,
183    dep_n: usize,
184) -> Result<ThreadInfo, TwzError> {
185    let monitor = crate::mon::get_monitor();
186    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
187    monitor.get_compartment_thread_info(caller, desc, dep_n)
188}
189
190#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
191#[cfg_attr(
192    not(feature = "secgate-impl"),
193    secgate::secure_gate(options(info, api))
194)]
195pub fn monitor_rt_lookup_compartment(
196    info: &secgate::GateCallInfo,
197    name_len: usize,
198) -> Result<Descriptor, TwzError> {
199    let monitor = crate::mon::get_monitor();
200    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
201    monitor.lookup_compartment(caller, info.thread_id(), name_len)
202}
203
204// Safety: the broken part is just DlPhdrInfo. We ensure that any pointers in there are
205// intra-compartment.
206unsafe impl Crossing for LibraryInfo {}
207
208#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
209#[cfg_attr(
210    not(feature = "secgate-impl"),
211    secgate::secure_gate(options(info, api))
212)]
213pub fn monitor_rt_load_compartment(
214    info: &secgate::GateCallInfo,
215    name_len: u64,
216    args_len: u64,
217    env_len: u64,
218    flags: u32,
219) -> Result<Descriptor, TwzError> {
220    let monitor = crate::mon::get_monitor();
221    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
222    monitor.load_compartment(
223        caller,
224        info.thread_id(),
225        name_len as usize,
226        args_len as usize,
227        env_len as usize,
228        NewCompartmentFlags::from_bits(flags).ok_or(ArgumentError::InvalidArgument)?,
229    )
230}
231
232#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
233#[cfg_attr(
234    not(feature = "secgate-impl"),
235    secgate::secure_gate(options(info, api))
236)]
237pub fn monitor_rt_compartment_wait(
238    info: &secgate::GateCallInfo,
239    desc: Option<Descriptor>,
240    flags: u64,
241) -> Result<u64, TwzError> {
242    let monitor = crate::mon::get_monitor();
243    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
244    Ok(monitor.compartment_wait(caller, desc, flags))
245}
246
247#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
248#[cfg_attr(
249    not(feature = "secgate-impl"),
250    secgate::secure_gate(options(info, api))
251)]
252pub fn monitor_rt_drop_compartment_handle(
253    info: &secgate::GateCallInfo,
254    desc: Descriptor,
255) -> Result<(), TwzError> {
256    let monitor = crate::mon::get_monitor();
257    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
258    monitor.drop_compartment_handle(caller, desc);
259    Ok(())
260}
261
262#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
263#[cfg_attr(
264    not(feature = "secgate-impl"),
265    secgate::secure_gate(options(info, api))
266)]
267pub fn monitor_rt_load_library(
268    info: &secgate::GateCallInfo,
269    compartment: Option<Descriptor>,
270    id: ObjID,
271) -> Result<Descriptor, TwzError> {
272    let monitor = crate::mon::get_monitor();
273    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
274    monitor.load_library(caller, id, compartment)
275}
276
277#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
278#[cfg_attr(
279    not(feature = "secgate-impl"),
280    secgate::secure_gate(options(info, api))
281)]
282pub fn monitor_rt_drop_library_handle(
283    info: &secgate::GateCallInfo,
284    desc: Descriptor,
285) -> Result<(), TwzError> {
286    let monitor = crate::mon::get_monitor();
287    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
288    monitor.drop_library_handle(caller, desc);
289    Ok(())
290}
291
292#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
293#[cfg_attr(
294    not(feature = "secgate-impl"),
295    secgate::secure_gate(options(info, api))
296)]
297pub fn monitor_rt_object_map(
298    info: &secgate::GateCallInfo,
299    id: ObjID,
300    flags: twizzler_rt_abi::object::MapFlags,
301) -> Result<crate::MappedObjectAddrs, TwzError> {
302    use crate::mon::space::MapInfo;
303    if unsafe { __is_monitor_ready() } {
304        // Are we recursing from the monitor, with a lock held? In that case, use early_object_map
305        // to map the object. This will leak this mapping, but this is both rare, and then
306        // since the mapping is leaked, it can be used as an allocator object indefinitely
307        // (not currently implemented). Make sure the ThreadKey drops.
308        let is_monitor_recursed =
309            { happylock::ThreadKey::get().is_none() && info.source_context().is_none() };
310        if is_monitor_recursed {
311            tracing::debug!(
312                "performing early object mapping (recursed), {} {:?}",
313                id,
314                flags
315            );
316            return Ok(crate::mon::early_object_map(MapInfo { id, flags }));
317        }
318        let monitor = crate::mon::get_monitor();
319        monitor
320            .map_object(
321                info.source_context().unwrap_or(MONITOR_INSTANCE_ID),
322                MapInfo { id, flags },
323            )
324            .map(|handle| handle.addrs())
325    } else {
326        // We need to use early_object_map, since the monitor hasn't finished initializing, but
327        // still needs to allocate (which may involve mapping an object).
328        tracing::debug!("performing early object mapping, {} {:?}", id, flags);
329        Ok(crate::mon::early_object_map(MapInfo { id, flags }))
330    }
331}
332
333#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
334#[cfg_attr(
335    not(feature = "secgate-impl"),
336    secgate::secure_gate(options(info, api))
337)]
338pub fn monitor_rt_object_pair_map(
339    info: &secgate::GateCallInfo,
340    id: ObjID,
341    flags: twizzler_rt_abi::object::MapFlags,
342    id2: ObjID,
343    flags2: twizzler_rt_abi::object::MapFlags,
344) -> Result<(crate::MappedObjectAddrs, crate::MappedObjectAddrs), TwzError> {
345    use crate::mon::space::MapInfo;
346    if unsafe { !__is_monitor_ready() } {
347        return Err(ResourceError::Unavailable.into());
348    }
349    let monitor = crate::mon::get_monitor();
350    monitor
351        .map_pair(
352            info.source_context().unwrap_or(MONITOR_INSTANCE_ID),
353            MapInfo { id, flags },
354            MapInfo {
355                id: id2,
356                flags: flags2,
357            },
358        )
359        .map(|(one, two)| (one.addrs(), two.addrs()))
360}
361
362#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
363#[cfg_attr(
364    not(feature = "secgate-impl"),
365    secgate::secure_gate(options(info, api))
366)]
367pub fn monitor_rt_object_unmap(
368    info: &secgate::GateCallInfo,
369    id: ObjID,
370    flags: twizzler_rt_abi::object::MapFlags,
371) -> Result<(), TwzError> {
372    if unsafe { __is_monitor_ready() } {
373        let monitor = crate::mon::get_monitor();
374        monitor.unmap_object(
375            info.source_context().unwrap_or(MONITOR_INSTANCE_ID),
376            crate::mon::space::MapInfo { id, flags },
377        );
378    }
379    Ok(())
380}
381
382#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
383#[cfg_attr(
384    not(feature = "secgate-impl"),
385    secgate::secure_gate(options(info, api))
386)]
387pub fn monitor_rt_get_thread_simple_buffer(
388    info: &secgate::GateCallInfo,
389) -> Result<ObjID, TwzError> {
390    let monitor = crate::mon::get_monitor();
391    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
392    monitor.get_thread_simple_buffer(caller, info.thread_id())
393}
394
395#[derive(Debug, Copy, Clone)]
396#[repr(C)]
397#[allow(dead_code)]
398pub enum MonitorCompControlCmd {
399    RuntimeReady,
400    RuntimePostMain,
401}
402
403#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
404#[cfg_attr(
405    not(feature = "secgate-impl"),
406    secgate::secure_gate(options(info, api))
407)]
408pub fn monitor_rt_comp_ctrl(
409    info: &secgate::GateCallInfo,
410    cmd: MonitorCompControlCmd,
411) -> Result<Option<i32>, TwzError> {
412    let monitor = crate::mon::get_monitor();
413    Ok(monitor.compartment_ctrl(info, cmd))
414}
415
416#[derive(Copy, Clone, Debug)]
417#[repr(C)]
418pub struct MonitorStats {
419    pub space: SpaceStats,
420    pub thread_mgr: ThreadMgrStats,
421    pub comp_mgr: CompartmentMgrStats,
422    pub handles: HandleStats,
423    pub dynlink: DynlinkStats,
424}
425
426#[derive(Copy, Clone, Debug)]
427#[repr(C)]
428pub struct SpaceStats {
429    pub mapped: usize,
430}
431
432#[derive(Copy, Clone, Debug)]
433#[repr(C)]
434pub struct ThreadMgrStats {
435    pub nr_threads: usize,
436}
437
438#[derive(Copy, Clone, Debug)]
439#[repr(C)]
440pub struct CompartmentMgrStats {
441    pub nr_compartments: usize,
442}
443
444#[derive(Copy, Clone, Debug)]
445#[repr(C)]
446pub struct HandleStats {
447    pub nr_comp_handles: usize,
448    pub nr_lib_handles: usize,
449}
450
451#[derive(Copy, Clone, Debug)]
452#[repr(C)]
453pub struct DynlinkStats {
454    pub nr_libs: usize,
455    pub nr_comps: usize,
456}
457
458#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
459#[cfg_attr(
460    not(feature = "secgate-impl"),
461    secgate::secure_gate(options(info, api))
462)]
463pub fn monitor_rt_stats(_info: &secgate::GateCallInfo) -> Result<MonitorStats, TwzError> {
464    let monitor = crate::mon::get_monitor();
465    Ok(monitor.stats())
466}
467
468#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
469#[cfg_attr(
470    not(feature = "secgate-impl"),
471    secgate::secure_gate(options(info, api))
472)]
473pub fn monitor_rt_set_nameroot(info: &secgate::GateCallInfo, root: ObjID) -> Result<(), TwzError> {
474    let monitor = crate::mon::get_monitor();
475    monitor.set_nameroot(info, root)
476}