monitor/
dlengine.rs

1use std::sync::OnceLock;
2
3use dynlink::{
4    compartment::{CompartmentId, MONITOR_COMPARTMENT_ID},
5    engines::{Backing, ContextEngine, LoadCtx},
6    library::UnloadedLibrary,
7    DynlinkError, DynlinkErrorKind,
8};
9use naming_core::{GetFlags, NameStore, NsNodeKind};
10use twizzler_abi::{
11    aux::KernelInitInfo,
12    object::{MAX_SIZE, NULLPAGE_SIZE},
13};
14use twizzler_rt_abi::{
15    error::{NamingError, TwzError},
16    object::{MapFlags, ObjID},
17};
18use twizzler_security::SecCtx;
19
20use crate::mon::{
21    get_monitor,
22    space::{MapInfo, Space},
23};
24
25pub struct Engine;
26
27fn get_new_sctx_instance(_sctx: ObjID) -> ObjID {
28    let sec_ctx = SecCtx::default();
29    sec_ctx.id()
30}
31
32impl ContextEngine for Engine {
33    fn load_segments(
34        &mut self,
35        src: &Backing,
36        ld: &[dynlink::engines::LoadDirective],
37        comp_id: CompartmentId,
38        load_ctx: &mut LoadCtx,
39    ) -> Result<Vec<Backing>, dynlink::DynlinkError> {
40        let instance = *load_ctx
41            .set
42            .entry(comp_id)
43            .or_insert_with(|| get_new_sctx_instance(1.into()));
44        let map = |text_id, data_id| {
45            #[allow(deprecated)]
46            let (text_handle, data_handle) = get_monitor()
47                .space
48                .lock()
49                .unwrap()
50                .map_pair(
51                    MapInfo {
52                        id: text_id,
53                        flags: MapFlags::READ | MapFlags::EXEC,
54                    },
55                    MapInfo {
56                        id: data_id,
57                        flags: MapFlags::READ | MapFlags::WRITE,
58                    },
59                )
60                .map_err(|_| DynlinkErrorKind::NewBackingFail)?;
61
62            if data_handle.monitor_data_start() as usize
63                != text_handle.monitor_data_start() as usize + MAX_SIZE
64            {
65                tracing::error!(
66                                "internal runtime error: failed to map text and data adjacent and in-order ({:p} {:p})",
67                                text_handle.monitor_data_start(),
68                                data_handle.monitor_data_start(),
69                            );
70                return Err(DynlinkErrorKind::NewBackingFail.into());
71            }
72            tracing::trace!(
73                "map {}: {} {}",
74                src.full_name(),
75                text_handle.id(),
76                data_handle.id()
77            );
78            unsafe {
79                Ok((
80                    Backing::new_owned(
81                        text_handle.monitor_data_start(),
82                        MAX_SIZE - NULLPAGE_SIZE * 2,
83                        text_id,
84                        text_handle,
85                        src.full_name().into(),
86                    ),
87                    Backing::new_owned(
88                        data_handle.monitor_data_start(),
89                        MAX_SIZE - NULLPAGE_SIZE * 2,
90                        data_id,
91                        data_handle,
92                        src.full_name().into(),
93                    ),
94                ))
95            }
96        };
97        dynlink::engines::twizzler::load_segments(src, ld, instance, map)
98    }
99
100    fn load_object(&mut self, unlib: &UnloadedLibrary) -> Result<Backing, DynlinkError> {
101        let (id, full) = name_resolver(&unlib.name)?;
102        let mapping = Space::map(
103            &get_monitor().space,
104            MapInfo {
105                id,
106                flags: MapFlags::READ,
107            },
108        )
109        .map_err(|_err| DynlinkErrorKind::NewBackingFail)?;
110        Ok(unsafe {
111            Backing::new_owned(
112                mapping.monitor_data_start(),
113                MAX_SIZE - NULLPAGE_SIZE * 2,
114                id,
115                mapping,
116                full,
117            )
118        })
119    }
120
121    fn select_compartment(
122        &mut self,
123        _unlib: &UnloadedLibrary,
124    ) -> Option<dynlink::compartment::CompartmentId> {
125        Some(MONITOR_COMPARTMENT_ID)
126    }
127}
128
129static NAMING: OnceLock<NameStore> = OnceLock::new();
130
131pub fn set_naming(root: ObjID) -> Result<(), TwzError> {
132    NAMING
133        .set(NameStore::new_with_root(root)?)
134        .map_err(|_| NamingError::AlreadyBound.into())
135}
136
137pub fn naming() -> Option<&'static NameStore> {
138    NAMING.get()
139}
140
141fn do_name_resolver(name: &str) -> Result<(ObjID, String), DynlinkError> {
142    if let Some(namer) = naming() {
143        let session = namer.root_session();
144        let node = session
145            .get(name, GetFlags::FOLLOW_SYMLINK)
146            .map_err(|_| DynlinkErrorKind::NameNotFound { name: name.into() })?;
147        return match node.kind {
148            NsNodeKind::Object => Ok((node.id, name.into())),
149            _ => Err(DynlinkErrorKind::NameNotFound { name: name.into() }.into()),
150        };
151    }
152
153    find_init_name(name).ok_or(DynlinkErrorKind::NameNotFound { name: name.into() }.into())
154}
155
156fn name_resolver(mut name: &str) -> Result<(ObjID, String), DynlinkError> {
157    if name.starts_with("libstd") {
158        name = "libstd.so";
159    }
160    if name.starts_with("libtest") {
161        name = "libtest.so";
162    }
163
164    if let Ok(r) = do_name_resolver(name) {
165        return Ok(r);
166    }
167
168    let initrdname = format!("/initrd/{}", name);
169    do_name_resolver(initrdname.as_str())
170}
171
172pub fn get_kernel_init_info() -> &'static KernelInitInfo {
173    unsafe {
174        (((twizzler_abi::slot::RESERVED_KERNEL_INIT * MAX_SIZE) + NULLPAGE_SIZE)
175            as *const KernelInitInfo)
176            .as_ref()
177            .unwrap()
178    }
179}
180
181fn find_init_name(name: &str) -> Option<(ObjID, String)> {
182    let init_info = get_kernel_init_info();
183    for n in init_info.names() {
184        if n.name() == name {
185            return Some((n.id(), name.to_string()));
186        }
187    }
188    None
189}