hyperlight_host/sandbox/
config.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 std::cmp::{max, min};
18use std::time::Duration;
19
20use tracing::{instrument, Span};
21
22use crate::mem::exe::ExeInfo;
23
24/// Used for passing debug configuration to a sandbox
25#[cfg(gdb)]
26#[derive(Copy, Clone, Debug, Eq, PartialEq)]
27pub struct DebugInfo {
28    /// Guest debug port
29    pub port: u16,
30}
31
32/// The complete set of configuration needed to create a Sandbox
33#[derive(Copy, Clone, Debug, Eq, PartialEq)]
34#[repr(C)]
35pub struct SandboxConfiguration {
36    /// Guest gdb debug port
37    #[cfg(gdb)]
38    guest_debug_info: Option<DebugInfo>,
39    /// The maximum size of the guest error buffer.
40    guest_error_buffer_size: usize,
41    /// The size of the memory buffer that is made available for Guest Function
42    /// Definitions
43    host_function_definition_size: usize,
44    /// The size of the memory buffer that is made available for serialising
45    /// Host Exceptions
46    host_exception_size: usize,
47    /// The size of the memory buffer that is made available for input to the
48    /// Guest Binary
49    input_data_size: usize,
50    /// The size of the memory buffer that is made available for input to the
51    /// Guest Binary
52    output_data_size: usize,
53    /// The stack size to use in the guest sandbox. If set to 0, the stack
54    /// size will be determined from the PE file header.
55    ///
56    /// Note: this is a C-compatible struct, so even though this optional
57    /// field should be represented as an `Option`, that type is not
58    /// FFI-safe, so it cannot be.
59    stack_size_override: u64,
60    /// The heap size to use in the guest sandbox. If set to 0, the heap
61    /// size will be determined from the PE file header
62    ///
63    /// Note: this is a C-compatible struct, so even though this optional
64    /// field should be represented as an `Option`, that type is not
65    /// FFI-safe, so it cannot be.
66    heap_size_override: u64,
67    /// The kernel_stack_size to use in the guest sandbox. If set to 0, the default kernel stack size will be used.
68    /// The value will be increased to a multiple page size when memory is allocated if necessary.
69    ///
70    kernel_stack_size: usize,
71    /// The max_execution_time of a guest execution in milliseconds. If set to 0, the max_execution_time
72    /// will be set to the default value of 1000ms if the guest execution does not complete within the time specified
73    /// then the execution will be cancelled, the minimum value is 1ms
74    ///
75    /// Note: this is a C-compatible struct, so even though this optional
76    /// field should be represented as an `Option`, that type is not
77    /// FFI-safe, so it cannot be.
78    ///
79    max_execution_time: u16,
80    /// The max_wait_for_cancellation represents the maximum time the host should wait for a guest execution to be cancelled
81    /// If set to 0, the max_wait_for_cancellation will be set to the default value of 10ms.
82    /// The minimum value is 1ms.
83    ///
84    /// Note: this is a C-compatible struct, so even though this optional
85    /// field should be represented as an `Option`, that type is not
86    /// FFI-safe, so it cannot be.
87    max_wait_for_cancellation: u8,
88    // The max_initialization_time represents the maximum time the host should wait for a guest to initialize
89    // If set to 0, the max_initialization_time will be set to the default value of 2000ms.
90    // The minimum value is 1ms.
91    //
92    // Note: this is a C-compatible struct, so even though this optional
93    // field should be represented as an `Option`, that type is not
94    // FFI-safe, so it cannot be.
95    max_initialization_time: u16,
96    /// The size of the memory buffer that is made available for serializing
97    /// guest panic context
98    guest_panic_context_buffer_size: usize,
99}
100
101impl SandboxConfiguration {
102    /// The default size of input data
103    pub const DEFAULT_INPUT_SIZE: usize = 0x4000;
104    /// The minimum size of input data
105    pub const MIN_INPUT_SIZE: usize = 0x2000;
106    /// The default size of output data
107    pub const DEFAULT_OUTPUT_SIZE: usize = 0x4000;
108    /// The minimum size of output data
109    pub const MIN_OUTPUT_SIZE: usize = 0x2000;
110    /// The default size of host function definitions
111    /// Host function definitions has its own page in memory, in order to be READ-ONLY
112    /// from a guest's perspective.
113    pub const DEFAULT_HOST_FUNCTION_DEFINITION_SIZE: usize = 0x1000;
114    /// The minimum size of host function definitions
115    pub const MIN_HOST_FUNCTION_DEFINITION_SIZE: usize = 0x1000;
116    /// The default size for host exceptions
117    pub const DEFAULT_HOST_EXCEPTION_SIZE: usize = 0x4000;
118    /// The minimum size for host exceptions
119    pub const MIN_HOST_EXCEPTION_SIZE: usize = 0x4000;
120    /// The default size for guest error messages
121    pub const DEFAULT_GUEST_ERROR_BUFFER_SIZE: usize = 0x100;
122    /// The minimum size for guest error messages
123    pub const MIN_GUEST_ERROR_BUFFER_SIZE: usize = 0x80;
124    /// The default value for max initialization time (in milliseconds)
125    pub const DEFAULT_MAX_INITIALIZATION_TIME: u16 = 2000;
126    /// The minimum value for max initialization time (in milliseconds)
127    pub const MIN_MAX_INITIALIZATION_TIME: u16 = 1;
128    /// The maximum value for max initialization time (in milliseconds)
129    pub const MAX_MAX_INITIALIZATION_TIME: u16 = u16::MAX;
130    /// The default and minimum values for max execution time (in milliseconds)
131    pub const DEFAULT_MAX_EXECUTION_TIME: u16 = 1000;
132    /// The minimum value for max execution time (in milliseconds)
133    pub const MIN_MAX_EXECUTION_TIME: u16 = 1;
134    /// The maximum value for max execution time (in milliseconds)
135    pub const MAX_MAX_EXECUTION_TIME: u16 = u16::MAX;
136    /// The default and minimum values for max wait for cancellation (in milliseconds)
137    pub const DEFAULT_MAX_WAIT_FOR_CANCELLATION: u8 = 100;
138    /// The minimum value for max wait for cancellation (in milliseconds)
139    pub const MIN_MAX_WAIT_FOR_CANCELLATION: u8 = 10;
140    /// The maximum value for max wait for cancellation (in milliseconds)
141    pub const MAX_MAX_WAIT_FOR_CANCELLATION: u8 = u8::MAX;
142    /// The default and minimum values for guest panic context data
143    pub const DEFAULT_GUEST_PANIC_CONTEXT_BUFFER_SIZE: usize = 0x400;
144    /// The minimum value for guest panic context data
145    pub const MIN_GUEST_PANIC_CONTEXT_BUFFER_SIZE: usize = 0x400;
146    /// The minimum value for kernel stack size
147    pub const MIN_KERNEL_STACK_SIZE: usize = 0x1000;
148    /// The default value for kernel stack size
149    pub const DEFAULT_KERNEL_STACK_SIZE: usize = Self::MIN_KERNEL_STACK_SIZE;
150
151    #[allow(clippy::too_many_arguments)]
152    /// Create a new configuration for a sandbox with the given sizes.
153    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
154    fn new(
155        input_data_size: usize,
156        output_data_size: usize,
157        function_definition_size: usize,
158        host_exception_size: usize,
159        guest_error_buffer_size: usize,
160        stack_size_override: Option<u64>,
161        heap_size_override: Option<u64>,
162        kernel_stack_size: usize,
163        max_execution_time: Option<Duration>,
164        max_initialization_time: Option<Duration>,
165        max_wait_for_cancellation: Option<Duration>,
166        guest_panic_context_buffer_size: usize,
167        #[cfg(gdb)] guest_debug_info: Option<DebugInfo>,
168    ) -> Self {
169        Self {
170            input_data_size: max(input_data_size, Self::MIN_INPUT_SIZE),
171            output_data_size: max(output_data_size, Self::MIN_OUTPUT_SIZE),
172            host_function_definition_size: max(
173                function_definition_size,
174                Self::MIN_HOST_FUNCTION_DEFINITION_SIZE,
175            ),
176            host_exception_size: max(host_exception_size, Self::MIN_HOST_EXCEPTION_SIZE),
177            guest_error_buffer_size: max(
178                guest_error_buffer_size,
179                Self::MIN_GUEST_ERROR_BUFFER_SIZE,
180            ),
181            stack_size_override: stack_size_override.unwrap_or(0),
182            heap_size_override: heap_size_override.unwrap_or(0),
183            kernel_stack_size: max(kernel_stack_size, Self::MIN_KERNEL_STACK_SIZE),
184            max_execution_time: {
185                match max_execution_time {
186                    Some(max_execution_time) => match max_execution_time.as_millis() {
187                        0 => Self::DEFAULT_MAX_EXECUTION_TIME,
188                        1.. => min(
189                            Self::MAX_MAX_EXECUTION_TIME.into(),
190                            max(
191                                max_execution_time.as_millis(),
192                                Self::MIN_MAX_EXECUTION_TIME.into(),
193                            ),
194                        ) as u16,
195                    },
196                    None => Self::DEFAULT_MAX_EXECUTION_TIME,
197                }
198            },
199            max_wait_for_cancellation: {
200                match max_wait_for_cancellation {
201                    Some(max_wait_for_cancellation) => {
202                        match max_wait_for_cancellation.as_millis() {
203                            0 => Self::DEFAULT_MAX_WAIT_FOR_CANCELLATION,
204                            1.. => min(
205                                Self::MAX_MAX_WAIT_FOR_CANCELLATION.into(),
206                                max(
207                                    max_wait_for_cancellation.as_millis(),
208                                    Self::MIN_MAX_WAIT_FOR_CANCELLATION.into(),
209                                ),
210                            ) as u8,
211                        }
212                    }
213                    None => Self::DEFAULT_MAX_WAIT_FOR_CANCELLATION,
214                }
215            },
216            max_initialization_time: {
217                match max_initialization_time {
218                    Some(max_initialization_time) => match max_initialization_time.as_millis() {
219                        0 => Self::DEFAULT_MAX_INITIALIZATION_TIME,
220                        1.. => min(
221                            Self::MAX_MAX_INITIALIZATION_TIME.into(),
222                            max(
223                                max_initialization_time.as_millis(),
224                                Self::MIN_MAX_INITIALIZATION_TIME.into(),
225                            ),
226                        ) as u16,
227                    },
228                    None => Self::DEFAULT_MAX_INITIALIZATION_TIME,
229                }
230            },
231            guest_panic_context_buffer_size: max(
232                guest_panic_context_buffer_size,
233                Self::MIN_GUEST_PANIC_CONTEXT_BUFFER_SIZE,
234            ),
235            #[cfg(gdb)]
236            guest_debug_info,
237        }
238    }
239
240    /// Set the size of the memory buffer that is made available for input to the guest
241    /// the minimum value is MIN_INPUT_SIZE
242    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
243    pub fn set_input_data_size(&mut self, input_data_size: usize) {
244        self.input_data_size = max(input_data_size, Self::MIN_INPUT_SIZE);
245    }
246
247    /// Set the size of the memory buffer that is made available for output from the guest
248    /// the minimum value is MIN_OUTPUT_SIZE
249    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
250    pub fn set_output_data_size(&mut self, output_data_size: usize) {
251        self.output_data_size = max(output_data_size, Self::MIN_OUTPUT_SIZE);
252    }
253
254    /// Set the size of the memory buffer that is made available for serialising host function definitions
255    /// the minimum value is MIN_HOST_FUNCTION_DEFINITION_SIZE
256    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
257    pub fn set_host_function_definition_size(&mut self, host_function_definition_size: usize) {
258        self.host_function_definition_size = max(
259            host_function_definition_size,
260            Self::MIN_HOST_FUNCTION_DEFINITION_SIZE,
261        );
262    }
263
264    /// Set the size of the memory buffer that is made available for serialising host exceptions
265    /// the minimum value is MIN_HOST_EXCEPTION_SIZE
266    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
267    pub fn set_host_exception_size(&mut self, host_exception_size: usize) {
268        self.host_exception_size = max(host_exception_size, Self::MIN_HOST_EXCEPTION_SIZE);
269    }
270
271    /// Set the size of the memory buffer that is made available for serialising guest error messages
272    /// the minimum value is MIN_GUEST_ERROR_BUFFER_SIZE
273    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
274    pub fn set_guest_error_buffer_size(&mut self, guest_error_buffer_size: usize) {
275        self.guest_error_buffer_size =
276            max(guest_error_buffer_size, Self::MIN_GUEST_ERROR_BUFFER_SIZE);
277    }
278
279    /// Set the stack size to use in the guest sandbox. If set to 0, the stack size will be determined from the PE file header
280    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
281    pub fn set_stack_size(&mut self, stack_size: u64) {
282        self.stack_size_override = stack_size;
283    }
284
285    /// Set the heap size to use in the guest sandbox. If set to 0, the heap size will be determined from the PE file header
286    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
287    pub fn set_heap_size(&mut self, heap_size: u64) {
288        self.heap_size_override = heap_size;
289    }
290
291    /// Set the kernel stack size to use in the guest sandbox. If less than the minimum value of MIN_KERNEL_STACK_SIZE, the minimum value will be used.
292    /// If its not a multiple of the page size, it will be increased to the a multiple of the page size when memory is allocated.
293    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
294    pub fn set_kernel_stack_size(&mut self, kernel_stack_size: usize) {
295        self.kernel_stack_size = max(kernel_stack_size, Self::MIN_KERNEL_STACK_SIZE);
296    }
297
298    /// Set the maximum execution time of a guest function execution. If set to 0, the max_execution_time
299    /// will be set to the default value of DEFAULT_MAX_EXECUTION_TIME if the guest execution does not complete within the time specified
300    /// then the execution will be cancelled, the minimum value is MIN_MAX_EXECUTION_TIME
301    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
302    pub fn set_max_execution_time(&mut self, max_execution_time: Duration) {
303        match max_execution_time.as_millis() {
304            0 => self.max_execution_time = Self::DEFAULT_MAX_EXECUTION_TIME,
305            1.. => {
306                self.max_execution_time = min(
307                    Self::MAX_MAX_EXECUTION_TIME.into(),
308                    max(
309                        max_execution_time.as_millis(),
310                        Self::MIN_MAX_EXECUTION_TIME.into(),
311                    ),
312                ) as u16
313            }
314        }
315    }
316
317    /// Set the maximum time to wait for guest execution calculation. If set to 0, the maximum cancellation time
318    /// will be set to the default value of DEFAULT_MAX_WAIT_FOR_CANCELLATION if the guest execution cancellation does not complete within the time specified
319    /// then an error will be returned, the minimum value is MIN_MAX_WAIT_FOR_CANCELLATION
320    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
321    pub fn set_max_execution_cancel_wait_time(&mut self, max_wait_for_cancellation: Duration) {
322        match max_wait_for_cancellation.as_millis() {
323            0 => self.max_wait_for_cancellation = Self::DEFAULT_MAX_WAIT_FOR_CANCELLATION,
324            1.. => {
325                self.max_wait_for_cancellation = min(
326                    Self::MAX_MAX_WAIT_FOR_CANCELLATION.into(),
327                    max(
328                        max_wait_for_cancellation.as_millis(),
329                        Self::MIN_MAX_WAIT_FOR_CANCELLATION.into(),
330                    ),
331                ) as u8
332            }
333        }
334    }
335
336    /// Set the maximum time to wait for guest initialization. If set to 0, the maximum initialization time
337    /// will be set to the default value of DEFAULT_MAX_INITIALIZATION_TIME if the guest initialization does not complete within the time specified
338    /// then an error will be returned, the minimum value is MIN_MAX_INITIALIZATION_TIME
339    pub fn set_max_initialization_time(&mut self, max_initialization_time: Duration) {
340        match max_initialization_time.as_millis() {
341            0 => self.max_initialization_time = Self::DEFAULT_MAX_INITIALIZATION_TIME,
342            1.. => {
343                self.max_initialization_time = min(
344                    Self::MAX_MAX_INITIALIZATION_TIME.into(),
345                    max(
346                        max_initialization_time.as_millis(),
347                        Self::MIN_MAX_INITIALIZATION_TIME.into(),
348                    ),
349                ) as u16
350            }
351        }
352    }
353
354    /// Set the size of the memory buffer that is made available for serializing guest panic context
355    /// the minimum value is MIN_GUEST_PANIC_CONTEXT_BUFFER_SIZE
356    pub fn set_guest_panic_context_buffer_size(&mut self, guest_panic_context_buffer_size: usize) {
357        self.guest_panic_context_buffer_size = max(
358            guest_panic_context_buffer_size,
359            Self::MIN_GUEST_PANIC_CONTEXT_BUFFER_SIZE,
360        );
361    }
362
363    /// Sets the configuration for the guest debug
364    #[cfg(gdb)]
365    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
366    pub fn set_guest_debug_info(&mut self, debug_info: DebugInfo) {
367        self.guest_debug_info = Some(debug_info);
368    }
369
370    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
371    pub(crate) fn get_guest_error_buffer_size(&self) -> usize {
372        self.guest_error_buffer_size
373    }
374
375    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
376    pub(crate) fn get_host_function_definition_size(&self) -> usize {
377        self.host_function_definition_size
378    }
379
380    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
381    pub(crate) fn get_host_exception_size(&self) -> usize {
382        self.host_exception_size
383    }
384
385    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
386    pub(crate) fn get_input_data_size(&self) -> usize {
387        self.input_data_size
388    }
389
390    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
391    pub(crate) fn get_output_data_size(&self) -> usize {
392        self.output_data_size
393    }
394
395    #[instrument(skip_all, parent = Span::current(), level="Trace")]
396    pub(crate) fn get_guest_panic_context_buffer_size(&self) -> usize {
397        self.guest_panic_context_buffer_size
398    }
399
400    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
401    pub(crate) fn get_max_execution_time(&self) -> u16 {
402        self.max_execution_time
403    }
404
405    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
406    pub(crate) fn get_max_wait_for_cancellation(&self) -> u8 {
407        self.max_wait_for_cancellation
408    }
409
410    pub(crate) fn get_max_initialization_time(&self) -> u16 {
411        self.max_initialization_time
412    }
413
414    #[cfg(gdb)]
415    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
416    pub(crate) fn get_guest_debug_info(&self) -> Option<DebugInfo> {
417        self.guest_debug_info
418    }
419
420    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
421    fn stack_size_override_opt(&self) -> Option<u64> {
422        (self.stack_size_override > 0).then_some(self.stack_size_override)
423    }
424
425    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
426    fn heap_size_override_opt(&self) -> Option<u64> {
427        (self.heap_size_override > 0).then_some(self.heap_size_override)
428    }
429
430    /// If self.stack_size is non-zero, return it. Otherwise,
431    /// return exe_info.stack_reserve()
432    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
433    pub(crate) fn get_stack_size(&self, exe_info: &ExeInfo) -> u64 {
434        self.stack_size_override_opt()
435            .unwrap_or_else(|| exe_info.stack_reserve())
436    }
437
438    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
439    pub(crate) fn get_kernel_stack_size(&self) -> usize {
440        self.kernel_stack_size
441    }
442
443    /// If self.heap_size_override is non-zero, return it. Otherwise,
444    /// return exe_info.heap_reserve()
445    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
446    pub(crate) fn get_heap_size(&self, exe_info: &ExeInfo) -> u64 {
447        self.heap_size_override_opt()
448            .unwrap_or_else(|| exe_info.heap_reserve())
449    }
450}
451
452impl Default for SandboxConfiguration {
453    #[instrument(skip_all, parent = Span::current(), level= "Trace")]
454    fn default() -> Self {
455        Self::new(
456            Self::DEFAULT_INPUT_SIZE,
457            Self::DEFAULT_OUTPUT_SIZE,
458            Self::DEFAULT_HOST_FUNCTION_DEFINITION_SIZE,
459            Self::DEFAULT_HOST_EXCEPTION_SIZE,
460            Self::DEFAULT_GUEST_ERROR_BUFFER_SIZE,
461            None,
462            None,
463            Self::DEFAULT_KERNEL_STACK_SIZE,
464            None,
465            None,
466            None,
467            Self::DEFAULT_GUEST_PANIC_CONTEXT_BUFFER_SIZE,
468            #[cfg(gdb)]
469            None,
470        )
471    }
472}
473
474#[cfg(test)]
475mod tests {
476    use std::time::Duration;
477
478    use super::SandboxConfiguration;
479    use crate::testing::{callback_guest_exe_info, simple_guest_exe_info};
480
481    #[test]
482    fn overrides() {
483        const STACK_SIZE_OVERRIDE: u64 = 0x10000;
484        const HEAP_SIZE_OVERRIDE: u64 = 0x50000;
485        const INPUT_DATA_SIZE_OVERRIDE: usize = 0x4000;
486        const OUTPUT_DATA_SIZE_OVERRIDE: usize = 0x4001;
487        const HOST_FUNCTION_DEFINITION_SIZE_OVERRIDE: usize = 0x4002;
488        const HOST_EXCEPTION_SIZE_OVERRIDE: usize = 0x4003;
489        const GUEST_ERROR_BUFFER_SIZE_OVERRIDE: usize = 0x40004;
490        const MAX_EXECUTION_TIME_OVERRIDE: u16 = 1010;
491        const MAX_WAIT_FOR_CANCELLATION_OVERRIDE: u8 = 200;
492        const MAX_INITIALIZATION_TIME_OVERRIDE: u16 = 2000;
493        const GUEST_PANIC_CONTEXT_BUFFER_SIZE_OVERRIDE: usize = 0x4005;
494        const KERNEL_STACK_SIZE_OVERRIDE: usize = 0x4000;
495        let mut cfg = SandboxConfiguration::new(
496            INPUT_DATA_SIZE_OVERRIDE,
497            OUTPUT_DATA_SIZE_OVERRIDE,
498            HOST_FUNCTION_DEFINITION_SIZE_OVERRIDE,
499            HOST_EXCEPTION_SIZE_OVERRIDE,
500            GUEST_ERROR_BUFFER_SIZE_OVERRIDE,
501            Some(STACK_SIZE_OVERRIDE),
502            Some(HEAP_SIZE_OVERRIDE),
503            KERNEL_STACK_SIZE_OVERRIDE,
504            Some(Duration::from_millis(MAX_EXECUTION_TIME_OVERRIDE as u64)),
505            Some(Duration::from_millis(
506                MAX_INITIALIZATION_TIME_OVERRIDE as u64,
507            )),
508            Some(Duration::from_millis(
509                MAX_WAIT_FOR_CANCELLATION_OVERRIDE as u64,
510            )),
511            GUEST_PANIC_CONTEXT_BUFFER_SIZE_OVERRIDE,
512            #[cfg(gdb)]
513            None,
514        );
515        let exe_infos = vec![
516            simple_guest_exe_info().unwrap(),
517            callback_guest_exe_info().unwrap(),
518        ];
519        for exe_info in exe_infos {
520            let stack_size = cfg.get_stack_size(&exe_info);
521            let heap_size = cfg.get_heap_size(&exe_info);
522            assert_eq!(STACK_SIZE_OVERRIDE, stack_size);
523            assert_eq!(HEAP_SIZE_OVERRIDE, heap_size);
524        }
525        cfg.stack_size_override = 1024;
526        cfg.heap_size_override = 2048;
527        assert_eq!(1024, cfg.stack_size_override);
528        assert_eq!(2048, cfg.heap_size_override);
529        assert_eq!(16384, cfg.kernel_stack_size);
530        assert_eq!(INPUT_DATA_SIZE_OVERRIDE, cfg.input_data_size);
531        assert_eq!(OUTPUT_DATA_SIZE_OVERRIDE, cfg.output_data_size);
532        assert_eq!(
533            HOST_FUNCTION_DEFINITION_SIZE_OVERRIDE,
534            cfg.host_function_definition_size
535        );
536        assert_eq!(HOST_EXCEPTION_SIZE_OVERRIDE, cfg.host_exception_size);
537        assert_eq!(
538            GUEST_ERROR_BUFFER_SIZE_OVERRIDE,
539            cfg.guest_error_buffer_size
540        );
541        assert_eq!(MAX_EXECUTION_TIME_OVERRIDE, cfg.max_execution_time);
542        assert_eq!(
543            MAX_WAIT_FOR_CANCELLATION_OVERRIDE,
544            cfg.max_wait_for_cancellation
545        );
546        assert_eq!(
547            MAX_WAIT_FOR_CANCELLATION_OVERRIDE,
548            cfg.max_wait_for_cancellation
549        );
550        assert_eq!(
551            GUEST_PANIC_CONTEXT_BUFFER_SIZE_OVERRIDE,
552            cfg.guest_panic_context_buffer_size
553        );
554    }
555
556    #[test]
557    fn min_sizes() {
558        let mut cfg = SandboxConfiguration::new(
559            SandboxConfiguration::MIN_INPUT_SIZE - 1,
560            SandboxConfiguration::MIN_OUTPUT_SIZE - 1,
561            SandboxConfiguration::MIN_HOST_FUNCTION_DEFINITION_SIZE - 1,
562            SandboxConfiguration::MIN_HOST_EXCEPTION_SIZE - 1,
563            SandboxConfiguration::MIN_GUEST_ERROR_BUFFER_SIZE - 1,
564            None,
565            None,
566            SandboxConfiguration::MIN_KERNEL_STACK_SIZE - 1,
567            Some(Duration::from_millis(
568                SandboxConfiguration::MIN_MAX_EXECUTION_TIME as u64,
569            )),
570            Some(Duration::from_millis(
571                SandboxConfiguration::MIN_MAX_INITIALIZATION_TIME as u64,
572            )),
573            Some(Duration::from_millis(
574                SandboxConfiguration::MIN_MAX_WAIT_FOR_CANCELLATION as u64 - 1,
575            )),
576            SandboxConfiguration::MIN_GUEST_PANIC_CONTEXT_BUFFER_SIZE - 1,
577            #[cfg(gdb)]
578            None,
579        );
580        assert_eq!(SandboxConfiguration::MIN_INPUT_SIZE, cfg.input_data_size);
581        assert_eq!(SandboxConfiguration::MIN_OUTPUT_SIZE, cfg.output_data_size);
582        assert_eq!(
583            SandboxConfiguration::MIN_KERNEL_STACK_SIZE,
584            cfg.kernel_stack_size
585        );
586        assert_eq!(
587            SandboxConfiguration::MIN_HOST_FUNCTION_DEFINITION_SIZE,
588            cfg.host_function_definition_size
589        );
590        assert_eq!(
591            SandboxConfiguration::MIN_HOST_EXCEPTION_SIZE,
592            cfg.host_exception_size
593        );
594        assert_eq!(
595            SandboxConfiguration::MIN_GUEST_ERROR_BUFFER_SIZE,
596            cfg.guest_error_buffer_size
597        );
598        assert_eq!(0, cfg.stack_size_override);
599        assert_eq!(0, cfg.heap_size_override);
600        assert_eq!(
601            SandboxConfiguration::MIN_MAX_EXECUTION_TIME,
602            cfg.max_execution_time
603        );
604        assert_eq!(
605            SandboxConfiguration::MIN_MAX_WAIT_FOR_CANCELLATION,
606            cfg.max_wait_for_cancellation
607        );
608        assert_eq!(
609            SandboxConfiguration::MIN_GUEST_PANIC_CONTEXT_BUFFER_SIZE,
610            cfg.guest_panic_context_buffer_size
611        );
612        assert_eq!(
613            SandboxConfiguration::MIN_MAX_EXECUTION_TIME,
614            cfg.max_initialization_time
615        );
616
617        cfg.set_input_data_size(SandboxConfiguration::MIN_INPUT_SIZE - 1);
618        cfg.set_output_data_size(SandboxConfiguration::MIN_OUTPUT_SIZE - 1);
619        cfg.set_host_function_definition_size(
620            SandboxConfiguration::MIN_HOST_FUNCTION_DEFINITION_SIZE - 1,
621        );
622        cfg.set_host_exception_size(SandboxConfiguration::MIN_HOST_EXCEPTION_SIZE - 1);
623        cfg.set_guest_error_buffer_size(SandboxConfiguration::MIN_GUEST_ERROR_BUFFER_SIZE - 1);
624        cfg.set_max_execution_time(Duration::from_millis(
625            SandboxConfiguration::MIN_MAX_EXECUTION_TIME as u64,
626        ));
627        cfg.set_max_initialization_time(Duration::from_millis(
628            SandboxConfiguration::MIN_MAX_INITIALIZATION_TIME as u64 - 1,
629        ));
630        cfg.set_max_execution_cancel_wait_time(Duration::from_millis(
631            SandboxConfiguration::MIN_MAX_WAIT_FOR_CANCELLATION as u64 - 1,
632        ));
633        cfg.set_guest_panic_context_buffer_size(
634            SandboxConfiguration::MIN_GUEST_PANIC_CONTEXT_BUFFER_SIZE - 1,
635        );
636
637        assert_eq!(SandboxConfiguration::MIN_INPUT_SIZE, cfg.input_data_size);
638        assert_eq!(SandboxConfiguration::MIN_OUTPUT_SIZE, cfg.output_data_size);
639        assert_eq!(
640            SandboxConfiguration::MIN_HOST_FUNCTION_DEFINITION_SIZE,
641            cfg.host_function_definition_size
642        );
643        assert_eq!(
644            SandboxConfiguration::MIN_HOST_EXCEPTION_SIZE,
645            cfg.host_exception_size
646        );
647        assert_eq!(
648            SandboxConfiguration::MIN_GUEST_ERROR_BUFFER_SIZE,
649            cfg.guest_error_buffer_size
650        );
651        assert_eq!(
652            SandboxConfiguration::MIN_MAX_EXECUTION_TIME,
653            cfg.max_execution_time
654        );
655        assert_eq!(
656            SandboxConfiguration::MIN_MAX_WAIT_FOR_CANCELLATION,
657            cfg.max_wait_for_cancellation
658        );
659        assert_eq!(
660            SandboxConfiguration::MIN_GUEST_PANIC_CONTEXT_BUFFER_SIZE,
661            cfg.guest_panic_context_buffer_size
662        );
663    }
664
665    mod proptests {
666        use proptest::prelude::*;
667
668        use super::SandboxConfiguration;
669        #[cfg(gdb)]
670        use crate::sandbox::config::DebugInfo;
671
672        proptest! {
673            #[test]
674            fn error_buffer_size(size in SandboxConfiguration::MIN_GUEST_ERROR_BUFFER_SIZE..=SandboxConfiguration::MIN_GUEST_ERROR_BUFFER_SIZE * 10) {
675                let mut cfg = SandboxConfiguration::default();
676                cfg.set_guest_error_buffer_size(size);
677                prop_assert_eq!(size, cfg.get_guest_error_buffer_size());
678            }
679
680            #[test]
681            fn host_function_definition_size(size in SandboxConfiguration::MIN_HOST_FUNCTION_DEFINITION_SIZE..=SandboxConfiguration::MIN_HOST_FUNCTION_DEFINITION_SIZE * 10) {
682                let mut cfg = SandboxConfiguration::default();
683                cfg.set_host_function_definition_size(size);
684                prop_assert_eq!(size, cfg.get_host_function_definition_size());
685            }
686
687            #[test]
688            fn host_exception_size(size in SandboxConfiguration::MIN_HOST_EXCEPTION_SIZE..=SandboxConfiguration::MIN_HOST_EXCEPTION_SIZE * 10) {
689                let mut cfg = SandboxConfiguration::default();
690                cfg.set_host_exception_size(size);
691                prop_assert_eq!(size, cfg.get_host_exception_size());
692            }
693
694            #[test]
695            fn input_data_size(size in SandboxConfiguration::MIN_INPUT_SIZE..=SandboxConfiguration::MIN_INPUT_SIZE * 10) {
696                let mut cfg = SandboxConfiguration::default();
697                cfg.set_input_data_size(size);
698                prop_assert_eq!(size, cfg.get_input_data_size());
699            }
700
701            #[test]
702            fn output_data_size(size in SandboxConfiguration::MIN_OUTPUT_SIZE..=SandboxConfiguration::MIN_OUTPUT_SIZE * 10) {
703                let mut cfg = SandboxConfiguration::default();
704                cfg.set_output_data_size(size);
705                prop_assert_eq!(size, cfg.get_output_data_size());
706            }
707
708            #[test]
709            fn guest_panic_context_buffer_size(size in SandboxConfiguration::MIN_GUEST_PANIC_CONTEXT_BUFFER_SIZE..=SandboxConfiguration::MIN_GUEST_PANIC_CONTEXT_BUFFER_SIZE * 10) {
710                let mut cfg = SandboxConfiguration::default();
711                cfg.set_guest_panic_context_buffer_size(size);
712                prop_assert_eq!(size, cfg.get_guest_panic_context_buffer_size());
713            }
714
715            #[test]
716            fn max_execution_time(time in SandboxConfiguration::MIN_MAX_EXECUTION_TIME..=SandboxConfiguration::MIN_MAX_EXECUTION_TIME * 10) {
717                let mut cfg = SandboxConfiguration::default();
718                cfg.set_max_execution_time(std::time::Duration::from_millis(time.into()));
719                prop_assert_eq!(time, cfg.get_max_execution_time());
720            }
721
722            #[test]
723            fn max_wait_for_cancellation(time in SandboxConfiguration::MIN_MAX_WAIT_FOR_CANCELLATION..=SandboxConfiguration::MIN_MAX_WAIT_FOR_CANCELLATION * 10) {
724                let mut cfg = SandboxConfiguration::default();
725                cfg.set_max_execution_cancel_wait_time(std::time::Duration::from_millis(time.into()));
726                prop_assert_eq!(time, cfg.get_max_wait_for_cancellation());
727            }
728
729            #[test]
730            fn max_initialization_time(time in SandboxConfiguration::MIN_MAX_INITIALIZATION_TIME..=SandboxConfiguration::MIN_MAX_INITIALIZATION_TIME * 10) {
731                let mut cfg = SandboxConfiguration::default();
732                cfg.set_max_initialization_time(std::time::Duration::from_millis(time.into()));
733                prop_assert_eq!(time, cfg.get_max_initialization_time());
734            }
735
736            #[test]
737            fn stack_size_override(size in 0x1000..=0x10000u64) {
738                let mut cfg = SandboxConfiguration::default();
739                cfg.set_stack_size(size);
740                prop_assert_eq!(size, cfg.stack_size_override);
741            }
742
743            #[test]
744            fn heap_size_override(size in 0x1000..=0x10000u64) {
745                let mut cfg = SandboxConfiguration::default();
746                cfg.set_heap_size(size);
747                prop_assert_eq!(size, cfg.heap_size_override);
748            }
749
750            #[test]
751            #[cfg(gdb)]
752            fn guest_debug_info(port in 9000..=u16::MAX) {
753                let mut cfg = SandboxConfiguration::default();
754                let debug_info = DebugInfo { port };
755                cfg.set_guest_debug_info(debug_info);
756                prop_assert_eq!(debug_info, *cfg.get_guest_debug_info().as_ref().unwrap());
757            }
758        }
759    }
760}