Skip to main content

hyperlight_wasm/sandbox/
sandbox_builder.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
17use hyperlight_host::func::HostFunction;
18use hyperlight_host::sandbox::SandboxConfiguration;
19use hyperlight_host::{GuestBinary, HyperlightError, Result, is_hypervisor_present};
20
21use super::proto_wasm_sandbox::ProtoWasmSandbox;
22
23// use large minimum scratch/heap/input data sizes
24// to deal with the size of wasmtime/wasi-libc aot artifacts
25pub const MIN_SCRATCH_SIZE: usize = 2 * 1024 * 1024;
26pub const MIN_INPUT_DATA_SIZE: usize = 192 * 1024;
27pub const MIN_HEAP_SIZE: u64 = 1024 * 1024;
28
29/// A builder for WasmSandbox
30#[derive(Clone)]
31pub struct SandboxBuilder {
32    config: SandboxConfiguration,
33    host_print_fn: Option<HostFunction<i32, (String,)>>,
34}
35
36impl SandboxBuilder {
37    /// Create a new SandboxBuilder
38    pub fn new() -> Self {
39        let mut config: SandboxConfiguration = Default::default();
40        config.set_input_data_size(MIN_INPUT_DATA_SIZE);
41        config.set_heap_size(MIN_HEAP_SIZE);
42        config.set_scratch_size(MIN_SCRATCH_SIZE);
43
44        Self {
45            config,
46            host_print_fn: None,
47        }
48    }
49
50    /// Enable debugging for the guest
51    /// This will allow the guest to be natively debugged using GDB or other debugging tools
52    ///
53    /// # Example:
54    /// ```rust
55    /// use hyperlight_wasm::SandboxBuilder;
56    /// let sandbox = SandboxBuilder::new()
57    ///    .with_debugging_enabled(8080) // Enable debugging on port 8080
58    ///    .build()
59    ///    .expect("Failed to build sandbox");
60    /// ```
61    /// # Note:
62    /// This feature is only available when the `gdb` feature is enabled.
63    /// If the `gdb` feature is not enabled, this method will have no effect.
64    #[cfg(gdb)]
65    pub fn with_debugging_enabled(mut self, port: u16) -> Self {
66        let debug_info = hyperlight_host::sandbox::config::DebugInfo { port };
67        self.config.set_guest_debug_info(debug_info);
68
69        self
70    }
71
72    /// Set the host print function
73    pub fn with_host_print_fn(
74        mut self,
75        host_print_fn: impl Into<HostFunction<i32, (String,)>>,
76    ) -> Self {
77        self.host_print_fn = Some(host_print_fn.into());
78        self
79    }
80
81    /// Set the guest output buffer size
82    pub fn with_guest_output_buffer_size(mut self, guest_output_buffer_size: usize) -> Self {
83        self.config.set_output_data_size(guest_output_buffer_size);
84        self
85    }
86
87    /// Set the guest input buffer size
88    /// This is the size of the buffer that the guest can write to
89    /// to send data to the host
90    /// The host can read from this buffer
91    /// The guest can write to this buffer
92    pub fn with_guest_input_buffer_size(mut self, guest_input_buffer_size: usize) -> Self {
93        if guest_input_buffer_size > MIN_INPUT_DATA_SIZE {
94            self.config.set_input_data_size(guest_input_buffer_size);
95        }
96        self
97    }
98
99    /// Set the guest scratch size in bytes.
100    /// The scratch region provides writable memory for the guest, including the
101    /// dynamically-sized stack. Increase this if your guest code needs deep
102    /// recursion or large local variables.
103    /// Values smaller than the default (288 KiB) are ignored.
104    pub fn with_guest_scratch_size(mut self, guest_scratch_size: usize) -> Self {
105        if guest_scratch_size > MIN_SCRATCH_SIZE {
106            self.config.set_scratch_size(guest_scratch_size);
107        }
108        self
109    }
110
111    /// Set the guest heap size
112    /// This is the size of the heap that code executing in the guest can use.
113    /// If this value is too small then the guest will fail, usually with a malloc failed error
114    /// The default (and minimum) value for this is set to the value of the MIN_HEAP_SIZE const.
115    pub fn with_guest_heap_size(mut self, guest_heap_size: u64) -> Self {
116        if guest_heap_size > MIN_HEAP_SIZE {
117            self.config.set_heap_size(guest_heap_size);
118        }
119        self
120    }
121
122    /// Enable or disable crashdump generation for the sandbox
123    /// When enabled, core dumps will be generated when the guest crashes
124    /// This requires the `crashdump` feature to be enabled
125    #[cfg(feature = "crashdump")]
126    pub fn with_crashdump_enabled(mut self, enabled: bool) -> Self {
127        self.config.set_guest_core_dump(enabled);
128        self
129    }
130
131    /// Build the ProtoWasmSandbox
132    pub fn build(self) -> Result<ProtoWasmSandbox> {
133        if !is_hypervisor_present() {
134            return Err(HyperlightError::NoHypervisorFound());
135        }
136
137        let guest_binary = GuestBinary::Buffer(super::WASM_RUNTIME.to_vec());
138
139        let mut proto_wasm_sandbox = ProtoWasmSandbox::new(Some(self.config), guest_binary)?;
140        if let Some(host_print_fn) = self.host_print_fn {
141            proto_wasm_sandbox.register_print(host_print_fn)?;
142        }
143        Ok(proto_wasm_sandbox)
144    }
145}
146
147impl Default for SandboxBuilder {
148    fn default() -> Self {
149        Self::new()
150    }
151}