hyperlight_host/sandbox/
mod.rs

1/*
2Copyright 2024 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
20mod 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;
26/// Functionality for dealing with memory access from the VM guest
27/// executable
28pub(crate) mod mem_access;
29/// Functionality for interacting with a sandbox's internally-stored
30/// `SandboxMemoryManager`
31pub(crate) mod mem_mgr;
32pub(crate) mod outb;
33/// Functionality for creating uninitialized sandboxes, manipulating them,
34/// and converting them to initialized sandboxes.
35pub mod uninitialized;
36/// Functionality for properly converting `UninitializedSandbox`es to
37/// initialized `Sandbox`es.
38pub(crate) mod uninitialized_evolve;
39
40/// Re-export for `SandboxConfiguration` type
41pub use config::SandboxConfiguration;
42/// Re-export for the `MultiUseSandbox` type
43pub use initialized_multi_use::MultiUseSandbox;
44use tracing::{instrument, Span};
45/// Re-export for `GuestBinary` type
46pub use uninitialized::GuestBinary;
47/// Re-export for `UninitializedSandbox` type
48pub use uninitialized::UninitializedSandbox;
49
50use self::mem_mgr::MemMgrWrapper;
51use crate::hypervisor::hypervisor_handler::HypervisorHandler;
52#[cfg(target_os = "windows")]
53use crate::hypervisor::windows_hypervisor_platform;
54use crate::mem::shared_mem::HostSharedMemory;
55
56// In case its not obvious why there are separate is_supported_platform and is_hypervisor_present functions its because
57// Hyperlight is designed to be able to run on a host that doesn't have a hypervisor.
58// In that case, the sandbox will be in process, we plan on making this a dev only feature and fixing up Linux support
59// so we should review the need for this function at that time.
60
61/// Determine if this is a supported platform for Hyperlight
62///
63/// Returns a boolean indicating whether this is a supported platform.
64#[instrument(skip_all, parent = Span::current())]
65pub fn is_supported_platform() -> bool {
66    #[cfg(not(target_os = "linux"))]
67    #[cfg(not(target_os = "windows"))]
68    return false;
69
70    true
71}
72
73/// Alias for the type of extra allowed syscalls.
74pub type ExtraAllowedSyscall = i64;
75
76/// Determine whether a suitable hypervisor is available to run
77/// this sandbox.
78///
79//  Returns a boolean indicating whether a suitable hypervisor is present.
80#[instrument(skip_all, parent = Span::current())]
81pub fn is_hypervisor_present() -> bool {
82    hypervisor::get_available_hypervisor().is_some()
83}
84
85pub(crate) trait WrapperGetter {
86    #[allow(dead_code)]
87    fn get_mgr_wrapper(&self) -> &MemMgrWrapper<HostSharedMemory>;
88    fn get_mgr_wrapper_mut(&mut self) -> &mut MemMgrWrapper<HostSharedMemory>;
89    fn get_hv_handler(&self) -> &HypervisorHandler;
90    #[allow(dead_code)]
91    fn get_hv_handler_mut(&mut self) -> &mut HypervisorHandler;
92}
93
94#[cfg(test)]
95mod tests {
96    use std::sync::Arc;
97    use std::thread;
98
99    use crossbeam_queue::ArrayQueue;
100    use hyperlight_testing::simple_guest_as_string;
101
102    use crate::sandbox::uninitialized::GuestBinary;
103    use crate::sandbox_state::sandbox::EvolvableSandbox;
104    use crate::sandbox_state::transition::Noop;
105    use crate::{new_error, MultiUseSandbox, UninitializedSandbox};
106
107    #[test]
108    // TODO: add support for testing on WHP
109    #[cfg(target_os = "linux")]
110    fn is_hypervisor_present() {
111        use std::path::Path;
112
113        cfg_if::cfg_if! {
114            if #[cfg(all(kvm, mshv))] {
115                assert_eq!(Path::new("/dev/kvm").exists() || Path::new("/dev/mshv").exists(), super::is_hypervisor_present());
116            } else if #[cfg(kvm)] {
117                assert_eq!(Path::new("/dev/kvm").exists(), super::is_hypervisor_present());
118            } else if #[cfg(mshv)] {
119                assert_eq!(Path::new("/dev/mshv").exists(), super::is_hypervisor_present());
120            } else {
121                assert!(!super::is_hypervisor_present());
122            }
123        }
124    }
125
126    #[test]
127    fn check_create_and_use_sandbox_on_different_threads() {
128        let unintializedsandbox_queue = Arc::new(ArrayQueue::<UninitializedSandbox>::new(10));
129        let sandbox_queue = Arc::new(ArrayQueue::<MultiUseSandbox>::new(10));
130
131        for i in 0..10 {
132            let simple_guest_path = simple_guest_as_string().expect("Guest Binary Missing");
133            let unintializedsandbox =
134                UninitializedSandbox::new(GuestBinary::FilePath(simple_guest_path), None)
135                    .unwrap_or_else(|_| panic!("Failed to create UninitializedSandbox {}", i));
136
137            unintializedsandbox_queue
138                .push(unintializedsandbox)
139                .unwrap_or_else(|_| panic!("Failed to push UninitializedSandbox {}", i));
140        }
141
142        let thread_handles = (0..10)
143            .map(|i| {
144                let uq = unintializedsandbox_queue.clone();
145                let sq = sandbox_queue.clone();
146                thread::spawn(move || {
147                    let uninitialized_sandbox = uq.pop().unwrap_or_else(|| {
148                        panic!("Failed to pop UninitializedSandbox thread {}", i)
149                    });
150                    let host_funcs = uninitialized_sandbox
151                        .host_funcs
152                        .try_lock()
153                        .map_err(|_| new_error!("Error locking"));
154
155                    assert!(host_funcs.is_ok());
156
157                    host_funcs
158                        .unwrap()
159                        .host_print(format!(
160                            "Printing from UninitializedSandbox on Thread {}\n",
161                            i
162                        ))
163                        .unwrap();
164
165                    let sandbox = uninitialized_sandbox
166                        .evolve(Noop::default())
167                        .unwrap_or_else(|_| {
168                            panic!("Failed to initialize UninitializedSandbox thread {}", i)
169                        });
170
171                    sq.push(sandbox).unwrap_or_else(|_| {
172                        panic!("Failed to push UninitializedSandbox thread {}", i)
173                    })
174                })
175            })
176            .collect::<Vec<_>>();
177
178        for handle in thread_handles {
179            handle.join().unwrap();
180        }
181
182        let thread_handles = (0..10)
183            .map(|i| {
184                let sq = sandbox_queue.clone();
185                thread::spawn(move || {
186                    let sandbox = sq
187                        .pop()
188                        .unwrap_or_else(|| panic!("Failed to pop Sandbox thread {}", i));
189                    let host_funcs = sandbox
190                        ._host_funcs
191                        .try_lock()
192                        .map_err(|_| new_error!("Error locking"));
193
194                    assert!(host_funcs.is_ok());
195
196                    host_funcs
197                        .unwrap()
198                        .host_print(format!("Print from Sandbox on Thread {}\n", i))
199                        .unwrap();
200                })
201            })
202            .collect::<Vec<_>>();
203
204        for handle in thread_handles {
205            handle.join().unwrap();
206        }
207    }
208}