hyperlight_host/func/
host_functions.rs1use std::sync::{Arc, Mutex};
18
19use hyperlight_common::flatbuffer_wrappers::function_types::{ParameterValue, ReturnValue};
20
21use super::utils::for_each_tuple;
22use super::{ParameterTuple, ResultType, SupportedReturnType};
23use crate::sandbox::{ExtraAllowedSyscall, UninitializedSandbox};
24use crate::{log_then_return, new_error, Result};
25
26#[derive(Clone)]
29pub struct HostFunction<Output, Args>
30where
31 Args: ParameterTuple,
32 Output: SupportedReturnType,
33{
34 func: Arc<dyn Fn(Args) -> Result<Output> + Send + Sync + 'static>,
59}
60
61pub(crate) struct TypeErasedHostFunction {
62 func: Box<dyn Fn(Vec<ParameterValue>) -> Result<ReturnValue> + Send + Sync + 'static>,
63}
64
65impl<Args, Output> HostFunction<Output, Args>
66where
67 Args: ParameterTuple,
68 Output: SupportedReturnType,
69{
70 pub fn call(&self, args: Args) -> Result<Output> {
72 (self.func)(args)
73 }
74}
75
76impl TypeErasedHostFunction {
77 pub(crate) fn call(&self, args: Vec<ParameterValue>) -> Result<ReturnValue> {
78 (self.func)(args)
79 }
80}
81
82impl<Args, Output> From<HostFunction<Output, Args>> for TypeErasedHostFunction
83where
84 Args: ParameterTuple,
85 Output: SupportedReturnType,
86{
87 fn from(func: HostFunction<Output, Args>) -> TypeErasedHostFunction {
88 TypeErasedHostFunction {
89 func: Box::new(move |args: Vec<ParameterValue>| {
90 let args = Args::from_value(args)?;
91 Ok(func.call(args)?.into_value())
92 }),
93 }
94 }
95}
96
97macro_rules! impl_host_function {
98 ([$N:expr] ($($p:ident: $P:ident),*)) => {
99 impl<F, R, $($P),*> From<F> for HostFunction<R::ReturnType, ($($P,)*)>
107 where
108 F: FnMut($($P),*) -> R + Send + 'static,
109 ($($P,)*): ParameterTuple,
110 R: ResultType,
111 {
112 fn from(mut func: F) -> HostFunction<R::ReturnType, ($($P,)*)> {
113 let func = move |($($p,)*): ($($P,)*)| -> Result<R::ReturnType> {
114 func($($p),*).into_result()
115 };
116 let func = Mutex::new(func);
117 HostFunction {
118 func: Arc::new(move |args: ($($P,)*)| {
119 func.try_lock()
120 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
121 (args)
122 })
123 }
124 }
125 }
126 };
127}
128
129for_each_tuple!(impl_host_function);
130
131pub(crate) fn register_host_function<Args: ParameterTuple, Output: SupportedReturnType>(
132 func: impl Into<HostFunction<Output, Args>>,
133 sandbox: &mut UninitializedSandbox,
134 name: &str,
135 extra_allowed_syscalls: Option<Vec<ExtraAllowedSyscall>>,
136) -> Result<()> {
137 let func = func.into().into();
138
139 if let Some(_eas) = extra_allowed_syscalls {
140 if cfg!(all(feature = "seccomp", target_os = "linux")) {
141 #[cfg(all(feature = "seccomp", target_os = "linux"))]
143 {
144 sandbox
145 .host_funcs
146 .try_lock()
147 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
148 .register_host_function_with_syscalls(name.to_string(), func, _eas)?;
149 }
150 } else {
151 log_then_return!(
153 "Extra allowed syscalls are only supported on Linux with seccomp enabled"
154 );
155 }
156 } else {
157 sandbox
159 .host_funcs
160 .try_lock()
161 .map_err(|e| new_error!("Error locking at {}:{}: {}", file!(), line!(), e))?
162 .register_host_function(name.to_string(), func)?;
163 }
164
165 Ok(())
166}