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