hyperlight_host/sandbox/
mod.rs1pub mod config;
19mod host_funcs;
21pub(crate) mod hypervisor;
23pub mod initialized_multi_use;
26#[cfg(inprocess)]
31pub(crate) mod leaked_outb;
32pub(crate) mod mem_access;
35pub(crate) mod mem_mgr;
38pub(crate) mod outb;
39mod run_options;
41pub mod uninitialized;
44pub(crate) mod uninitialized_evolve;
47
48pub(crate) mod metrics;
50
51use std::collections::HashMap;
52
53pub use config::SandboxConfiguration;
55pub use initialized_multi_use::MultiUseSandbox;
57pub use run_options::SandboxRunOptions;
59use tracing::{instrument, Span};
60pub use uninitialized::GuestBinary;
62pub use uninitialized::UninitializedSandbox;
64
65use self::mem_mgr::MemMgrWrapper;
66use crate::func::HyperlightFunction;
67use crate::hypervisor::hypervisor_handler::HypervisorHandler;
68#[cfg(target_os = "windows")]
69use crate::hypervisor::windows_hypervisor_platform;
70use crate::mem::shared_mem::HostSharedMemory;
71
72#[instrument(skip_all, parent = Span::current())]
81pub fn is_supported_platform() -> bool {
82 #[cfg(not(target_os = "linux"))]
83 #[cfg(not(target_os = "windows"))]
84 return false;
85
86 true
87}
88
89pub type ExtraAllowedSyscall = i64;
91
92#[derive(Clone, Default)]
97pub(super) struct FunctionsMap(
98 HashMap<String, (HyperlightFunction, Option<Vec<ExtraAllowedSyscall>>)>,
99);
100
101impl FunctionsMap {
102 pub(super) fn insert(
104 &mut self,
105 key: String,
106 value: HyperlightFunction,
107 extra_syscalls: Option<Vec<ExtraAllowedSyscall>>,
108 ) {
109 self.0.insert(key, (value, extra_syscalls));
110 }
111
112 pub(super) fn get(
114 &self,
115 key: &str,
116 ) -> Option<&(HyperlightFunction, Option<Vec<ExtraAllowedSyscall>>)> {
117 self.0.get(key)
118 }
119
120 fn len(&self) -> usize {
122 self.0.len()
123 }
124}
125
126impl PartialEq for FunctionsMap {
127 #[instrument(skip_all, parent = Span::current(), level= "Trace")]
128 fn eq(&self, other: &Self) -> bool {
129 self.len() == other.len() && self.0.keys().all(|k| other.0.contains_key(k))
130 }
131}
132
133impl Eq for FunctionsMap {}
134
135#[instrument(skip_all, parent = Span::current())]
140pub fn is_hypervisor_present() -> bool {
141 hypervisor::get_available_hypervisor().is_some()
142}
143
144pub(crate) trait WrapperGetter {
145 #[allow(dead_code)]
146 fn get_mgr_wrapper(&self) -> &MemMgrWrapper<HostSharedMemory>;
147 fn get_mgr_wrapper_mut(&mut self) -> &mut MemMgrWrapper<HostSharedMemory>;
148 fn get_hv_handler(&self) -> &HypervisorHandler;
149 #[allow(dead_code)]
150 fn get_hv_handler_mut(&mut self) -> &mut HypervisorHandler;
151}
152
153#[cfg(test)]
154mod tests {
155 use std::sync::Arc;
156 use std::thread;
157
158 use crossbeam_queue::ArrayQueue;
159 use hyperlight_testing::simple_guest_as_string;
160
161 use crate::sandbox::uninitialized::GuestBinary;
162 use crate::sandbox_state::sandbox::EvolvableSandbox;
163 use crate::sandbox_state::transition::Noop;
164 use crate::{new_error, MultiUseSandbox, UninitializedSandbox};
165
166 #[test]
167 #[cfg(target_os = "linux")]
169 fn is_hypervisor_present() {
170 use std::path::Path;
171
172 cfg_if::cfg_if! {
173 if #[cfg(all(kvm, mshv))] {
174 assert_eq!(Path::new("/dev/kvm").exists() || Path::new("/dev/mshv").exists(), super::is_hypervisor_present());
175 } else if #[cfg(kvm)] {
176 assert_eq!(Path::new("/dev/kvm").exists(), super::is_hypervisor_present());
177 } else if #[cfg(mshv)] {
178 assert_eq!(Path::new("/dev/mshv").exists(), super::is_hypervisor_present());
179 } else {
180 assert!(!super::is_hypervisor_present());
181 }
182 }
183 }
184
185 #[test]
186 fn check_create_and_use_sandbox_on_different_threads() {
187 let unintializedsandbox_queue = Arc::new(ArrayQueue::<UninitializedSandbox>::new(10));
188 let sandbox_queue = Arc::new(ArrayQueue::<MultiUseSandbox>::new(10));
189
190 for i in 0..10 {
191 let simple_guest_path = simple_guest_as_string().expect("Guest Binary Missing");
192 let unintializedsandbox = UninitializedSandbox::new(
193 GuestBinary::FilePath(simple_guest_path),
194 None,
195 None,
196 None,
197 )
198 .unwrap_or_else(|_| panic!("Failed to create UninitializedSandbox {}", i));
199
200 unintializedsandbox_queue
201 .push(unintializedsandbox)
202 .unwrap_or_else(|_| panic!("Failed to push UninitializedSandbox {}", i));
203 }
204
205 let thread_handles = (0..10)
206 .map(|i| {
207 let uq = unintializedsandbox_queue.clone();
208 let sq = sandbox_queue.clone();
209 thread::spawn(move || {
210 let uninitialized_sandbox = uq.pop().unwrap_or_else(|| {
211 panic!("Failed to pop UninitializedSandbox thread {}", i)
212 });
213 let host_funcs = uninitialized_sandbox
214 .host_funcs
215 .try_lock()
216 .map_err(|_| new_error!("Error locking"));
217
218 assert!(host_funcs.is_ok());
219
220 host_funcs
221 .unwrap()
222 .host_print(format!(
223 "Printing from UninitializedSandbox on Thread {}\n",
224 i
225 ))
226 .unwrap();
227
228 let sandbox = uninitialized_sandbox
229 .evolve(Noop::default())
230 .unwrap_or_else(|_| {
231 panic!("Failed to initialize UninitializedSandbox thread {}", i)
232 });
233
234 sq.push(sandbox).unwrap_or_else(|_| {
235 panic!("Failed to push UninitializedSandbox thread {}", i)
236 })
237 })
238 })
239 .collect::<Vec<_>>();
240
241 for handle in thread_handles {
242 handle.join().unwrap();
243 }
244
245 let thread_handles = (0..10)
246 .map(|i| {
247 let sq = sandbox_queue.clone();
248 thread::spawn(move || {
249 let sandbox = sq
250 .pop()
251 .unwrap_or_else(|| panic!("Failed to pop Sandbox thread {}", i));
252 let host_funcs = sandbox
253 ._host_funcs
254 .try_lock()
255 .map_err(|_| new_error!("Error locking"));
256
257 assert!(host_funcs.is_ok());
258
259 host_funcs
260 .unwrap()
261 .host_print(format!("Print from Sandbox on Thread {}\n", i))
262 .unwrap();
263 })
264 })
265 .collect::<Vec<_>>();
266
267 for handle in thread_handles {
268 handle.join().unwrap();
269 }
270 }
271}