Skip to main content

enclave_runner/
builder.rs

1/* Copyright (c) Fortanix, Inc.
2 *
3 * This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this
5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7use std::convert::TryInto;
8
9use crate::Command;
10use crate::platform::*;
11use crate::stream_router::{StreamRouter, OsStreamRouter};
12
13pub struct EnclaveBuilder<P: EnclavePlatform<T>, T: EnclaveType> {
14    platform: P,
15    stream_router: Option<Box<dyn StreamRouter + Send + Sync>>,
16    forward_panics: bool,
17    type_builder: T::ConfigurationBuilder,
18}
19
20impl<P: EnclavePlatform<T>, T: EnclaveType> EnclaveBuilder<P, T> {
21    pub fn new(platform: P) -> Self {
22        EnclaveBuilder {
23            platform,
24            stream_router: None,
25            forward_panics: false,
26            type_builder: Default::default(),
27        }
28    }
29
30    /// The stream router that this enclave should use when the enclave is
31    /// creating any streams. Defaults to [`OsStreamRouter`].
32    pub fn stream_router<R: Into<Box<dyn StreamRouter + Send + Sync>>>(&mut self, router: R) -> &mut Self {
33        self.stream_router = Some(router.into());
34        self
35    }
36
37    /// Whether to panic the runner if any enclave thread panics.
38    /// Defaults to `false`.
39    /// Note: If multiple enclaves are loaded, and an enclave with this set to
40    /// true panics, then all enclaves handled by this runner will exit because
41    /// the runner itself will panic.
42    pub fn forward_panics(&mut self, fp: bool) -> &mut Self {
43        self.forward_panics = fp;
44        self
45    }
46
47    pub fn build(self, loader: P::Loader) -> Result<T, anyhow::Error> {
48        let configuration = EnclaveConfiguration {
49            stream_router: self.stream_router.unwrap_or_else(|| OsStreamRouter::new()),
50            forward_panics: self.forward_panics,
51        };
52        self.platform.build(loader, configuration, self.type_builder.try_into()?)
53    }
54}
55
56impl<P: EnclavePlatform<Command>> EnclaveBuilder<P, Command> where {
57    /// Adds multiple arguments to pass to enclave's `fn main`.
58    /// **NOTE:** This is not an appropriate channel for passing secrets or
59    /// security configurations to the enclave.
60    pub fn args<I, S>(&mut self, args: I) -> &mut Self
61    where
62        I: IntoIterator<Item = S>,
63        S: AsRef<[u8]>,
64    {
65        let args = args.into_iter().map(|a| a.as_ref().to_owned());
66        self.type_builder.cmd_args.extend(args);
67        self
68    }
69
70    /// Adds an argument to pass to enclave's `fn main`.
71    /// **NOTE:** This is not an appropriate channel for passing secrets or
72    /// security configurations to the enclave.
73    pub fn arg<S: AsRef<[u8]>>(&mut self, arg: S) -> &mut Self {
74        let arg = arg.as_ref().to_owned();
75        self.type_builder.cmd_args.push(arg);
76        self
77    }
78
79    /// Sets the number of worker threads used to run the enclave.
80    pub fn num_worker_threads(&mut self, num_worker_threads: usize) -> &mut Self {
81        self.type_builder.num_worker_threads = Some(num_worker_threads);
82        self
83    }
84}
85
86#[cfg(test)]
87mod tests {
88    use super::*;
89    use test_case::test_case;
90
91    struct TestEnclaveBuilder(Vec<String>);
92
93    impl EnclavePlatform<Command> for TestEnclaveBuilder {
94        type Loader = ();
95
96        fn build(
97            self,
98            _loader: Self::Loader,
99            _configuration: EnclaveConfiguration,
100            cmd_configuration: CommandConfiguration,
101        ) -> Result<Command, anyhow::Error> {
102            let f = Box::new(move || {
103                let enclave_args = cmd_configuration
104                    .cmd_args
105                    .into_iter()
106                    .map(|arr| String::from_utf8(arr))
107                    .collect::<Result<Vec<_>, _>>()?;
108                assert_eq!(
109                    self.0, enclave_args,
110                    "{:?} differs from expected: {:?}",
111                    enclave_args, self.0
112                );
113                Ok(())
114            }) as Box<dyn FnOnce() -> _>;
115            Ok(f.into())
116        }
117    }
118
119    #[test_case(vec![]; "empty")]
120    #[test_case(vec!["--arg1".to_owned(), "--arg2".to_owned()]; "with args")]
121    fn test_enclave_args(args: Vec<String>) {
122        let mut expected = vec!["enclave".to_owned()];
123        expected.extend_from_slice(&args[..]);
124        let enclave_builder = TestEnclaveBuilder(expected);
125        let mut enclave_builder = EnclaveBuilder::new(enclave_builder);
126        enclave_builder.args(args);
127        enclave_builder.build(()).unwrap().run().unwrap();
128    }
129}