mirror of
https://github.com/AmbiML/sparrow-kata-full.git
synced 2025-09-18 16:36:43 +00:00
Add SecurityCoordinator skeleton.
- add SecurityCoordinator component (needs mailbox support, just a fake which should be enabled with a feature flag) - connect to ProcessManager & MlCoordinator - temproarily connect to DebugConsole to enable scecho test command - expand Bundle to hold application information (may need more elf) - connect ProcessManager::{install, uninstall} to SecurityCoordinator (no application binary yet, needs global page allocator) Notes: - SecurityCoordinator depends on camkes for thread synchronization - private heap is 8KB (and could possible be less; need to tune) - camkes interface connection uses seL4RPCOverMultiSharedData so ipc buffers are 4KB; the request & reply serde buffers are 2KB but could be near 4KB since they are used sequentially and the other params are a few bytes (but beware of camkes stack allocation) - the camkes SecurityCoordinator::request rpc is defined so that the request param has reasonable handling but the reply param requires a full copy (even if only partly used); haven't found a way to express the desired handling Change-Id: I686dc2d501e39bc8c27fe22db40657165a55b472 GitOrigin-RevId: db1536c241e28ddda1dc8f8da341b8c667ed6646
This commit is contained in:
@@ -55,6 +55,18 @@ DeclareCAmkESComponent(MlCoordinator
|
||||
INCLUDES interfaces
|
||||
)
|
||||
|
||||
RustAddLibrary(
|
||||
kata_security_coordinator
|
||||
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/components/SecurityCoordinator
|
||||
TARGET "riscv32imc-unknown-none-elf"
|
||||
LIB_FILENAME libkata_security_coordinator.a
|
||||
)
|
||||
|
||||
DeclareCAmkESComponent(SecurityCoordinator
|
||||
LIBS kata_security_coordinator
|
||||
INCLUDES interfaces
|
||||
)
|
||||
|
||||
DeclareCAmkESComponent(LogFibonacci
|
||||
SOURCES
|
||||
components/LogFibonacci/src/main.c
|
||||
|
@@ -2,6 +2,7 @@ import <LoggerInterface.camkes>;
|
||||
import <ProcessControlInterface.camkes>;
|
||||
import <PackageManagementInterface.camkes>;
|
||||
import <MlCoordinatorInterface.camkes>;
|
||||
import <SecurityCoordinatorInterface.camkes>;
|
||||
import <SeL4DebugInterface.camkes>;
|
||||
|
||||
component DebugConsole {
|
||||
@@ -18,6 +19,8 @@ component DebugConsole {
|
||||
provides LoggerInterface logger;
|
||||
uses ProcessControlInterface proc_ctrl;
|
||||
uses PackageManagementInterface pkg_mgmt;
|
||||
// TODO(sleffler): for debugging
|
||||
uses SecurityCoordinatorInterface security;
|
||||
uses SeL4DebugInterface sel4debug;
|
||||
uses MlCoordinatorInterface mlcoord;
|
||||
}
|
||||
|
@@ -9,5 +9,6 @@ cstr_core = "0.2"
|
||||
kata-io = { path = "../kata-io" }
|
||||
kata-line-reader = { path = "../kata-line-reader" }
|
||||
kata-proc-common = { path = "../../ProcessManager/kata-proc-common" }
|
||||
kata-security-common = { path = "../../SecurityCoordinator/kata-security-common" }
|
||||
log = "0.4"
|
||||
postcard = { version = "0.7", features = ["alloc"] }
|
||||
|
@@ -82,6 +82,7 @@ fn dispatch_command(cmdline: &str, output: &mut dyn io::Write) {
|
||||
"install" => install_command(&mut args, output),
|
||||
"loglevel" => loglevel_command(&mut args, output),
|
||||
"ps" => ps_command(),
|
||||
"scecho" => scecho_command(cmdline, output),
|
||||
"start" => start_command(&mut args, output),
|
||||
"stop" => stop_command(&mut args, output),
|
||||
"uninstall" => uninstall_command(&mut args, output),
|
||||
@@ -117,6 +118,33 @@ fn echo_command(cmdline: &str, output: &mut dyn io::Write) -> Result<(), Command
|
||||
}
|
||||
}
|
||||
|
||||
/// Implements an "scecho" command that sends arguments to the Security Core's echo service.
|
||||
fn scecho_command(cmdline: &str, output: &mut dyn io::Write) -> Result<(), CommandError> {
|
||||
use kata_security_common::*;
|
||||
let (_, request) = cmdline.split_at(7); // 'scecho'
|
||||
let reply = &mut [0u8; SECURITY_REPLY_DATA_SIZE];
|
||||
match unsafe {
|
||||
security_request(
|
||||
SecurityRequest::SrEcho,
|
||||
request.len() as u32,
|
||||
request.as_ptr(),
|
||||
reply as *mut _,
|
||||
)
|
||||
} {
|
||||
SecurityRequestError::SreSuccess => {
|
||||
writeln!(
|
||||
output,
|
||||
"{}",
|
||||
String::from_utf8_lossy(&reply[..request.len()])
|
||||
)?;
|
||||
}
|
||||
status => {
|
||||
writeln!(output, "ECHO replied {:?}", status)?;
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Set/display the max log level for the DebugConsole.
|
||||
fn loglevel_command(
|
||||
args: &mut dyn Iterator<Item = &str>,
|
||||
|
@@ -1,9 +1,11 @@
|
||||
import <LoggerInterface.camkes>;
|
||||
import <MlCoordinatorInterface.camkes>;
|
||||
import <SecurityCoordinatorInterface.camkes>;
|
||||
|
||||
component MlCoordinator {
|
||||
provides MlCoordinatorInterface mlcoord;
|
||||
|
||||
uses LoggerInterface logger;
|
||||
uses SecurityCoordinatorInterface security;
|
||||
uses VectorCoreInterface vctop;
|
||||
}
|
||||
|
@@ -4,6 +4,7 @@ import <LoggerInterface.camkes>;
|
||||
import <PackageManagementInterface.camkes>;
|
||||
import <ProcessControlInterface.camkes>;
|
||||
import <SeL4DebugInterface.camkes>;
|
||||
import <SecurityCoordinatorInterface.camkes>;
|
||||
|
||||
component ProcessManager {
|
||||
provides PackageManagementInterface pkg_mgmt;
|
||||
@@ -11,4 +12,5 @@ component ProcessManager {
|
||||
|
||||
uses LoggerInterface logger;
|
||||
uses SeL4DebugInterface sel4debug;
|
||||
uses SecurityCoordinatorInterface security;
|
||||
}
|
||||
|
@@ -4,4 +4,6 @@ version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
kata-security-common = { path = "../../SecurityCoordinator/kata-security-common" }
|
||||
postcard = { version = "0.7", features = ["alloc"] }
|
||||
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
|
||||
|
@@ -6,45 +6,68 @@ extern crate alloc;
|
||||
use alloc::string::String;
|
||||
use alloc::vec::Vec;
|
||||
use core::str;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub type BundleIdArray = Vec<String>;
|
||||
|
||||
// NB: struct's marked repr(C) are processed by cbindgen to get a .h file
|
||||
// used in camkes C interfaces.
|
||||
|
||||
// BundleId capcity before spillover to the heap.
|
||||
// TODO(sleffler): hide this; it's part of the implementation
|
||||
pub const DEFAULT_BUNDLE_ID_CAPACITY: usize = 64;
|
||||
|
||||
// Size of the data buffer used to pass BundleIdArray data between Rust <> C.
|
||||
// Size of the data buffer used to pass a serialized BundleIdArray between Rust <> C.
|
||||
// The data structure size is bounded by the camkes ipc buffer (120 bytes!)
|
||||
// and also by it being allocated on the stack of the rpc glue code.
|
||||
// So we need to balance these against being able to return all values.
|
||||
pub const RAW_BUNDLE_ID_DATA_SIZE: usize = 100;
|
||||
pub type RawBundleIdData = [u8; RAW_BUNDLE_ID_DATA_SIZE];
|
||||
|
||||
// TODO(sleffler): fill-in
|
||||
#[derive(Clone, Debug)]
|
||||
// BundleId capacity before spillover to the heap.
|
||||
// TODO(sleffler): hide this; it's part of the implementation
|
||||
pub const DEFAULT_BUNDLE_ID_CAPACITY: usize = 64;
|
||||
|
||||
mod ptr_helper {
|
||||
use super::*;
|
||||
use serde::{Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<T, S>(ptr: &*const T, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
(*ptr as usize).serialize(serializer)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<*const T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(usize::deserialize(deserializer)? as *const T)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Serialize, Deserialize)]
|
||||
pub struct Bundle {
|
||||
// NB: application & ML binaries use well-known paths relative to bundle_id
|
||||
// NB: ProcessManager owns loaded application's memory
|
||||
|
||||
// Bundle id extracted from manifest
|
||||
pub app_id: String,
|
||||
pub data: [u8; 64], // TODO(sleffler): placeholder
|
||||
|
||||
// Raw memory address of loaded application
|
||||
#[serde(with = "ptr_helper")]
|
||||
pub app_memory_address: *const u8,
|
||||
|
||||
// Size (bytes) of loaded application
|
||||
pub app_memory_size: u32,
|
||||
}
|
||||
impl Bundle {
|
||||
pub fn new() -> Self {
|
||||
Bundle {
|
||||
app_id: String::with_capacity(DEFAULT_BUNDLE_ID_CAPACITY),
|
||||
data: [0u8; 64],
|
||||
app_memory_address: 0 as *const u8,
|
||||
app_memory_size: 0u32,
|
||||
}
|
||||
}
|
||||
pub fn as_ptr(&self) -> *const u8 {
|
||||
self.data.as_ptr()
|
||||
}
|
||||
pub fn as_mut_ptr(&mut self) -> *mut u8 {
|
||||
self.data.as_mut_ptr()
|
||||
}
|
||||
}
|
||||
|
||||
// NB: struct's marked repr(C) are processed by cbindgen to get a .h file
|
||||
// used in camkes C interfaces.
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Copy, Clone, Debug, Eq, PartialEq)]
|
||||
pub enum ProcessManagerError {
|
||||
@@ -70,7 +93,7 @@ pub trait ProcessManagerInterface {
|
||||
&mut self,
|
||||
pkg_buffer: *const u8,
|
||||
pkg_buffer_size: u32,
|
||||
) -> Result<Bundle, ProcessManagerError>;
|
||||
) -> Result<String, ProcessManagerError>;
|
||||
fn uninstall(&mut self, bundle_id: &str) -> Result<(), ProcessManagerError>;
|
||||
fn start(&mut self, bundle: &Bundle) -> Result<(), ProcessManagerError>;
|
||||
fn stop(&mut self, bundle: &Bundle) -> Result<(), ProcessManagerError>;
|
||||
|
@@ -5,9 +5,10 @@ description = "Kata OS ProcessManager services"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
cstr_core = { version = "0.2.3", default-features = false, features = ["alloc"] }
|
||||
hashbrown = { version = "0.11", features = ["ahash-compile-time-rng"] }
|
||||
kata-proc-common = { path = "../kata-proc-common" }
|
||||
kata-security-common = { path = "../../SecurityCoordinator/kata-security-common" }
|
||||
log = "0.4"
|
||||
postcard = "0.7"
|
||||
smallstr = "0.2"
|
||||
spin = "0.9"
|
||||
|
@@ -3,9 +3,11 @@
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::string::{String, ToString};
|
||||
use kata_proc_common as proc;
|
||||
use proc::*;
|
||||
use alloc::string::String;
|
||||
use kata_proc_common::*;
|
||||
use kata_security_common::*;
|
||||
use log::trace;
|
||||
use postcard;
|
||||
use spin::Mutex;
|
||||
|
||||
mod proc_manager;
|
||||
@@ -77,48 +79,99 @@ impl ProcessManagerInterface for KataManagerInterface {
|
||||
fn install(
|
||||
&mut self,
|
||||
pkg_buffer: *const u8,
|
||||
_pkg_buffer_size: u32,
|
||||
) -> Result<Bundle, ProcessManagerError> {
|
||||
pkg_buffer_size: u32,
|
||||
) -> Result<String, ProcessManagerError> {
|
||||
// Package contains: application manifest, application binary, and
|
||||
// (optional) ML workload binary to run on vector core.
|
||||
// Manifest contains bundle_id.
|
||||
// Resulting flash file/pathname is fixed (1 app / bundle), only need bundle_id.
|
||||
// Store a generated "access key" (for Tock) for start ops; this is
|
||||
// "bound via capability badging to seL4 capabilities".
|
||||
let bundle = Bundle {
|
||||
// NB: temporarily fill-in app_id
|
||||
app_id: (pkg_buffer as usize).to_string(),
|
||||
data: [0u8; 64],
|
||||
};
|
||||
Ok(bundle)
|
||||
// Pass opaque package contents through; get back bundle_id.
|
||||
|
||||
// This is handled by the SecurityCoordinator.
|
||||
let reply = &mut [0u8; SECURITY_REPLY_DATA_SIZE];
|
||||
match unsafe {
|
||||
security_request(
|
||||
SecurityRequest::SrInstall,
|
||||
pkg_buffer_size,
|
||||
pkg_buffer,
|
||||
reply as *mut _,
|
||||
)
|
||||
} {
|
||||
SecurityRequestError::SreSuccess => {
|
||||
fn deserialize_failure(e: postcard::Error) -> ProcessManagerError {
|
||||
trace!("install failed: deserialize {:?}", e);
|
||||
ProcessManagerError::BundleDataInvalid
|
||||
}
|
||||
postcard::from_bytes::<String>(reply).map_err(deserialize_failure)
|
||||
}
|
||||
status => {
|
||||
trace!("install failed: {:?}", status);
|
||||
Err(ProcessManagerError::InstallFailed)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn uninstall(&mut self, _bundle_id: &str) -> Result<(), ProcessManagerError> {
|
||||
// This is handled with the StorageManager::Installer::uninstall.
|
||||
Ok(())
|
||||
fn uninstall(&mut self, bundle_id: &str) -> Result<(), ProcessManagerError> {
|
||||
fn serialize_failure(e: postcard::Error) -> ProcessManagerError {
|
||||
trace!("uninstall failed: serialize {:?}", e);
|
||||
ProcessManagerError::UninstallFailed
|
||||
}
|
||||
|
||||
// NB: the caller has already checked no running application exists
|
||||
// NB: the Security Core is assumed to invalidate/remove any kv store
|
||||
|
||||
// This is handled by the SecurityCoordinator.
|
||||
let mut request_data = [0u8; SECURITY_REQUEST_DATA_SIZE];
|
||||
let _ = postcard::to_slice(&bundle_id, &mut request_data).map_err(serialize_failure)?;
|
||||
let reply = &mut [0u8; SECURITY_REPLY_DATA_SIZE];
|
||||
match unsafe {
|
||||
security_request(
|
||||
SecurityRequest::SrUninstall,
|
||||
request_data.len() as u32,
|
||||
request_data.as_ptr(),
|
||||
reply as *mut _,
|
||||
)
|
||||
} {
|
||||
SecurityRequestError::SreSuccess => Ok(()),
|
||||
status => {
|
||||
trace!("uninstall failed: {:?}", status);
|
||||
Err(ProcessManagerError::UninstallFailed)
|
||||
}
|
||||
}
|
||||
}
|
||||
fn start(&mut self, _bundle: &Bundle) -> Result<(), ProcessManagerError> {
|
||||
// 1. Allocate shared memory for the program image
|
||||
// 2. Poke security core (via mailbox) to VerifyAndLoad data and load
|
||||
// into shared memory
|
||||
// 3. Security core responds (via mailbox) with success/failure &
|
||||
// mailbox handler sends interrupt
|
||||
// 4. Request completed with validated program in shared memory.
|
||||
// 5. On success allocate seL4 resources: VSpace, TCB & necessary
|
||||
// capabiltiies; setup application system context and start thread
|
||||
// (or should resources be allocated before Verify?).
|
||||
// TODO: set up access to StorageManager? (badge seL4 cap w/ bundle_id)
|
||||
// 1. Ask security core for application footprint with SizeBuffer
|
||||
// 2. Ask security core for manifest (maybe piggyback on SizeBuffer)
|
||||
// and parse for necessary info (e.g. whether kv Storage is
|
||||
// required, other privileges/capabilities)
|
||||
// 3. Ask MemoryManager for shared memory pages for the application
|
||||
// (model handled separately by MlCoordinator since we do not know
|
||||
// which model will be used)
|
||||
// 4. Allocate other seL4 resources:
|
||||
// - VSpace, TCB & necessary capabiltiies
|
||||
// 5. Ask security core to VerifyAndLoad app into shared memory pages
|
||||
// 6. Complete seL4 setup:
|
||||
// - Setup application system context and start thread
|
||||
// - Badge seL4 recv cap w/ bundle_id for (optional) StorageManager
|
||||
// access
|
||||
//
|
||||
// Applications with an ML workload use the MlCoordinator to request
|
||||
// data be loaded for the vector core.
|
||||
//
|
||||
// TBD where stuff normally in ELF headers comes from (e.g. starting pc,
|
||||
// text size for marking pages executable, bss size).
|
||||
//
|
||||
// May want stack size parameterized.
|
||||
//
|
||||
// Applications with an ML workload use the MLCoordinator to request
|
||||
// data be written to the vector core.
|
||||
// TODO(sleffler): fill-in
|
||||
// Err(ProcessManagerError::StartFailed)
|
||||
Ok(())
|
||||
}
|
||||
fn stop(&mut self, _bundle: &Bundle) -> Result<(), ProcessManagerError> {
|
||||
// 1. If thread is running, notify application so it can do cleanup;
|
||||
// e.g. ask the MLCoordinator to stop any ML workloads
|
||||
// 2. If thread notified, wait some period of time for ack.
|
||||
// 3. If thread is running, stop thread.
|
||||
// 0. Assume thread is running (caller verifies)
|
||||
// 1. Notify application so it can do cleanup; e.g. ask the
|
||||
// MLCoordinator to stop any ML workloads
|
||||
// 2. Wait some period of time for an ack from application
|
||||
// 3. Stop thread
|
||||
// 4. Reclaim seL4 resources: TCB, VSpace, memory, capabilities, etc.
|
||||
// TODO(sleffler): fill-in
|
||||
// Err(ProcessManagerError::StopFailed)
|
||||
|
@@ -6,6 +6,7 @@ use alloc::string::String;
|
||||
use core::convert::TryFrom;
|
||||
use core::marker::Sync;
|
||||
use hashbrown::HashMap;
|
||||
use kata_proc_common::{Bundle, DEFAULT_BUNDLE_ID_CAPACITY};
|
||||
use log::trace;
|
||||
use smallstr::SmallString;
|
||||
|
||||
@@ -81,21 +82,23 @@ impl PackageManagementInterface for ProcessManager {
|
||||
|
||||
// We assume the seL4 capability for the memory associated with
|
||||
// pkg_buffer has been setup for us so we can pass it along (as needed)
|
||||
// to the StorageManager.
|
||||
// to the Security Core.
|
||||
//
|
||||
// NB: defer to StorageManager for handling an install of a previously
|
||||
// installed app. We do not have the app_id to check locally so if the
|
||||
// StorageManager disallows re-install then we'll return it's error;
|
||||
// otherwise we update the returned Bundle state.
|
||||
// TODO(sleffler): owner's public key?
|
||||
let bundle = self.manager.install(pkg_buffer, pkg_buffer_size)?;
|
||||
let bundle_id = self.manager.install(pkg_buffer, pkg_buffer_size)?;
|
||||
trace!(
|
||||
"install pkg {:p}:{} => bundle_id:{}",
|
||||
pkg_buffer,
|
||||
pkg_buffer_size,
|
||||
&bundle.app_id
|
||||
bundle_id
|
||||
);
|
||||
|
||||
let mut bundle = Bundle::new();
|
||||
bundle.app_id = bundle_id;
|
||||
assert!(self
|
||||
.bundles
|
||||
.insert(BundleId::from_str(&bundle.app_id), BundleData::new(&bundle))
|
||||
@@ -315,6 +318,4 @@ mod tests {
|
||||
let running = mgr.get_running_bundles().unwrap();
|
||||
assert_eq!(running.len(), 0);
|
||||
}
|
||||
|
||||
// TODO(sleffler): check uninstall stops a running thread
|
||||
}
|
||||
|
23
apps/system/components/SecurityCoordinator/Cargo.toml
Normal file
23
apps/system/components/SecurityCoordinator/Cargo.toml
Normal file
@@ -0,0 +1,23 @@
|
||||
[workspace]
|
||||
|
||||
members = [
|
||||
"kata-security-common",
|
||||
"kata-security-component",
|
||||
"kata-security-coordinator",
|
||||
]
|
||||
|
||||
[profile.dev]
|
||||
opt-level = 0
|
||||
debug = true
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
|
||||
[profile.release]
|
||||
opt-level = "z"
|
||||
lto = "fat"
|
||||
codegen-units = 1
|
||||
split-debuginfo = "unpacked"
|
||||
|
||||
[profile.release.build-override]
|
||||
opt-level = "z"
|
||||
codegen-units = 1
|
@@ -0,0 +1,10 @@
|
||||
// Kata OS SecurityCoordinator services.
|
||||
|
||||
import <LoggerInterface.camkes>;
|
||||
import <SecurityCoordinatorInterface.camkes>;
|
||||
|
||||
component SecurityCoordinator {
|
||||
provides SecurityCoordinatorInterface security;
|
||||
|
||||
uses LoggerInterface logger;
|
||||
}
|
7
apps/system/components/SecurityCoordinator/cbindgen.toml
Normal file
7
apps/system/components/SecurityCoordinator/cbindgen.toml
Normal file
@@ -0,0 +1,7 @@
|
||||
language = "C"
|
||||
include_guard = "__SECURITY_COORDINATOR_BINDINGS_H__"
|
||||
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
|
||||
no_includes = true
|
||||
|
||||
[export]
|
||||
include = ["SecurityRequestData", "SecurityReplyData", "SecurityRequest", "SecurityRequestError"]
|
@@ -0,0 +1,8 @@
|
||||
[package]
|
||||
name = "kata-security-common"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] }
|
||||
serde-big-array = "0.3"
|
@@ -0,0 +1,174 @@
|
||||
//! Kata OS Security Coordinator support
|
||||
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::string::String;
|
||||
use core::str;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// NB: serde helper for arrays w/ >32 elements
|
||||
// c.f. https://github.com/serde-rs/serde/pull/1860
|
||||
use serde_big_array::big_array;
|
||||
big_array! { BigArray; }
|
||||
|
||||
// Size of the buffers used to pass serialized data between Rust <> C.
|
||||
// The data structure size is bounded by the camkes ipc buffer (2K bytes!)
|
||||
// and also by it being allocated on the stack of the rpc glue code.
|
||||
// So we need to balance these against being able to handle all values.
|
||||
|
||||
pub const SECURITY_REQUEST_DATA_SIZE: usize = 2048;
|
||||
pub type SecurityRequestData = [u8; SECURITY_REQUEST_DATA_SIZE];
|
||||
|
||||
pub const SECURITY_REPLY_DATA_SIZE: usize = 2048;
|
||||
pub type SecurityReplyData = [u8; SECURITY_REPLY_DATA_SIZE];
|
||||
|
||||
// NB: struct's marked repr(C) are processed by cbindgen to get a .h file
|
||||
// used in camkes C interfaces.
|
||||
|
||||
mod mut_ptr_helper {
|
||||
use super::*;
|
||||
use serde::{Deserializer, Serializer};
|
||||
|
||||
pub fn serialize<T, S>(ptr: &*mut T, serializer: S) -> Result<S::Ok, S::Error>
|
||||
where
|
||||
S: Serializer,
|
||||
{
|
||||
(*ptr as usize).serialize(serializer)
|
||||
}
|
||||
|
||||
pub fn deserialize<'de, T, D>(deserializer: D) -> Result<*mut T, D::Error>
|
||||
where
|
||||
D: Deserializer<'de>,
|
||||
{
|
||||
Ok(usize::deserialize(deserializer)? as *mut T)
|
||||
}
|
||||
}
|
||||
|
||||
// NB: SecurityRequestInstall is handled specially.
|
||||
|
||||
// SecurityRequestUninstall
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct UninstallRequest {
|
||||
pub bundle_id: String,
|
||||
}
|
||||
|
||||
// SecurityRequestSizeBuffer
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct SizeBufferRequest {
|
||||
pub bundle_id: String,
|
||||
}
|
||||
|
||||
// SecurityRequestGetManifest
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct GetManifestRequest {
|
||||
pub bundle_id: String,
|
||||
}
|
||||
|
||||
// SecurityRequestLoadApplication
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct LoadApplicationRequest {
|
||||
pub bundle_id: String,
|
||||
|
||||
// Scatter-list of shared memory pages where application should be loaded.
|
||||
// TODO(sleffler) scatter list
|
||||
#[serde(with = "mut_ptr_helper")]
|
||||
pub app_binary: *mut u8,
|
||||
}
|
||||
|
||||
// SecurityRequestLoadModel
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct LoadModelRequest {
|
||||
pub bundle_id: String,
|
||||
pub model_id: String,
|
||||
|
||||
// Scatter-list of shared memory pages where model should be loaded.
|
||||
// TODO(sleffler) scatter list
|
||||
#[serde(with = "mut_ptr_helper")]
|
||||
pub model_binary: *mut u8,
|
||||
}
|
||||
|
||||
// SecurityRequestReadKey
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct ReadKeyRequest {
|
||||
pub bundle_id: String,
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
// SecurityRequestWriteKey
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct WriteKeyRequest<'a> {
|
||||
pub bundle_id: String,
|
||||
pub key: String,
|
||||
pub value: &'a [u8],
|
||||
}
|
||||
|
||||
// SecurityRequestDeleteKey
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub struct DeleteKeyRequest {
|
||||
pub bundle_id: String,
|
||||
pub key: String,
|
||||
}
|
||||
|
||||
// NB: this is the union of InstallInterface & StorageInterface because
|
||||
// the camkes-generated interface code uses basic C which does not
|
||||
// tolerate overlapping member names.
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum SecurityRequestError {
|
||||
SreSuccess = 0,
|
||||
SreBundleIdInvalid,
|
||||
SreBundleDataInvalid,
|
||||
SreBundleNotFound,
|
||||
SreKeyNotFound,
|
||||
SrePackageBufferLenInvalid,
|
||||
SreValueInvalid,
|
||||
SreKeyInvalid,
|
||||
// Generic errors, mostly used in unit tests
|
||||
SreInstallFailed,
|
||||
SreUninstallFailed,
|
||||
SreReadFailed,
|
||||
SreWriteFailed,
|
||||
SreDeleteFailed,
|
||||
}
|
||||
|
||||
#[repr(C)]
|
||||
#[derive(Debug, Eq, PartialEq)]
|
||||
pub enum SecurityRequest {
|
||||
SrEcho = 0, // Security core replies with request payload
|
||||
|
||||
SrInstall, // Install package [pkg_buffer] -> bundle_id
|
||||
SrUninstall, // Uninstall package [bundle_id]
|
||||
|
||||
SrSizeBuffer, // Size application image [bundle_id] -> u32
|
||||
SrGetManifest, // Return application manifest [bundle_id] -> String
|
||||
SrLoadApplication, // Load application [bundle_id]
|
||||
// TODO(sleffler): define <tag>?
|
||||
SrLoadModel, // Load ML model [bundle_id, <tag>]
|
||||
|
||||
SrReadKey, // Read key value [bundle_id, key] -> value
|
||||
SrWriteKey, // Write key value [bundle_id, key, value]
|
||||
SrDeleteKey, // Delete key [bundle_id, key]
|
||||
}
|
||||
|
||||
// Interface to underlying facilities; also used to inject fakes for unit tests.
|
||||
pub trait SecurityCoordinatorInterface {
|
||||
fn request(
|
||||
&mut self,
|
||||
request_id: SecurityRequest,
|
||||
request_buffer: &[u8],
|
||||
reply_buffer: &mut [u8],
|
||||
) -> Result<(), SecurityRequestError>;
|
||||
}
|
||||
|
||||
// Camkes-generated rpc api.
|
||||
// NB: this requires the SecurityCoordinator component be named "security".
|
||||
#[allow(dead_code)]
|
||||
extern "C" {
|
||||
pub fn security_request(
|
||||
c_request: SecurityRequest,
|
||||
c_request_buffer_len: u32,
|
||||
c_request_buffer: *const u8,
|
||||
c_reply_buffer: *mut SecurityReplyData,
|
||||
) -> SecurityRequestError;
|
||||
}
|
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "kata-security-component"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
kata-allocator = { path = "../../DebugConsole/kata-allocator" }
|
||||
kata-logger = { path = "../../DebugConsole/kata-logger" }
|
||||
kata-panic = { path = "../../DebugConsole/kata-panic" }
|
||||
kata-security-common = { path = "../kata-security-common" }
|
||||
kata-security-coordinator = { path = "../kata-security-coordinator" }
|
||||
log = "0.4"
|
||||
|
||||
[lib]
|
||||
name = "kata_security_coordinator"
|
||||
path = "src/run.rs"
|
||||
crate-type = ["staticlib"]
|
@@ -0,0 +1,55 @@
|
||||
//! Kata OS Security Coordinator component support.
|
||||
|
||||
// Code here binds the camkes component to the rust code.
|
||||
#![no_std]
|
||||
|
||||
use core::slice;
|
||||
use kata_allocator;
|
||||
use kata_logger::KataLogger;
|
||||
extern crate kata_panic;
|
||||
use kata_security_common::*;
|
||||
use kata_security_coordinator::KATA_SECURITY;
|
||||
use log::trace;
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn pre_init() {
|
||||
static KATA_LOGGER: KataLogger = KataLogger;
|
||||
log::set_logger(&KATA_LOGGER).unwrap();
|
||||
// NB: set to max; the LoggerInterface will filter
|
||||
log::set_max_level(log::LevelFilter::Trace);
|
||||
|
||||
// TODO(sleffler): temp until we integrate with seL4
|
||||
// TODO(sleffler): should be used rarely
|
||||
static mut HEAP_MEMORY: [u8; 8 * 1024] = [0; 8 * 1024];
|
||||
unsafe {
|
||||
kata_allocator::ALLOCATOR.init(HEAP_MEMORY.as_mut_ptr() as usize, HEAP_MEMORY.len());
|
||||
trace!(
|
||||
"setup heap: start_addr {:p} size {}",
|
||||
HEAP_MEMORY.as_ptr(),
|
||||
HEAP_MEMORY.len()
|
||||
);
|
||||
}
|
||||
|
||||
// Complete KATA_SECURITY setup. This is as early as we can do it given that
|
||||
// it needs the GlobalAllocator.
|
||||
unsafe {
|
||||
KATA_SECURITY.init();
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern "C" fn security_request(
|
||||
c_request: SecurityRequest,
|
||||
c_request_buffer_len: u32,
|
||||
c_request_buffer: *const u8,
|
||||
c_reply_buffer: *mut SecurityReplyData,
|
||||
) -> SecurityRequestError {
|
||||
unsafe {
|
||||
KATA_SECURITY.request(
|
||||
c_request,
|
||||
slice::from_raw_parts(c_request_buffer, c_request_buffer_len as usize),
|
||||
&mut (*c_reply_buffer)[..],
|
||||
)
|
||||
}
|
||||
.map_or_else(|e| e, |_v| SecurityRequestError::SreSuccess)
|
||||
}
|
@@ -0,0 +1,9 @@
|
||||
[package]
|
||||
name = "kata-security-coordinator"
|
||||
version = "0.1.0"
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
kata-security-common = { path = "../kata-security-common" }
|
||||
log = "0.4"
|
||||
postcard = "0.7"
|
@@ -0,0 +1,150 @@
|
||||
//! Kata OS security coordinator support
|
||||
|
||||
#![cfg_attr(not(test), no_std)]
|
||||
// NB: "error[E0658]: trait bounds other than `Sized` on const fn parameters are unstable"
|
||||
#![feature(const_fn_trait_bound)]
|
||||
|
||||
extern crate alloc;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::ToString;
|
||||
use kata_security_common::*;
|
||||
use log::trace;
|
||||
use postcard;
|
||||
|
||||
#[cfg(not(test))]
|
||||
pub static mut KATA_SECURITY: KataSecurityCoordinator = KataSecurityCoordinator::empty();
|
||||
|
||||
// KataSecurityCoordinator bundles an instance of the SecurityCoordinator that operates
|
||||
// on KataOS interfaces. There is a two-step dance to setup an instance because we want
|
||||
// KATA_STORAGE static.
|
||||
// NB: no locking is done; we assume the caller/user is single-threaded
|
||||
pub struct KataSecurityCoordinator {
|
||||
manager: Option<Box<dyn SecurityCoordinatorInterface + Sync>>,
|
||||
// TODO(sleffler): mailbox ipc state
|
||||
}
|
||||
impl KataSecurityCoordinator {
|
||||
// Constructs a partially-initialized instance; to complete call init().
|
||||
// This is needed because we need a const fn for static setup.
|
||||
const fn empty() -> KataSecurityCoordinator {
|
||||
KataSecurityCoordinator { manager: None }
|
||||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
self.manager = Some(Box::new(KataSecurityCoordinatorInterface));
|
||||
}
|
||||
}
|
||||
impl SecurityCoordinatorInterface for KataSecurityCoordinator {
|
||||
fn request(
|
||||
&mut self,
|
||||
request_id: SecurityRequest,
|
||||
request_buffer: &[u8],
|
||||
reply_buffer: &mut [u8],
|
||||
) -> Result<(), SecurityRequestError> {
|
||||
self.manager
|
||||
.as_mut()
|
||||
.unwrap()
|
||||
.request(request_id, request_buffer, reply_buffer)
|
||||
}
|
||||
}
|
||||
|
||||
struct KataSecurityCoordinatorInterface;
|
||||
// TODO(sleffler): move this to a feature-controlled fake
|
||||
impl SecurityCoordinatorInterface for KataSecurityCoordinatorInterface {
|
||||
fn request(
|
||||
&mut self,
|
||||
request_id: SecurityRequest,
|
||||
request_buffer: &[u8],
|
||||
reply_buffer: &mut [u8],
|
||||
) -> Result<(), SecurityRequestError> {
|
||||
fn serialize_failure(e: postcard::Error) -> SecurityRequestError {
|
||||
trace!("serialize failed: {:?}", e);
|
||||
SecurityRequestError::SreBundleDataInvalid
|
||||
}
|
||||
fn deserialize_failure(e: postcard::Error) -> SecurityRequestError {
|
||||
trace!("deserialize failed: {:?}", e);
|
||||
SecurityRequestError::SreBundleDataInvalid
|
||||
}
|
||||
|
||||
// TODO(sleffler): mailbox ipc
|
||||
match request_id {
|
||||
SecurityRequest::SrEcho => {
|
||||
trace!("ECHO {:?}", request_buffer);
|
||||
reply_buffer[0..request_buffer.len()].copy_from_slice(&request_buffer[..]);
|
||||
Ok(())
|
||||
}
|
||||
SecurityRequest::SrInstall => {
|
||||
trace!(
|
||||
"INSTALL addr {:p} len {}",
|
||||
request_buffer.as_ptr(),
|
||||
request_buffer.len()
|
||||
);
|
||||
let _ = postcard::to_slice(
|
||||
&(request_buffer.as_ptr() as usize).to_string(),
|
||||
reply_buffer,
|
||||
)
|
||||
.map_err(serialize_failure)?;
|
||||
Ok(())
|
||||
}
|
||||
SecurityRequest::SrUninstall => {
|
||||
let request = postcard::from_bytes::<UninstallRequest>(&request_buffer[..])
|
||||
.map_err(deserialize_failure)?;
|
||||
trace!("UNINSTALL {}", request.bundle_id);
|
||||
Ok(())
|
||||
}
|
||||
SecurityRequest::SrSizeBuffer => {
|
||||
let request = postcard::from_bytes::<SizeBufferRequest>(&request_buffer[..])
|
||||
.map_err(deserialize_failure)?;
|
||||
trace!("SIZE BUFFER bundle_id {}", request.bundle_id);
|
||||
let _ = postcard::to_slice(
|
||||
&0u32, // TODO(sleffler): fill-in
|
||||
reply_buffer
|
||||
).map_err(serialize_failure)?;
|
||||
Ok(())
|
||||
}
|
||||
SecurityRequest::SrGetManifest => {
|
||||
let request = postcard::from_bytes::<SizeBufferRequest>(&request_buffer[..])
|
||||
.map_err(deserialize_failure)?;
|
||||
trace!("GET MANIFEST bundle_id {}", request.bundle_id);
|
||||
let _ = postcard::to_slice(
|
||||
"# Comments like this
|
||||
[Manifest]
|
||||
BundleId=com.google.cerebra.hw.HelloWorld
|
||||
|
||||
[Binaries]
|
||||
App=HelloWorldBin
|
||||
Model=NeuralNetworkName
|
||||
|
||||
[Storage]
|
||||
Required=1
|
||||
", // TODO(sleffler): fill-in
|
||||
reply_buffer
|
||||
).map_err(serialize_failure)?;
|
||||
Ok(())
|
||||
}
|
||||
SecurityRequest::SrLoadApplication => {
|
||||
let request = postcard::from_bytes::<LoadApplicationRequest>(&request_buffer[..])
|
||||
.map_err(deserialize_failure)?;
|
||||
trace!(
|
||||
"LOAD APPLICATION bundle_id {} addr {:p}",
|
||||
request.bundle_id,
|
||||
request.app_binary
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
SecurityRequest::SrLoadModel => {
|
||||
let request = postcard::from_bytes::<LoadModelRequest>(&request_buffer[..])
|
||||
.map_err(deserialize_failure)?;
|
||||
trace!(
|
||||
"LOAD MODEL bundle_id {} model_id {} addr {:p}",
|
||||
request.bundle_id,
|
||||
request.model_id,
|
||||
request.model_binary
|
||||
);
|
||||
Ok(())
|
||||
}
|
||||
SecurityRequest::SrReadKey => Err(SecurityRequestError::SreReadFailed),
|
||||
SecurityRequest::SrWriteKey => Err(SecurityRequestError::SreWriteFailed),
|
||||
SecurityRequest::SrDeleteKey => Err(SecurityRequestError::SreDeleteFailed),
|
||||
}
|
||||
}
|
||||
}
|
@@ -3,10 +3,10 @@
|
||||
|
||||
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
|
||||
|
||||
#define DEFAULT_BUNDLE_ID_CAPACITY 64
|
||||
|
||||
#define RAW_BUNDLE_ID_DATA_SIZE 100
|
||||
|
||||
#define DEFAULT_BUNDLE_ID_CAPACITY 64
|
||||
|
||||
typedef enum ProcessManagerError {
|
||||
Success = 0,
|
||||
BundleIdInvalid,
|
||||
|
41
apps/system/interfaces/SecurityCoordinatorBindings.h
Normal file
41
apps/system/interfaces/SecurityCoordinatorBindings.h
Normal file
@@ -0,0 +1,41 @@
|
||||
#ifndef __SECURITY_COORDINATOR_BINDINGS_H__
|
||||
#define __SECURITY_COORDINATOR_BINDINGS_H__
|
||||
|
||||
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
|
||||
|
||||
#define SECURITY_REQUEST_DATA_SIZE 2048
|
||||
|
||||
#define SECURITY_REPLY_DATA_SIZE 2048
|
||||
|
||||
typedef enum SecurityRequest {
|
||||
SrEcho = 0,
|
||||
SrInstall,
|
||||
SrUninstall,
|
||||
SrLoadApplication,
|
||||
SrLoadModel,
|
||||
SrReadKey,
|
||||
SrWriteKey,
|
||||
SrDeleteKey,
|
||||
} SecurityRequest;
|
||||
|
||||
typedef enum SecurityRequestError {
|
||||
SreSuccess = 0,
|
||||
SreBundleIdInvalid,
|
||||
SreBundleDataInvalid,
|
||||
SreBundleNotFound,
|
||||
SreKeyNotFound,
|
||||
SrePackageBufferLenInvalid,
|
||||
SreValueInvalid,
|
||||
SreKeyInvalid,
|
||||
SreInstallFailed,
|
||||
SreUninstallFailed,
|
||||
SreReadFailed,
|
||||
SreWriteFailed,
|
||||
SreDeleteFailed,
|
||||
} SecurityRequestError;
|
||||
|
||||
typedef uint8_t SecurityRequestData[SECURITY_REQUEST_DATA_SIZE];
|
||||
|
||||
typedef uint8_t SecurityReplyData[SECURITY_REPLY_DATA_SIZE];
|
||||
|
||||
#endif /* __SECURITY_COORDINATOR_BINDINGS_H__ */
|
@@ -0,0 +1,5 @@
|
||||
procedure SecurityCoordinatorInterface {
|
||||
include <SecurityCoordinatorBindings.h>;
|
||||
|
||||
SecurityRequestError request(in int request_id, in char request[], out SecurityReplyData reply);
|
||||
};
|
@@ -20,6 +20,7 @@ import "components/DebugConsole/DebugConsole.camkes";
|
||||
import "components/ProcessManager/ProcessManager.camkes";
|
||||
import "components/MlCoordinator/MlCoordinator.camkes";
|
||||
import "components/SeL4Debug/SeL4Debug.camkes";
|
||||
import "components/SecurityCoordinator/SecurityCoordinator.camkes";
|
||||
import "components/VectorCoreDriver/VectorCoreDriver.camkes";
|
||||
|
||||
component OpenTitanUART {
|
||||
@@ -49,6 +50,7 @@ assembly {
|
||||
component ProcessManager process_manager;
|
||||
component MlCoordinator ml_coordinator;
|
||||
component DebugConsole debug_console;
|
||||
component SecurityCoordinator security_coordinator;
|
||||
|
||||
// OpenTitanUARTDriver
|
||||
connection seL4HardwareMMIO uart_mem(from uart_driver.mmio_region,
|
||||
@@ -73,6 +75,15 @@ assembly {
|
||||
connection seL4RPCCall shell_ml(from debug_console.mlcoord,
|
||||
to ml_coordinator.mlcoord);
|
||||
|
||||
// Connect the SecurityCoordinatorInterface to each component that needs
|
||||
// access to the Security Core. Note this allocates a 4KB shared memory
|
||||
// region to each component and copies data between components.
|
||||
connection seL4RPCOverMultiSharedData multi_security(
|
||||
from debug_console.security, // NB: for debug/test
|
||||
from process_manager.security,
|
||||
from ml_coordinator.security, // NB: for LoadModel but not in design
|
||||
to security_coordinator.security);
|
||||
|
||||
// Connect the DebugConsole to the OpenTitanUARTDriver.
|
||||
connection seL4SharedData tx_channel(
|
||||
from debug_console.tx_dataport, to uart_driver.tx_dataport);
|
||||
@@ -89,6 +100,7 @@ assembly {
|
||||
connection seL4RPCOverMultiSharedData multi_logger(
|
||||
from process_manager.logger,
|
||||
from ml_coordinator.logger,
|
||||
from security_coordinator.logger,
|
||||
to debug_console.logger);
|
||||
|
||||
// Connect the SeL4Debug interface of each component that needs access.
|
||||
|
Reference in New Issue
Block a user