@@ -14,15 +14,18 @@ See the License for the specific language governing permissions and
14
14
limitations under the License.
15
15
*/
16
16
17
+ use std:: collections:: HashMap ;
17
18
use std:: fmt:: Debug ;
18
19
use std:: option:: Option ;
19
20
use std:: path:: Path ;
20
21
use std:: sync:: { Arc , Mutex } ;
22
+ #[ cfg( target_os = "linux" ) ]
23
+ use std:: time:: Duration ;
21
24
22
25
use log:: LevelFilter ;
23
26
use tracing:: { Span , instrument} ;
24
27
25
- use super :: host_funcs:: { FunctionRegistry , default_writer_func} ;
28
+ use super :: host_funcs:: { FunctionEntry , FunctionRegistry , default_writer_func} ;
26
29
use super :: mem_mgr:: MemMgrWrapper ;
27
30
use super :: uninitialized_evolve:: evolve_impl_multi_use;
28
31
use crate :: func:: host_functions:: { HostFunction , register_host_function} ;
@@ -34,6 +37,8 @@ use crate::mem::memory_region::{DEFAULT_GUEST_BLOB_MEM_FLAGS, MemoryRegionFlags}
34
37
use crate :: mem:: mgr:: { STACK_COOKIE_LEN , SandboxMemoryManager } ;
35
38
use crate :: mem:: shared_mem:: ExclusiveSharedMemory ;
36
39
use crate :: sandbox:: SandboxConfiguration ;
40
+ #[ cfg( gdb) ]
41
+ use crate :: sandbox:: config:: DebugInfo ;
37
42
use crate :: { MultiUseSandbox , Result , new_error} ;
38
43
39
44
#[ cfg( all( target_os = "linux" , feature = "seccomp" ) ) ]
@@ -69,6 +74,8 @@ pub(crate) struct SandboxRuntimeConfig {
69
74
/// host-implemented functions you need to be available to the guest, then
70
75
/// call `evolve` to transform your
71
76
/// `UninitializedSandbox` into an initialized `Sandbox`.
77
+ #[ doc( hidden) ]
78
+ //TODO: deprecate this #[deprecated(since = "0.8.0", note = "Deprecated in favour of Builder")]
72
79
pub struct UninitializedSandbox {
73
80
/// Registered host functions
74
81
pub ( crate ) host_funcs : Arc < Mutex < FunctionRegistry > > ,
@@ -81,6 +88,212 @@ pub struct UninitializedSandbox {
81
88
pub ( crate ) load_info : crate :: mem:: exe:: LoadInfo ,
82
89
}
83
90
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
+
84
297
impl Debug for UninitializedSandbox {
85
298
fn fmt ( & self , f : & mut std:: fmt:: Formatter < ' _ > ) -> std:: fmt:: Result {
86
299
f. debug_struct ( "UninitializedSandbox" )
0 commit comments