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}