monitor/
gates.rs

1use dynlink::context::NewCompartmentFlags;
2use monitor_api::{
3    CompartmentInfoRaw, LibraryInfoRaw, MonitorCompControlCmd, MonitorStats, PostSignalFlags,
4    ThreadInfo, MONITOR_INSTANCE_ID,
5};
6use secgate::util::Descriptor;
7use twizzler_rt_abi::{
8    error::{ArgumentError, ResourceError, TwzError},
9    object::ObjID,
10    thread::ThreadSpawnArgs,
11};
12
13extern "C-unwind" {
14    fn __is_monitor_ready() -> bool;
15}
16
17#[secgate::entry(lib = "monitor-api")]
18pub fn monitor_rt_spawn_thread(
19    args: ThreadSpawnArgs,
20    thread_pointer: usize,
21    stack_pointer: usize,
22) -> Result<ObjID, TwzError> {
23    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
24    let monitor = crate::mon::get_monitor();
25    monitor.spawn_compartment_thread(
26        info.source_context().unwrap_or(0.into()),
27        args,
28        stack_pointer,
29        thread_pointer,
30    )
31}
32
33#[secgate::entry(lib = "monitor-api")]
34pub fn monitor_rt_get_comp_config() -> Result<usize, TwzError> {
35    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
36    let monitor = crate::mon::get_monitor();
37    Ok(monitor
38        .get_comp_config(info.source_context().unwrap_or(MONITOR_INSTANCE_ID))
39        .map(|ptr| ptr as usize)
40        .unwrap_or(0))
41}
42
43#[secgate::entry(lib = "monitor-api")]
44pub fn monitor_rt_get_library_info(desc: Descriptor) -> Result<LibraryInfoRaw, TwzError> {
45    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
46    let monitor = crate::mon::get_monitor();
47    let instance = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
48    let thread = info.thread_id();
49    monitor.get_library_info(instance, thread, desc)
50}
51
52#[secgate::entry(lib = "monitor-api")]
53pub fn monitor_rt_get_library_handle(
54    compartment: Option<Descriptor>,
55    lib_n: usize,
56) -> Result<Descriptor, TwzError> {
57    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
58    let monitor = crate::mon::get_monitor();
59    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
60    monitor.get_library_handle(caller, compartment, lib_n)
61}
62
63#[secgate::entry(lib = "monitor-api")]
64pub fn monitor_rt_get_compartment_handle(compartment: ObjID) -> Result<Descriptor, TwzError> {
65    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
66    let monitor = crate::mon::get_monitor();
67    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
68    let compartment = if compartment.raw() == 0 {
69        caller
70    } else {
71        compartment
72    };
73    monitor.get_compartment_handle(caller, compartment)
74}
75
76#[secgate::entry(lib = "monitor-api")]
77pub fn monitor_rt_get_compartment_info(
78    desc: Option<Descriptor>,
79) -> Result<CompartmentInfoRaw, TwzError> {
80    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
81    let monitor = crate::mon::get_monitor();
82    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
83    monitor.get_compartment_info(caller, info.thread_id(), desc)
84}
85
86#[secgate::entry(lib = "monitor-api")]
87pub fn monitor_rt_compartment_dynamic_gate(
88    desc: Option<Descriptor>,
89    name_len: usize,
90) -> Result<usize, TwzError> {
91    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
92    let monitor = crate::mon::get_monitor();
93    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
94    monitor.get_compartment_gate_address(caller, info.thread_id(), desc, name_len)
95}
96
97#[secgate::entry(lib = "monitor-api")]
98pub fn monitor_rt_get_compartment_deps(
99    desc: Option<Descriptor>,
100    dep_n: usize,
101) -> Result<Descriptor, TwzError> {
102    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
103    let monitor = crate::mon::get_monitor();
104    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
105    monitor.get_compartment_deps(caller, desc, dep_n)
106}
107
108#[secgate::entry(lib = "monitor-api")]
109pub fn monitor_rt_get_compartment_thread(
110    desc: Option<Descriptor>,
111    dep_n: usize,
112) -> Result<ThreadInfo, TwzError> {
113    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
114    let monitor = crate::mon::get_monitor();
115    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
116    monitor.get_compartment_thread_info(caller, desc, dep_n)
117}
118
119#[secgate::entry(lib = "monitor-api")]
120pub fn monitor_rt_lookup_compartment(name_len: usize) -> Result<Descriptor, TwzError> {
121    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
122    let monitor = crate::mon::get_monitor();
123    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
124    monitor.lookup_compartment(caller, info.thread_id(), name_len)
125}
126
127#[secgate::entry(lib = "monitor-api")]
128pub fn monitor_rt_load_compartment(
129    root_obj: ObjID,
130    name_len: u64,
131    args_len: u64,
132    env_len: u64,
133    flags: u32,
134    config: u64,
135) -> Result<Descriptor, TwzError> {
136    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
137    let monitor = crate::mon::get_monitor();
138    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
139    monitor.load_compartment(
140        caller,
141        info.thread_id(),
142        root_obj,
143        name_len as usize,
144        args_len as usize,
145        env_len as usize,
146        NewCompartmentFlags::from_bits(flags).ok_or(ArgumentError::InvalidArgument)?,
147        config as usize as *const _,
148    )
149}
150
151#[secgate::entry(lib = "monitor-api")]
152pub fn monitor_rt_compartment_wait(desc: Option<Descriptor>, flags: u64) -> Result<u64, TwzError> {
153    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
154    let monitor = crate::mon::get_monitor();
155    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
156    Ok(monitor.compartment_wait(caller, desc, flags))
157}
158
159#[secgate::entry(lib = "monitor-api")]
160pub fn monitor_rt_drop_compartment_handle(desc: Descriptor) -> Result<(), TwzError> {
161    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
162    let monitor = crate::mon::get_monitor();
163    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
164    monitor.drop_compartment_handle(caller, desc);
165    Ok(())
166}
167
168#[secgate::entry(lib = "monitor-api")]
169pub fn monitor_rt_load_library(
170    _compartment: Option<Descriptor>,
171    id: Option<ObjID>,
172    name_len: usize,
173) -> Result<(Descriptor, usize), TwzError> {
174    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
175    let monitor = crate::mon::get_monitor();
176    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
177    monitor.load_library_by_name(caller, info.thread_id(), name_len, id)
178}
179
180#[secgate::entry(lib = "monitor-api")]
181pub fn monitor_rt_drop_library_handle(desc: Descriptor) -> Result<(), TwzError> {
182    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
183    let monitor = crate::mon::get_monitor();
184    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
185    monitor.drop_library_handle(caller, desc);
186    Ok(())
187}
188
189#[secgate::entry(lib = "monitor-api")]
190pub fn monitor_rt_object_map(
191    id: ObjID,
192    flags: twizzler_rt_abi::object::MapFlags,
193) -> Result<crate::MappedObjectAddrs, TwzError> {
194    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
195    use crate::mon::space::MapInfo;
196    if unsafe { __is_monitor_ready() } {
197        // Are we recursing from the monitor, with a lock held? In that case, use early_object_map
198        // to map the object. This will leak this mapping, but this is both rare, and then
199        // since the mapping is leaked, it can be used as an allocator object indefinitely
200        // (not currently implemented). Make sure the ThreadKey drops.
201        let is_monitor_recursed =
202            { happylock::ThreadKey::get().is_none() && info.source_context().is_none() };
203        if is_monitor_recursed {
204            tracing::debug!(
205                "performing early object mapping (recursed), {} {:?}",
206                id,
207                flags
208            );
209            return Ok(crate::mon::early_object_map(MapInfo { id, flags }));
210        }
211        let monitor = crate::mon::get_monitor();
212        monitor
213            .map_object(
214                info.source_context().unwrap_or(MONITOR_INSTANCE_ID),
215                MapInfo { id, flags },
216            )
217            .map(|handle| handle.addrs())
218    } else {
219        // We need to use early_object_map, since the monitor hasn't finished initializing, but
220        // still needs to allocate (which may involve mapping an object).
221        tracing::debug!("performing early object mapping, {} {:?}", id, flags);
222        Ok(crate::mon::early_object_map(MapInfo { id, flags }))
223    }
224}
225
226#[secgate::entry(lib = "monitor-api")]
227pub fn monitor_rt_object_pair_map(
228    id: ObjID,
229    flags: twizzler_rt_abi::object::MapFlags,
230    id2: ObjID,
231    flags2: twizzler_rt_abi::object::MapFlags,
232) -> Result<(crate::MappedObjectAddrs, crate::MappedObjectAddrs), TwzError> {
233    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
234    use crate::mon::space::MapInfo;
235    if unsafe { !__is_monitor_ready() } {
236        return Err(ResourceError::Unavailable.into());
237    }
238    let monitor = crate::mon::get_monitor();
239    monitor
240        .map_pair(
241            info.source_context().unwrap_or(MONITOR_INSTANCE_ID),
242            MapInfo { id, flags },
243            MapInfo {
244                id: id2,
245                flags: flags2,
246            },
247        )
248        .map(|(one, two)| (one.addrs(), two.addrs()))
249}
250
251#[secgate::entry(lib = "monitor-api")]
252pub fn monitor_rt_object_unmap(
253    id: ObjID,
254    flags: twizzler_rt_abi::object::MapFlags,
255) -> Result<(), TwzError> {
256    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
257    if unsafe { __is_monitor_ready() } {
258        let monitor = crate::mon::get_monitor();
259        monitor.unmap_object(
260            info.source_context().unwrap_or(MONITOR_INSTANCE_ID),
261            crate::mon::space::MapInfo { id, flags },
262        );
263    }
264    Ok(())
265}
266
267#[secgate::entry(lib = "monitor-api")]
268pub fn monitor_rt_get_thread_simple_buffer() -> Result<ObjID, TwzError> {
269    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
270    let monitor = crate::mon::get_monitor();
271    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
272    monitor.get_thread_simple_buffer(caller, info.thread_id())
273}
274
275#[secgate::entry(lib = "monitor-api")]
276pub fn monitor_rt_comp_ctrl(cmd: MonitorCompControlCmd) -> Result<Option<i32>, TwzError> {
277    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
278    let monitor = crate::mon::get_monitor();
279    Ok(monitor.compartment_ctrl(&info, cmd))
280}
281
282#[secgate::entry(lib = "monitor-api")]
283pub fn monitor_rt_stats() -> Result<MonitorStats, TwzError> {
284    let monitor = crate::mon::get_monitor();
285    Ok(monitor.stats())
286}
287
288#[secgate::entry(lib = "monitor-api")]
289pub fn monitor_rt_post_signal(
290    comp: Option<ObjID>,
291    signal: u64,
292    flags: PostSignalFlags,
293) -> Result<(), TwzError> {
294    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
295    let monitor = crate::mon::get_monitor();
296    monitor.post_signal(&info, comp, signal, flags)
297}
298
299#[secgate::entry(lib = "monitor-api")]
300pub fn monitor_rt_set_controller(comp: ObjID, controller: ObjID) -> Result<(), TwzError> {
301    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
302    let monitor = crate::mon::get_monitor();
303    let comp = if comp.raw() == 0 {
304        info.source_context().unwrap_or(MONITOR_INSTANCE_ID)
305    } else {
306        comp
307    };
308    monitor.set_controller(&info, comp, controller)
309}
310
311#[secgate::entry(lib = "monitor-api")]
312pub fn monitor_rt_lookup_compartment_id(id: ObjID) -> Result<Descriptor, TwzError> {
313    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
314    let monitor = crate::mon::get_monitor();
315    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
316    monitor.lookup_compartment_id(caller, info.thread_id(), id)
317}
318
319#[secgate::entry(lib = "monitor-api")]
320pub fn monitor_rt_libname_map(namelen: usize, id: ObjID) -> Result<(), TwzError> {
321    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
322    let monitor = crate::mon::get_monitor();
323    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
324    monitor.libname_map(caller, info.thread_id(), namelen, id)
325}
326
327#[secgate::entry(lib = "monitor-api")]
328pub fn monitor_rt_libname_unmap(namelen: Option<usize>, id: Option<ObjID>) -> Result<(), TwzError> {
329    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
330    let monitor = crate::mon::get_monitor();
331    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
332    monitor.libname_unmap(caller, info.thread_id(), namelen, id)
333}
334
335#[secgate::entry(lib = "monitor-api")]
336pub fn monitor_rt_lookup_symbol(
337    lib_desc: Option<Descriptor>,
338    name_len: usize,
339) -> Result<usize, TwzError> {
340    let info = secgate::get_caller().ok_or(TwzError::NOT_SUPPORTED)?;
341    let monitor = crate::mon::get_monitor();
342    let caller = info.source_context().unwrap_or(MONITOR_INSTANCE_ID);
343    monitor.lookup_symbol(caller, info.thread_id(), lib_desc, name_len)
344}