hyperlight_host/sandbox/
mod.rs

1/*
2Copyright 2025  The Hyperlight Authors.
3
4Licensed under the Apache License, Version 2.0 (the "License");
5you may not use this file except in compliance with the License.
6You may obtain a copy of the License at
7
8    http://www.apache.org/licenses/LICENSE-2.0
9
10Unless required by applicable law or agreed to in writing, software
11distributed under the License is distributed on an "AS IS" BASIS,
12WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13See the License for the specific language governing permissions and
14limitations under the License.
15*/
16
17/// Configuration needed to establish a sandbox.
18pub mod config;
19/// Functionality for reading, but not modifying host functions
20pub(crate) mod host_funcs;
21/// Functionality for dealing with `Sandbox`es that contain Hypervisors
22pub(crate) mod hypervisor;
23/// Functionality for dealing with initialized sandboxes that can
24/// call 0 or more guest functions
25pub mod initialized_multi_use;
26pub(crate) mod outb;
27/// Functionality for creating uninitialized sandboxes, manipulating them,
28/// and converting them to initialized sandboxes.
29pub mod uninitialized;
30/// Functionality for properly converting `UninitializedSandbox`es to
31/// initialized `Sandbox`es.
32pub(crate) mod uninitialized_evolve;
33
34/// Representation of a snapshot of a `Sandbox`.
35pub mod snapshot;
36
37/// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm
38mod callable;
39
40/// Module for tracing guest execution
41#[cfg(feature = "trace_guest")]
42pub(crate) mod trace;
43
44/// Trait used by the macros to paper over the differences between hyperlight and hyperlight-wasm
45pub use callable::Callable;
46/// Re-export for `SandboxConfiguration` type
47pub use config::SandboxConfiguration;
48/// Re-export for the `MultiUseSandbox` type
49pub use initialized_multi_use::MultiUseSandbox;
50use tracing::{Span, instrument};
51/// Re-export for `GuestBinary` type
52pub use uninitialized::GuestBinary;
53/// Re-export for `UninitializedSandbox` type
54pub use uninitialized::UninitializedSandbox;
55
56/// Determine whether a suitable hypervisor is available to run
57/// this sandbox.
58///
59///  Returns a boolean indicating whether a suitable hypervisor is present.
60#[instrument(skip_all, parent = Span::current())]
61pub fn is_hypervisor_present() -> bool {
62    hypervisor::get_available_hypervisor().is_some()
63}
64
65#[cfg(test)]
66mod tests {
67    use std::sync::Arc;
68    use std::thread;
69
70    use crossbeam_queue::ArrayQueue;
71    use hyperlight_testing::simple_guest_as_string;
72
73    use crate::sandbox::uninitialized::GuestBinary;
74    use crate::{MultiUseSandbox, UninitializedSandbox, new_error};
75
76    #[test]
77    // TODO: add support for testing on WHP
78    #[cfg(target_os = "linux")]
79    fn is_hypervisor_present() {
80        use std::path::Path;
81
82        cfg_if::cfg_if! {
83            if #[cfg(all(kvm, mshv3))] {
84                assert_eq!(Path::new("/dev/kvm").exists() || Path::new("/dev/mshv").exists(), super::is_hypervisor_present());
85            } else if #[cfg(kvm)] {
86                assert_eq!(Path::new("/dev/kvm").exists(), super::is_hypervisor_present());
87            } else if #[cfg(mshv3)] {
88                assert_eq!(Path::new("/dev/mshv").exists(), super::is_hypervisor_present());
89            } else {
90                assert!(!super::is_hypervisor_present());
91            }
92        }
93    }
94
95    #[test]
96    fn check_create_and_use_sandbox_on_different_threads() {
97        let unintializedsandbox_queue = Arc::new(ArrayQueue::<UninitializedSandbox>::new(10));
98        let sandbox_queue = Arc::new(ArrayQueue::<MultiUseSandbox>::new(10));
99
100        for i in 0..10 {
101            let simple_guest_path = simple_guest_as_string().expect("Guest Binary Missing");
102            let unintializedsandbox =
103                UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_path), None)
104                    .unwrap_or_else(|_| panic!("Failed to create UninitializedSandbox {}", i));
105
106            unintializedsandbox_queue
107                .push(unintializedsandbox)
108                .unwrap_or_else(|_| panic!("Failed to push UninitializedSandbox {}", i));
109        }
110
111        let thread_handles = (0..10)
112            .map(|i| {
113                let uq = unintializedsandbox_queue.clone();
114                let sq = sandbox_queue.clone();
115                thread::spawn(move || {
116                    let uninitialized_sandbox = uq.pop().unwrap_or_else(|| {
117                        panic!("Failed to pop UninitializedSandbox thread {}", i)
118                    });
119                    let host_funcs = uninitialized_sandbox
120                        .host_funcs
121                        .try_lock()
122                        .map_err(|_| new_error!("Error locking"));
123
124                    assert!(host_funcs.is_ok());
125
126                    host_funcs
127                        .unwrap()
128                        .host_print(format!(
129                            "Printing from UninitializedSandbox on Thread {}\n",
130                            i
131                        ))
132                        .unwrap();
133
134                    let sandbox = uninitialized_sandbox.evolve().unwrap_or_else(|_| {
135                        panic!("Failed to initialize UninitializedSandbox thread {}", i)
136                    });
137
138                    sq.push(sandbox).unwrap_or_else(|_| {
139                        panic!("Failed to push UninitializedSandbox thread {}", i)
140                    })
141                })
142            })
143            .collect::<Vec<_>>();
144
145        for handle in thread_handles {
146            handle.join().unwrap();
147        }
148
149        let thread_handles = (0..10)
150            .map(|i| {
151                let sq = sandbox_queue.clone();
152                thread::spawn(move || {
153                    let sandbox = sq
154                        .pop()
155                        .unwrap_or_else(|| panic!("Failed to pop Sandbox thread {}", i));
156                    let host_funcs = sandbox
157                        .host_funcs
158                        .try_lock()
159                        .map_err(|_| new_error!("Error locking"));
160
161                    assert!(host_funcs.is_ok());
162
163                    host_funcs
164                        .unwrap()
165                        .host_print(format!("Print from Sandbox on Thread {}\n", i))
166                        .unwrap();
167                })
168            })
169            .collect::<Vec<_>>();
170
171        for handle in thread_handles {
172            handle.join().unwrap();
173        }
174    }
175}