diff --git a/Cargo.lock b/Cargo.lock index c3cb77dc0..c2992cdc2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -954,6 +954,7 @@ name = "litebox_runner_lvbs" version = "0.1.0" dependencies = [ "litebox", + "litebox_common_linux", "litebox_platform_lvbs", "litebox_platform_multiplex", "litebox_shim_optee", diff --git a/dev_tests/src/ratchet.rs b/dev_tests/src/ratchet.rs index 6252f8379..f7bad64a5 100644 --- a/dev_tests/src/ratchet.rs +++ b/dev_tests/src/ratchet.rs @@ -29,7 +29,7 @@ fn ratchet_globals() -> Result<()> { ("litebox/", 8), ("litebox_platform_linux_kernel/", 5), ("litebox_platform_linux_userland/", 5), - ("litebox_platform_lvbs/", 21), + ("litebox_platform_lvbs/", 22), ("litebox_platform_multiplex/", 1), ("litebox_platform_windows_userland/", 7), ("litebox_runner_linux_userland/", 1), diff --git a/litebox/src/lib.rs b/litebox/src/lib.rs index 1b64a0344..1b8030d23 100644 --- a/litebox/src/lib.rs +++ b/litebox/src/lib.rs @@ -24,6 +24,7 @@ pub mod platform; pub mod shim; pub mod sync; pub mod tls; +pub mod upcall; // The core [`LiteBox`] object itself, re-exported here publicly, just to keep management of the // code cleaner. diff --git a/litebox/src/upcall.rs b/litebox/src/upcall.rs new file mode 100644 index 000000000..cd2ee9785 --- /dev/null +++ b/litebox/src/upcall.rs @@ -0,0 +1,64 @@ +//! Upcall for platforms +//! +//! This module defines types and trait to provide upcalls for platforms. +//! A platform may receive some messages or requests from the host, devices, +//! or remote parties that it does not know how to handle. Rather than +//! making the platform be aware of all these messages or requests itself, +//! we implement upcalls to let platforms delegate handling of unknown +//! messages or requests to other layers of LiteBox (i.e., runner or shim). +//! Examples of such messages or requests include HVCI/Heki requests from +//! VTL0 and OP-TEE SMC calls from the normal world. +//! +//! # Security considerations +//! +//! Unlike other upcalls like hyperupcalls from the hypervisor to a guest VM, +//! this upcall is handled within LiteBox's TCB (i.e., by either runner or shim). +//! Therefore, the security considerations for this upcall are similar to function +//! calls within LiteBox. However, care must be taken to ensure that the upcall's +//! parameters and return values are properly validated and sanitized to prevent +//! potential security vulnerabilities. This is because the parameters might be +//! provided by untrusted sources and return values might contain sensitive +//! information. We assume that the upcall providers must implement necessary +//! security checks and validations. The platform would simply pass the parameters +//! and return values between untrusted sources and upcall providers (because it +//! does not have semantics to validate them). We can specify a function for early +//! validation at the platform side if needed but its advantages are not clear at +//! this moment (since there is no costly context switch within LiteBox). + +use thiserror::Error; + +/// An interface for upcalls from the platform to other layers of LiteBox. +pub trait Upcall { + /// The upcall parameter type to be passed from the platform. + type Parameter; + + /// The upcall return type to be returned to the platform. + type Return; + + /// Initialize the upcall handler. Must be called by the platform exactly once. + /// Per-thread initialization is possible but all threads must share the same + /// upcall handler. + fn init( + &self, + ) -> alloc::boxed::Box< + dyn crate::upcall::Upcall, + >; + + /// Execute the upcall with the given parameter. Since we do not expect that the + /// platform validates the parameters, the implementation of `execute` must validate + /// parameters to avoid potential security vulnerabilities. Also, it must sanitize + /// the return values before returning them to the platform. + fn execute(&self, ctx: &mut Self::Parameter) -> Result; +} + +/// The error type for upcalls +#[non_exhaustive] +#[derive(Error, Debug)] +pub enum UpcallError { + #[error("Upcall failed")] + Failure, + #[error("Upcall needs to be retried")] + Retry, + #[error("Upcall parameter is invalid")] + InvalidParameter, +} diff --git a/litebox_platform_lvbs/src/lib.rs b/litebox_platform_lvbs/src/lib.rs index 7498447da..b05278df3 100644 --- a/litebox_platform_lvbs/src/lib.rs +++ b/litebox_platform_lvbs/src/lib.rs @@ -389,6 +389,19 @@ impl LinuxKernel { ) { syscall_entry::init(shim); } + + /// Register the upcall. + pub fn register_upcall( + upcall: &'static ( + dyn litebox::upcall::Upcall< + Parameter = litebox_common_linux::PtRegs, + Return = litebox_common_linux::PtRegs, + > + Send + + Sync + ), + ) { + UPCALL.call_once(|| upcall); + } } impl RawMutexProvider for LinuxKernel { @@ -755,6 +768,17 @@ impl StdioProvider for LinuxKernel { } } +// Use static for upcall (we can use kernel TLS if needed) and `PtRegs` for now. +static UPCALL: spin::Once< + &'static ( + dyn litebox::upcall::Upcall< + Parameter = litebox_common_linux::PtRegs, + Return = litebox_common_linux::PtRegs, + > + Send + + Sync + ), +> = spin::Once::new(); + // NOTE: The below code is a naive workaround to let LVBS code to access the platform. // Rather than doing this, we should implement LVBS interface/provider for the platform. diff --git a/litebox_platform_lvbs/src/mshv/vsm_optee_smc.rs b/litebox_platform_lvbs/src/mshv/vsm_optee_smc.rs index 0ac94059b..c7158c717 100644 --- a/litebox_platform_lvbs/src/mshv/vsm_optee_smc.rs +++ b/litebox_platform_lvbs/src/mshv/vsm_optee_smc.rs @@ -18,7 +18,12 @@ pub(crate) fn optee_smc_dispatch(optee_smc_args_pfn: u64) -> i64 { with_per_cpu_variables_mut(|per_cpu_variables| { per_cpu_variables.save_extended_states(HV_VTL_SECURE); }); - // TODO: Implement OP-TEE SMC for TA command invocation here. + + // Placeholder for now + let upcall = crate::UPCALL.get().expect("OP-TEE upcall not registered"); + let mut ctx = litebox_common_linux::PtRegs::default(); + let _ = upcall.execute(&mut ctx); + debug_serial_println!("VSM function call for OP-TEE message"); with_per_cpu_variables_mut(|per_cpu_variables| { per_cpu_variables.restore_extended_states(HV_VTL_SECURE); diff --git a/litebox_runner_lvbs/Cargo.toml b/litebox_runner_lvbs/Cargo.toml index 30a916484..de1957b95 100644 --- a/litebox_runner_lvbs/Cargo.toml +++ b/litebox_runner_lvbs/Cargo.toml @@ -5,11 +5,11 @@ edition = "2024" [dependencies] litebox = { version = "0.1.0", path = "../litebox" } +litebox_common_linux = { path = "../litebox_common_linux/", version = "0.1.0" } litebox_platform_lvbs = { version = "0.1.0", path = "../litebox_platform_lvbs", default-features = false, features = ["interrupt"] } litebox_platform_multiplex = { version = "0.1.0", path = "../litebox_platform_multiplex", default-features = false, features = ["platform_lvbs"] } litebox_shim_optee = { path = "../litebox_shim_optee/", version = "0.1.0" } - [target.'cfg(target_arch = "x86_64")'.dependencies] x86_64 = { version = "0.15.2", default-features = false, features = ["instructions"] } diff --git a/litebox_runner_lvbs/src/lib.rs b/litebox_runner_lvbs/src/lib.rs index ca136b3f0..6fbd3e0dc 100644 --- a/litebox_runner_lvbs/src/lib.rs +++ b/litebox_runner_lvbs/src/lib.rs @@ -1,5 +1,7 @@ #![no_std] +extern crate alloc; + use core::panic::PanicInfo; use litebox_platform_lvbs::{ arch::{gdt, get_core_id, instrs::hlt_loop, interrupts}, @@ -91,6 +93,7 @@ pub fn init() -> Option<&'static Platform> { interrupts::init_idt(); x86_64::instructions::interrupts::enable(); Platform::register_shim(&litebox_shim_optee::OpteeShim); + Platform::register_upcall(&crate::OpteeMsgHandler); ret } @@ -99,6 +102,30 @@ pub fn run(platform: Option<&'static Platform>) -> ! { vtl_switch_loop_entry(platform) } +pub struct OpteeMsgHandler; +impl litebox::upcall::Upcall for OpteeMsgHandler { + type Parameter = litebox_common_linux::PtRegs; + type Return = litebox_common_linux::PtRegs; + + fn init( + &self, + ) -> alloc::boxed::Box< + dyn litebox::upcall::Upcall< + Parameter = litebox_common_linux::PtRegs, + Return = litebox_common_linux::PtRegs, + >, + > { + alloc::boxed::Box::new(OpteeMsgHandler {}) + } + + fn execute( + &self, + _ctx: &mut Self::Parameter, + ) -> Result { + todo!("invoke OP-TEE message handlers") + } +} + #[panic_handler] fn panic(info: &PanicInfo) -> ! { serial_println!("{}", info);