@@ -14,15 +14,18 @@ See the License for the specific language governing permissions and
1414limitations under the License.
1515*/
1616
17+ use std:: collections:: HashMap ;
1718use std:: fmt:: Debug ;
1819use std:: option:: Option ;
1920use std:: path:: Path ;
2021use std:: sync:: { Arc , Mutex } ;
22+ #[ cfg( target_os = "linux" ) ]
23+ use std:: time:: Duration ;
2124
2225use log:: LevelFilter ;
2326use tracing:: { Span , instrument} ;
2427
25- use super :: host_funcs:: { FunctionRegistry , default_writer_func} ;
28+ use super :: host_funcs:: { FunctionEntry , FunctionRegistry , default_writer_func} ;
2629use super :: mem_mgr:: MemMgrWrapper ;
2730use super :: uninitialized_evolve:: evolve_impl_multi_use;
2831use crate :: func:: host_functions:: { HostFunction , register_host_function} ;
@@ -34,6 +37,8 @@ use crate::mem::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionFlags}
3437use crate :: mem:: mgr:: { STACK_COOKIE_LEN , SandboxMemoryManager } ;
3538use crate :: mem:: shared_mem:: ExclusiveSharedMemory ;
3639use crate :: sandbox:: SandboxConfiguration ;
40+ #[ cfg( gdb) ]
41+ use crate :: sandbox:: config:: DebugInfo ;
3742use crate :: { MultiUseSandbox , Result , new_error} ;
3843
3944#[ cfg( all( target_os = "linux" , feature = "seccomp" ) ) ]
@@ -73,6 +78,8 @@ pub(crate) struct SandboxRuntimeConfig {
7378///
7479/// The virtual machine is not created until you call [`evolve`](Self::evolve) to transform
7580/// this into an initialized [`MultiUseSandbox`].
81+ #[ doc( hidden) ]
82+ //TODO: deprecate this #[deprecated(since = "0.8.0", note = "Deprecated in favour of Builder")]
7683pub struct UninitializedSandbox {
7784 /// Registered host functions
7885 pub ( crate ) host_funcs : Arc < Mutex < FunctionRegistry > > ,
@@ -85,6 +92,212 @@ pub struct UninitializedSandbox {
8592 pub ( crate ) load_info : crate :: mem:: exe:: LoadInfo ,
8693}
8794
95+ /// A builder for `Sandbox`.
96+ /// This builder allows you to configure the sandbox, and register host functions.
97+ #[ derive( Default ) ]
98+ pub struct Builder {
99+ config : SandboxConfiguration ,
100+ host_functions : HashMap < String , FunctionEntry > ,
101+ }
102+
103+ impl Builder {
104+ /// The default size of input data
105+ pub const DEFAULT_INPUT_SIZE : usize = SandboxConfiguration :: DEFAULT_INPUT_SIZE ;
106+ /// The minimum size of input data
107+ pub const MIN_INPUT_SIZE : usize = SandboxConfiguration :: MIN_INPUT_SIZE ;
108+ /// The default size of output data
109+ pub const DEFAULT_OUTPUT_SIZE : usize = SandboxConfiguration :: DEFAULT_OUTPUT_SIZE ;
110+ /// The minimum size of output data
111+ pub const MIN_OUTPUT_SIZE : usize = SandboxConfiguration :: MIN_OUTPUT_SIZE ;
112+ /// The default size of host function definitionsSET
113+ /// Host function definitions has its own page in memory, in order to be READ-ONLY
114+ /// from a guest's perspective.
115+ pub const DEFAULT_HOST_FUNCTION_DEFINITION_SIZE : usize =
116+ SandboxConfiguration :: DEFAULT_HOST_FUNCTION_DEFINITION_SIZE ;
117+ /// The minimum size of host function definitions
118+ pub const MIN_HOST_FUNCTION_DEFINITION_SIZE : usize =
119+ SandboxConfiguration :: MIN_HOST_FUNCTION_DEFINITION_SIZE ;
120+ /// The default interrupt retry delay
121+ #[ cfg( target_os = "linux" ) ]
122+ pub const DEFAULT_INTERRUPT_RETRY_DELAY : Duration =
123+ SandboxConfiguration :: DEFAULT_INTERRUPT_RETRY_DELAY ;
124+ /// The default signal offset from `SIGRTMIN` used to determine the signal number for interrupting
125+ #[ cfg( target_os = "linux" ) ]
126+ pub const INTERRUPT_VCPU_SIGRTMIN_OFFSET : u8 =
127+ SandboxConfiguration :: INTERRUPT_VCPU_SIGRTMIN_OFFSET ;
128+
129+ /// Set the size of the memory buffer that is made available for serialising host function definitions
130+ /// the minimum value is MIN_HOST_FUNCTION_DEFINITION_SIZE
131+ pub fn host_function_definition_size ( & mut self , bytes : usize ) -> & mut Self {
132+ self . config . set_host_function_definition_size ( bytes) ;
133+ self
134+ }
135+
136+ /// Set the size of the memory buffer that is made available for input to the guest
137+ /// the minimum value is MIN_INPUT_SIZE
138+ pub fn input_data_size ( & mut self , bytes : usize ) -> & mut Self {
139+ self . config . set_input_data_size ( bytes) ;
140+ self
141+ }
142+
143+ /// Set the size of the memory buffer that is made available for output from the guest
144+ /// the minimum value is MIN_OUTPUT_SIZE
145+ pub fn output_data_size ( & mut self , output_data_size : usize ) -> & mut Self {
146+ self . config . set_output_data_size ( output_data_size) ;
147+ self
148+ }
149+
150+ /// Set the stack size to use in the guest sandbox.
151+ /// If set to 0, the stack size will be determined from the PE file header
152+ pub fn stack_size ( & mut self , bytes : usize ) -> & mut Self {
153+ self . config . set_stack_size ( bytes as u64 ) ;
154+ self
155+ }
156+
157+ /// Set the heap size to use in the guest sandbox.
158+ /// If set to 0, the heap size will be determined from the PE file header
159+ pub fn heap_size ( & mut self , bytes : usize ) -> & mut Self {
160+ self . config . set_heap_size ( bytes as u64 ) ;
161+ self
162+ }
163+
164+ /// Sets the interrupt retry delay
165+ #[ cfg( target_os = "linux" ) ]
166+ pub fn interrupt_retry_delay ( & mut self , delay : Duration ) -> & mut Self {
167+ self . config . set_interrupt_retry_delay ( delay) ;
168+ self
169+ }
170+
171+ /// Sets the offset from `SIGRTMIN` to determine the real-time signal used for
172+ /// interrupting the VCPU thread.
173+ ///
174+ /// The final signal number is computed as `SIGRTMIN + offset`, and it must fall within
175+ /// the valid range of real-time signals supported by the host system.
176+ ///
177+ /// Returns an error if the offset exceeds the maximum real-time signal number.
178+ #[ cfg( target_os = "linux" ) ]
179+ pub fn interrupt_vcpu_sigrtmin_offset ( & mut self , offset : u8 ) -> Result < & mut Self > {
180+ self . config . set_interrupt_vcpu_sigrtmin_offset ( offset) ?;
181+ Ok ( self )
182+ }
183+
184+ /// Enables the guest core dump generation for a sandbox
185+ #[ cfg( crashdump) ]
186+ pub fn enable_core_dump ( & mut self ) -> & mut Self {
187+ self . config . set_guest_core_dump ( true ) ;
188+ self
189+ }
190+
191+ /// Sets the configuration for the guest debug
192+ #[ cfg( gdb) ]
193+ pub fn debug_info ( & mut self , debug_info : DebugInfo ) -> & mut Self {
194+ self . config . set_guest_debug_info ( debug_info) ;
195+ self
196+ }
197+
198+ /// Register a host function with the given name in the sandbox.
199+ pub fn register < Args : ParameterTuple , Output : SupportedReturnType > (
200+ & mut self ,
201+ name : impl AsRef < str > ,
202+ host_func : impl Into < HostFunction < Output , Args > > ,
203+ ) -> & mut Self {
204+ let name = name. as_ref ( ) . to_string ( ) ;
205+ let entry = FunctionEntry {
206+ function : host_func. into ( ) . into ( ) ,
207+ extra_allowed_syscalls : None ,
208+ parameter_types : Args :: TYPE ,
209+ return_type : Output :: TYPE ,
210+ } ;
211+ self . host_functions . insert ( name, entry) ;
212+ self
213+ }
214+
215+ /// Register the host function with the given name in the sandbox.
216+ /// Unlike `register`, this variant takes a list of extra syscalls that will
217+ /// allowed during the execution of the function handler.
218+ #[ cfg( all( feature = "seccomp" , target_os = "linux" ) ) ]
219+ pub fn register_with_syscalls < Args : ParameterTuple , Output : SupportedReturnType > (
220+ & mut self ,
221+ name : impl AsRef < str > ,
222+ host_func : impl Into < HostFunction < Output , Args > > ,
223+ extra_allowed_syscalls : impl IntoIterator < Item = crate :: sandbox:: ExtraAllowedSyscall > ,
224+ ) -> & mut Self {
225+ let name = name. as_ref ( ) . to_string ( ) ;
226+ let entry = FunctionEntry {
227+ function : host_func. into ( ) . into ( ) ,
228+ extra_allowed_syscalls : Some ( extra_allowed_syscalls. into_iter ( ) . collect ( ) ) ,
229+ parameter_types : Args :: TYPE ,
230+ return_type : Output :: TYPE ,
231+ } ;
232+ self . host_functions . insert ( name, entry) ;
233+ self
234+ }
235+
236+ /// Register a host function named "HostPrint" that will be called by the guest
237+ /// when it wants to print to the console.
238+ /// The "HostPrint" host function is kind of special, as we expect it to have the
239+ /// `FnMut(String) -> i32` signature.
240+ pub fn register_print (
241+ & mut self ,
242+ print_func : impl Into < HostFunction < i32 , ( String , ) > > ,
243+ ) -> & mut Self {
244+ #[ cfg( not( all( target_os = "linux" , feature = "seccomp" ) ) ) ]
245+ self . register ( "HostPrint" , print_func) ;
246+
247+ #[ cfg( all( target_os = "linux" , feature = "seccomp" ) ) ]
248+ self . register_with_syscalls (
249+ "HostPrint" ,
250+ print_func,
251+ EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC . iter ( ) . copied ( ) ,
252+ ) ;
253+
254+ self
255+ }
256+
257+ /// Register a host function named "HostPrint" that will be called by the guest
258+ /// when it wants to print to the console.
259+ /// The "HostPrint" host function is kind of special, as we expect it to have the
260+ /// `FnMut(String) -> i32` signature.
261+ /// Unlike `register_print`, this variant takes a list of extra syscalls that will
262+ /// allowed during the execution of the function handler.
263+ #[ cfg( all( target_os = "linux" , feature = "seccomp" ) ) ]
264+ pub fn register_print_with_syscalls (
265+ & mut self ,
266+ print_func : impl Into < HostFunction < i32 , ( String , ) > > ,
267+ extra_allowed_syscalls : impl IntoIterator < Item = crate :: sandbox:: ExtraAllowedSyscall > ,
268+ ) -> & mut Self {
269+ self . register_with_syscalls (
270+ "HostPrint" ,
271+ print_func,
272+ EXTRA_ALLOWED_SYSCALLS_FOR_WRITER_FUNC
273+ . iter ( )
274+ . copied ( )
275+ . chain ( extra_allowed_syscalls) ,
276+ )
277+ }
278+
279+ /// Build a new sandbox configured to run the binary specified by `env`.
280+ pub fn build < ' a , ' b > (
281+ & mut self ,
282+ env : impl Into < GuestEnvironment < ' a , ' b > > ,
283+ ) -> Result < MultiUseSandbox > {
284+ #![ allow( deprecated) ]
285+ let mut sandbox = UninitializedSandbox :: new ( env, Some ( self . config ) ) ?;
286+ #[ allow( clippy:: unwrap_used) ]
287+ // unwrap is ok since no other thread will be holding the lock at this point
288+ let mut host_functions = sandbox. host_funcs . try_lock ( ) . unwrap ( ) ;
289+ for ( name, entry) in self . host_functions . iter ( ) {
290+ host_functions. register_host_function (
291+ name. to_string ( ) ,
292+ entry. clone ( ) ,
293+ sandbox. mgr . unwrap_mgr_mut ( ) ,
294+ ) ?;
295+ }
296+ drop ( host_functions) ;
297+ sandbox. evolve ( )
298+ }
299+ }
300+
88301impl Debug for UninitializedSandbox {
89302 fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
90303 f. debug_struct ( "UninitializedSandbox" )
0 commit comments