Merge "Add StorageManager skeleton."

GitOrigin-RevId: e776e3c357ca54ad3b74212176da8a4ebc16b372
This commit is contained in:
Sam Leffler 2021-09-22 20:33:51 +00:00
parent 66c03e7858
commit bf19c88ccf
21 changed files with 671 additions and 82 deletions

View File

@ -67,6 +67,18 @@ DeclareCAmkESComponent(SecurityCoordinator
INCLUDES interfaces
)
RustAddLibrary(
kata_storage_manager
SOURCE_DIR ${CMAKE_CURRENT_LIST_DIR}/components/StorageManager
TARGET "riscv32imc-unknown-none-elf"
LIB_FILENAME libkata_storage_manager.a
)
DeclareCAmkESComponent(StorageManager
LIBS kata_storage_manager
INCLUDES interfaces
)
DeclareCAmkESComponent(LogFibonacci
SOURCES
components/LogFibonacci/src/main.c

View File

@ -4,6 +4,7 @@ import <PackageManagementInterface.camkes>;
import <MlCoordinatorInterface.camkes>;
import <SecurityCoordinatorInterface.camkes>;
import <SeL4DebugInterface.camkes>;
import <StorageInterface.camkes>;
component DebugConsole {
control;
@ -19,8 +20,10 @@ component DebugConsole {
provides LoggerInterface logger;
uses ProcessControlInterface proc_ctrl;
uses PackageManagementInterface pkg_mgmt;
// TODO(sleffler): for debugging
// TODO(b/200707300): for debugging
uses SecurityCoordinatorInterface security;
// TODO(b/200707300): for debugging
uses StorageInterface storage;
uses SeL4DebugInterface sel4debug;
uses MlCoordinatorInterface mlcoord;
}

View File

@ -10,5 +10,6 @@ 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" }
kata-storage-interface = { path = "../../StorageManager/kata-storage-interface" }
log = "0.4"
postcard = { version = "0.7", features = ["alloc"] }

View File

@ -2,6 +2,7 @@
extern crate alloc;
use alloc::string::String;
use alloc::vec::Vec;
use core::fmt;
use core::fmt::Write;
use cstr_core::CString;
@ -10,6 +11,9 @@ use postcard;
use kata_io as io;
use kata_line_reader::LineReader;
use kata_proc_common::{BundleIdArray, ProcessManagerError, RAW_BUNDLE_ID_DATA_SIZE};
use kata_storage_interface::kata_storage_delete;
use kata_storage_interface::kata_storage_read;
use kata_storage_interface::kata_storage_write;
/// Error type indicating why a command line is not runnable.
enum CommandError {
@ -79,6 +83,9 @@ fn dispatch_command(cmdline: &str, output: &mut dyn io::Write) {
"echo" => echo_command(cmdline, output),
"clear" => clear_command(output),
"bundles" => bundles_command(output),
"kvdelete" => kvdelete_command(&mut args, output),
"kvread" => kvread_command(&mut args, output),
"kvwrite" => kvwrite_command(&mut args, output),
"install" => install_command(&mut args, output),
"loglevel" => loglevel_command(&mut args, output),
"ps" => ps_command(),
@ -123,14 +130,7 @@ fn scecho_command(cmdline: &str, output: &mut dyn io::Write) -> Result<(), Comma
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 _,
)
} {
match kata_security_request(SecurityRequest::SrEcho, request.as_bytes(), reply) {
SecurityRequestError::SreSuccess => {
writeln!(
output,
@ -331,11 +331,69 @@ fn stop_command(
}
}
fn kvdelete_command(
args: &mut dyn Iterator<Item = &str>,
output: &mut dyn io::Write,
) -> Result<(), CommandError> {
if let Some(key) = args.nth(0) {
match kata_storage_delete(key) {
Ok(_) => {
writeln!(output, "Delete key \"{}\".", key)?;
}
Err(status) => {
writeln!(output, "Delete key \"{}\" failed: {:?}", key, status)?;
}
}
Ok(())
} else {
Err(CommandError::BadArgs)
}
}
fn kvread_command(
args: &mut dyn Iterator<Item = &str>,
output: &mut dyn io::Write,
) -> Result<(), CommandError> {
if let Some(key) = args.nth(0) {
match kata_storage_read(key) {
Ok(value) => {
writeln!(output, "Read key \"{}\" = {:?}.", key, value)?;
}
Err(status) => {
writeln!(output, "Read key \"{}\" failed: {:?}", key, status)?;
}
}
Ok(())
} else {
Err(CommandError::BadArgs)
}
}
fn kvwrite_command(
args: &mut dyn Iterator<Item = &str>,
output: &mut dyn io::Write,
) -> Result<(), CommandError> {
if let Some(key) = args.nth(0) {
let value = args.collect::<Vec<&str>>().join(" ");
match kata_storage_write(key, value.as_bytes()) {
Ok(_) => {
writeln!(output, "Write key \"{}\" = {:?}.", key, value)?;
}
Err(status) => {
writeln!(output, "Write key \"{}\" failed: {:?}", key, status)?;
}
}
Ok(())
} else {
Err(CommandError::BadArgs)
}
}
/// Implements a command that tests facilities that use the global allocator.
/// Shamelessly cribbed from https://os.phil-opp.com/heap-allocation/
fn test_alloc_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
extern crate alloc;
use alloc::{boxed::Box, rc::Rc, vec, vec::Vec};
use alloc::{boxed::Box, rc::Rc, vec};
// allocate a number on the heap
let heap_value = Box::new(41);
@ -370,9 +428,6 @@ fn test_alloc_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
/// Implements a command that tests the global allocator error handling.
fn test_alloc_error_command(output: &mut dyn io::Write) -> Result<(), CommandError> {
extern crate alloc;
use alloc::vec::Vec;
// Default heap holds 16KB.
let mut vec = Vec::with_capacity(16384);
for i in 0..16348 {

View File

@ -4,6 +4,7 @@
extern crate alloc;
use alloc::string::String;
use core::slice;
use kata_proc_common::*;
use kata_security_common::*;
use log::trace;
@ -89,14 +90,11 @@ impl ProcessManagerInterface for KataManagerInterface {
// 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 _,
)
} {
match kata_security_request(
SecurityRequest::SrInstall,
unsafe { slice::from_raw_parts(pkg_buffer, pkg_buffer_size as usize) },
reply,
) {
SecurityRequestError::SreSuccess => {
fn deserialize_failure(e: postcard::Error) -> ProcessManagerError {
trace!("install failed: deserialize {:?}", e);
@ -123,14 +121,7 @@ impl ProcessManagerInterface for KataManagerInterface {
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 _,
)
} {
match kata_security_request(SecurityRequest::SrUninstall, &request_data, reply) {
SecurityRequestError::SreSuccess => Ok(()),
status => {
trace!("uninstall failed: {:?}", status);
@ -139,7 +130,7 @@ impl ProcessManagerInterface for KataManagerInterface {
}
}
fn start(&mut self, _bundle: &Bundle) -> Result<(), ProcessManagerError> {
// 1. Ask security core for application footprint with SizeBuffer
// 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)

View File

@ -45,6 +45,8 @@ mod mut_ptr_helper {
}
}
// TODO(sleffler): convert String to &str
// NB: SecurityRequestInstall is handled specially.
// SecurityRequestUninstall
@ -145,8 +147,8 @@ pub enum SecurityRequest {
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
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>]
@ -166,14 +168,29 @@ pub trait SecurityCoordinatorInterface {
) -> Result<(), SecurityRequestError>;
}
// Camkes-generated rpc api.
// NB: this requires the SecurityCoordinator component be named "security".
// TODO(sleffler): try kata_security_request<T> to lower serde work
#[inline]
#[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;
pub fn kata_security_request(
request: SecurityRequest,
request_buffer: &[u8],
reply_buffer: &mut SecurityReplyData,
) -> SecurityRequestError {
// NB: this assumes the SecurityCoordinator component is named "security".
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;
}
unsafe {
security_request(
request,
request_buffer.len() as u32,
request_buffer.as_ptr(),
reply_buffer as *mut _,
)
}
}

View File

@ -9,6 +9,8 @@ fake = []
sel4 = []
[dependencies]
hashbrown = { version = "0.11", features = ["ahash-compile-time-rng"] }
kata-security-common = { path = "../kata-security-common" }
kata-storage-interface = { path = "../../StorageManager/kata-storage-interface" }
log = "0.4"
postcard = "0.7"

View File

@ -1,22 +1,69 @@
//! Kata OS security coordinator fake support
extern crate alloc;
use alloc::string::ToString;
use alloc::string::{String, ToString};
use hashbrown::HashMap;
use kata_security_common::*;
use kata_storage_interface::{KeyValueData, KEY_VALUE_DATA_SIZE};
use log::trace;
use postcard;
pub struct FakeSecurityCoordinatorInterface {
// TODO(sleffler): mailbox ipc state
struct BundleData {
pkg_size: usize,
manifest: String,
keys: HashMap<String, KeyValueData>,
}
impl FakeSecurityCoordinatorInterface {
pub fn new() -> Self {
FakeSecurityCoordinatorInterface {}
impl BundleData {
fn new(pkg_size: usize) -> Self {
BundleData {
pkg_size: pkg_size,
manifest: String::from(
"# Comments like this
[Manifest]
BundleId=com.google.cerebra.hw.HelloWorld
[Binaries]
App=HelloWorldBin
Model=NeuralNetworkName
[Storage]
Required=1
",
),
keys: HashMap::with_capacity(2),
}
}
}
pub type KataSecurityCoordinatorInterface = FakeSecurityCoordinatorInterface;
impl SecurityCoordinatorInterface for FakeSecurityCoordinatorInterface {
pub struct FakeSecurityCoordinator {
bundles: HashMap<String, BundleData>,
}
impl FakeSecurityCoordinator {
pub fn new() -> Self {
FakeSecurityCoordinator {
bundles: HashMap::with_capacity(2),
}
}
fn get_bundle(&self, bundle_id: &str) -> Result<&BundleData, SecurityRequestError> {
self.bundles
.get(bundle_id)
.map_or_else(|| Err(SecurityRequestError::SreBundleNotFound), |v| Ok(v))
}
fn get_bundle_mut(&mut self, bundle_id: &str) -> Result<&mut BundleData, SecurityRequestError> {
self.bundles
.get_mut(bundle_id)
.map_or_else(|| Err(SecurityRequestError::SreBundleNotFound), |v| Ok(v))
}
fn remove_bundle(&mut self, bundle_id: &str) -> Result<(), SecurityRequestError> {
self.bundles
.remove(bundle_id)
.map_or_else(|| Err(SecurityRequestError::SreBundleNotFound), |_v| Ok(()))
}
}
pub type KataSecurityCoordinatorInterface = FakeSecurityCoordinator;
impl SecurityCoordinatorInterface for FakeSecurityCoordinator {
fn request(
&mut self,
request_id: SecurityRequest,
@ -47,25 +94,29 @@ impl SecurityCoordinatorInterface for FakeSecurityCoordinatorInterface {
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)?;
// let bundle_id = (request_buffer.as_ptr() as usize).to_string();
// TODO(sleffler): used by kata-storage-component for kvops
let bundle_id = "fubar".to_string();
let _ = postcard::to_slice(&bundle_id, reply_buffer).map_err(serialize_failure)?;
assert!(self
.bundles
.insert(bundle_id, BundleData::new(request_buffer.len()))
.is_none());
Ok(())
}
SecurityRequest::SrUninstall => {
let request = postcard::from_bytes::<UninstallRequest>(&request_buffer[..])
.map_err(deserialize_failure)?;
trace!("UNINSTALL {}", request.bundle_id);
Ok(())
self.remove_bundle(&request.bundle_id)
}
SecurityRequest::SrSizeBuffer => {
let request = postcard::from_bytes::<SizeBufferRequest>(&request_buffer[..])
.map_err(deserialize_failure)?;
trace!("SIZE BUFFER bundle_id {}", request.bundle_id);
let bundle = self.get_bundle(&request.bundle_id)?;
let _ = postcard::to_slice(
&0u32, // TODO(sleffler): fill-in
&bundle.pkg_size, // TODO(sleffler): do better
reply_buffer,
)
.map_err(serialize_failure)?;
@ -75,21 +126,9 @@ impl SecurityCoordinatorInterface for FakeSecurityCoordinatorInterface {
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)?;
let bundle = self.get_bundle(&request.bundle_id)?;
let _ = postcard::to_slice(&bundle.manifest, reply_buffer)
.map_err(serialize_failure)?;
Ok(())
}
SecurityRequest::SrLoadApplication => {
@ -100,6 +139,7 @@ impl SecurityCoordinatorInterface for FakeSecurityCoordinatorInterface {
request.bundle_id,
request.app_binary
);
let _ = self.get_bundle(&request.bundle_id)?;
Ok(())
}
SecurityRequest::SrLoadModel => {
@ -111,6 +151,8 @@ impl SecurityCoordinatorInterface for FakeSecurityCoordinatorInterface {
request.model_id,
request.model_binary
);
// TODO(sleffler): check model id
let _ = self.get_bundle(&request.bundle_id)?;
Ok(())
}
SecurityRequest::SrReadKey => {
@ -121,8 +163,15 @@ impl SecurityCoordinatorInterface for FakeSecurityCoordinatorInterface {
request.bundle_id,
request.key,
);
// TODO(sleffler): fill-in
Err(SreReadFailed)
let bundle = self.get_bundle(&request.bundle_id)?;
match bundle.keys.get(&request.key) {
Some(value) => {
// TODO(sleffler): return values are fixed size unless we serialize
reply_buffer[..value.len()].copy_from_slice(&value[..]);
Ok(())
}
None => Err(SreKeyNotFound),
}
}
SecurityRequest::SrWriteKey => {
let request = postcard::from_bytes::<WriteKeyRequest>(&request_buffer[..])
@ -133,8 +182,12 @@ impl SecurityCoordinatorInterface for FakeSecurityCoordinatorInterface {
request.key,
request.value,
);
// TODO(sleffler): fill-in
Err(SreWriteFailed)
let bundle = self.get_bundle_mut(&request.bundle_id)?;
// TODO(sleffler): optimnize with entry
let mut value = [0u8; KEY_VALUE_DATA_SIZE];
value[..request.value.len()].copy_from_slice(request.value);
let _ = bundle.keys.insert(request.key, value);
Ok(())
}
SecurityRequest::SrDeleteKey => {
let request = postcard::from_bytes::<DeleteKeyRequest>(&request_buffer[..])
@ -144,8 +197,10 @@ impl SecurityCoordinatorInterface for FakeSecurityCoordinatorInterface {
request.bundle_id,
request.key,
);
// TODO(sleffler): fill-in
Err(SreDeleteFailed)
let bundle = self.get_bundle_mut(&request.bundle_id)?;
// TODO(sleffler): error if no entry?
let _ = bundle.keys.remove(&request.key);
Ok(())
}
}
}

View File

@ -5,17 +5,17 @@ use kata_security_common::*;
use log::trace;
use postcard;
pub struct SeL4SecurityCoordinatorInterface {
pub struct SeL4SecurityCoordinator {
// TODO(sleffler): mailbox ipc state
}
impl SeL4SecurityCoordinatorInterface {
impl SeL4SecurityCoordinator {
pub fn new() -> Self {
SeL4SecurityCoordinatorInterface {}
SeL4SecurityCoordinator {}
}
}
pub type KataSecurityCoordinatorInterface = SeL4SecurityCoordinatorInterface;
pub type KataSecurityCoordinatorInterface = SeL4SecurityCoordinator;
impl SecurityCoordinatorInterface for SeL4SecurityCoordinatorInterface {
impl SecurityCoordinatorInterface for SeL4SecurityCoordinator {
fn request(
&mut self,
request_id: SecurityRequest,

View File

@ -0,0 +1,23 @@
[workspace]
members = [
"kata-storage-component",
"kata-storage-interface",
"kata-storage-manager",
]
[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

View File

@ -0,0 +1,12 @@
// Kata OS StorageManager services.
import <LoggerInterface.camkes>;
import <SecurityCoordinatorInterface.camkes>;
import <StorageInterface.camkes>;
component StorageManager {
provides StorageInterface storage;
uses LoggerInterface logger;
uses SecurityCoordinatorInterface security;
}

View File

@ -0,0 +1,7 @@
language = "C"
include_guard = "__STORAGE_MANAGER_BINDINGS_H__"
autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */"
no_includes = true
[export]
include = ["KeyValueData", "StorageManagerError"]

View File

@ -0,0 +1,19 @@
[package]
name = "kata-storage-component"
version = "0.1.0"
edition = "2018"
[dependencies]
cstr_core = { version = "0.2.3", default-features = false }
kata-allocator = { path = "../../DebugConsole/kata-allocator" }
kata-logger = { path = "../../DebugConsole/kata-logger" }
kata-panic = { path = "../../DebugConsole/kata-panic" }
kata-storage-interface = { path = "../kata-storage-interface" }
kata-storage-manager = { path = "../kata-storage-manager" }
log = "0.4"
postcard = "0.7"
[lib]
name = "kata_storage_manager"
path = "src/run.rs"
crate-type = ["staticlib"]

View File

@ -0,0 +1,120 @@
//! Kata OS StorageManager component support.
// Code here binds the camkes component to the rust code.
#![no_std]
extern crate alloc;
use core::slice;
use cstr_core::CStr;
extern crate kata_panic;
use kata_allocator;
use kata_logger::KataLogger;
use kata_storage_interface::KeyValueData;
use kata_storage_interface::StorageError;
use kata_storage_interface::StorageManagerInterface;
use kata_storage_interface::StorageManagerError;
use kata_storage_manager::KATA_STORAGE;
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
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()
);
}
}
fn map_storage_error(se: StorageError, def: StorageManagerError) -> StorageManagerError {
match se {
StorageError::Success => StorageManagerError::SmeSuccess,
StorageError::BundleNotFound => StorageManagerError::SmeBundleNotFound,
StorageError::KeyNotFound => StorageManagerError::SmeKeyNotFound,
StorageError::KeyInvalid => StorageManagerError::SmeKeyInvalid,
StorageError::ValueInvalid => StorageManagerError::SmeValueInvalid,
_ => def,
}
}
// StorageInterface glue stubs.
#[no_mangle]
pub extern "C" fn storage_read(
c_key: *const cstr_core::c_char,
c_raw_value: *mut KeyValueData,
) -> StorageManagerError {
unsafe {
match CStr::from_ptr(c_key).to_str() {
Ok(key) => {
// TODO(sleffler): de-badge reply cap to get bundle_id
match KATA_STORAGE.read("fubar", key) {
// NB: no serialization, returns raw data
Ok(value) => {
(*c_raw_value).copy_from_slice(&value);
StorageManagerError::SmeSuccess
}
Err(e) => map_storage_error(e, StorageManagerError::SmeReadFailed),
}
}
Err(e) => {
trace!("read: keyinvalid {:?}", e);
StorageManagerError::SmeKeyInvalid
}
}
}
}
#[no_mangle]
pub extern "C" fn storage_write(
c_key: *const cstr_core::c_char,
c_raw_value_len: usize,
c_raw_value: *const u8,
) -> StorageManagerError {
unsafe {
match CStr::from_ptr(c_key).to_str() {
Ok(key) => {
// TODO(sleffler): de-badge reply cap to get bundle_id
match KATA_STORAGE.write(
"fubar",
key,
slice::from_raw_parts(c_raw_value, c_raw_value_len),
) {
Ok(_) => StorageManagerError::SmeSuccess,
Err(e) => map_storage_error(e, StorageManagerError::SmeWriteFailed),
}
}
Err(e) => {
trace!("write: keyinvalid {:?}", e);
StorageManagerError::SmeKeyInvalid
}
}
}
}
#[no_mangle]
pub extern "C" fn storage_delete(c_key: *const cstr_core::c_char) -> StorageManagerError {
unsafe {
match CStr::from_ptr(c_key).to_str() {
Ok(key) => {
// TODO(sleffler): de-badge reply cap to get bundle_id
match KATA_STORAGE.delete("fubar", key) {
Ok(_) => StorageManagerError::SmeSuccess,
Err(e) => map_storage_error(e, StorageManagerError::SmeDeleteFailed),
}
}
Err(e) => {
trace!("delete: keyinvalid {:?}", e);
StorageManagerError::SmeKeyInvalid
}
}
}
}

View File

@ -0,0 +1,7 @@
[package]
name = "kata-storage-interface"
version = "0.1.0"
edition = "2018"
[dependencies]
cstr_core = "0.2"

View File

@ -0,0 +1,105 @@
//! Kata OS storage management support
#![cfg_attr(not(test), no_std)]
use core::str;
use cstr_core::CString;
// TODO(sleffler): temp constraint on value part of key-value pairs
pub const KEY_VALUE_DATA_SIZE: usize = 100;
pub type KeyValueData = [u8; KEY_VALUE_DATA_SIZE];
// NB: struct's marked repr(C) are processed by cbindgen to get a .h file
// used in camkes C interfaces.
#[derive(Debug, Eq, PartialEq)]
pub enum StorageError {
Success = 0,
BundleNotFound,
KeyNotFound,
KeyInvalid,
ValueInvalid,
SerializeFailed,
// Generic errors.
ReadFailed,
WriteFailed,
DeleteFailed,
}
pub trait StorageManagerInterface {
fn read(&self, bundle_id: &str, key: &str) -> Result<KeyValueData, StorageError>;
fn write(&self, bundle_id: &str, key: &str, value: &[u8]) -> Result<(), StorageError>;
fn delete(&self, bundle_id: &str, key: &str) -> Result<(), StorageError>;
}
// Public version of StorageError presented over rpc interface.
// This is needed because the enum is exported to C users and needs to
// be unique from other enum's.
// TODO(sleffler): switch to single generic error space ala absl::StatusCode
#[repr(C)]
#[derive(Debug, Eq, PartialEq)]
pub enum StorageManagerError {
SmeSuccess = 0,
SmeBundleIdInvalid,
SmeBundleNotFound,
SmeKeyNotFound,
SmeValueInvalid,
SmeKeyInvalid,
// Generic errors.
SmeReadFailed,
SmeWriteFailed,
SmeDeleteFailed,
}
#[inline]
#[allow(dead_code)]
pub fn kata_storage_delete(key: &str) -> Result<(), StorageManagerError> {
// NB: this assumes the StorageManager component is named "storage".
extern "C" {
pub fn storage_delete(
c_key: *const cstr_core::c_char
) -> StorageManagerError;
}
let cstr = CString::new(key)
.map_err(|_| StorageManagerError::SmeKeyInvalid)?;
match unsafe { storage_delete(cstr.as_ptr()) } {
StorageManagerError::SmeSuccess => Ok(()),
status => Err(status),
}
}
#[inline]
#[allow(dead_code)]
pub fn kata_storage_read(key: &str) -> Result<KeyValueData, StorageManagerError> {
extern "C" {
fn storage_read(
c_key: *const cstr_core::c_char,
c_raw_value: *mut KeyValueData,
) -> StorageManagerError;
}
let cstr = CString::new(key)
.map_err(|_| StorageManagerError::SmeKeyInvalid)?;
let value = &mut [0u8; KEY_VALUE_DATA_SIZE];
match unsafe { storage_read(cstr.as_ptr(), value as *mut _) } {
StorageManagerError::SmeSuccess => Ok(*value),
status => Err(status),
}
}
#[inline]
#[allow(dead_code)]
pub fn kata_storage_write(key: &str, value: &[u8]) -> Result<(), StorageManagerError> {
extern "C" {
fn storage_write(
c_key: *const cstr_core::c_char,
c_raw_value_len: usize,
c_raw_value: *const u8,
) -> StorageManagerError;
}
let cstr = CString::new(key)
.map_err(|_| StorageManagerError::SmeKeyInvalid)?;
match unsafe { storage_write(cstr.as_ptr(), value.len(), value.as_ptr()) } {
StorageManagerError::SmeSuccess => Ok(()),
status => Err(status),
}
}

View File

@ -0,0 +1,10 @@
[package]
name = "kata-storage-manager"
version = "0.1.0"
edition = "2018"
[dependencies]
kata-security-common = { path = "../../SecurityCoordinator/kata-security-common" }
kata-storage-interface = { path = "../kata-storage-interface" }
log = "0.4"
postcard = "0.7"

View File

@ -0,0 +1,115 @@
//! Kata OS storage management support
#![cfg_attr(not(test), no_std)]
extern crate alloc;
use alloc::string::String;
use kata_security_common::*;
use kata_storage_interface::{KeyValueData, KEY_VALUE_DATA_SIZE};
use kata_storage_interface::StorageError;
use kata_storage_interface::StorageManagerInterface;
use log::trace;
use postcard;
// NB: KATA_STORAGE cannot be used before setup is completed with a call to init()
#[cfg(not(test))]
pub static mut KATA_STORAGE: KataStorageManager = KataStorageManager{};
// KataStorageManager bundles an instance of the StorageManager that operates
// on KataOS interfaces. There is a two-step dance to setup an instance because
// we want KATA_STORAGE static and there is no const Box::new variant.
pub struct KataStorageManager;
impl StorageManagerInterface for KataStorageManager {
fn read(&self, bundle_id: &str, key: &str) -> Result<KeyValueData, StorageError> {
trace!("read bundle_id:{} key:{}", bundle_id, key);
fn serialize_failure(e: postcard::Error) -> StorageError {
trace!("read: serialize failure {:?}", e);
StorageError::SerializeFailed
}
// Send request to Security Core via SecurityCoordinator
let mut request = [0u8; SECURITY_REQUEST_DATA_SIZE];
let _ = postcard::to_slice(
&ReadKeyRequest {
bundle_id: String::from(bundle_id),
key: String::from(key),
},
&mut request[..],
)
.map_err(serialize_failure)?;
let result = &mut [0u8; SECURITY_REPLY_DATA_SIZE];
match kata_security_request(SecurityRequest::SrReadKey, &request, result) {
SecurityRequestError::SreSuccess => {
let mut keyval = [0u8; KEY_VALUE_DATA_SIZE];
keyval.copy_from_slice(&result[..KEY_VALUE_DATA_SIZE]);
Ok(keyval)
}
e => Err(map_security_request_error(e, StorageError::ReadFailed)),
}
}
fn write(&self, bundle_id: &str, key: &str, value: &[u8]) -> Result<(), StorageError> {
trace!(
"write bundle_id:{} key:{} value:{:?}",
bundle_id,
key,
value
);
fn serialize_failure(e: postcard::Error) -> StorageError {
trace!("write: serialize failure {:?}", e);
StorageError::SerializeFailed
}
// Send request to Security Core via SecurityCoordinator
let mut request = [0u8; SECURITY_REQUEST_DATA_SIZE];
let _ = postcard::to_slice(
&WriteKeyRequest {
bundle_id: String::from(bundle_id),
key: String::from(key),
value: value,
},
&mut request[..],
)
.map_err(serialize_failure)?;
let result = &mut [0u8; SECURITY_REPLY_DATA_SIZE];
match kata_security_request(SecurityRequest::SrWriteKey, &request, result) {
SecurityRequestError::SreSuccess => Ok(()),
e => Err(map_security_request_error(e, StorageError::WriteFailed)),
}
}
fn delete(&self, bundle_id: &str, key: &str) -> Result<(), StorageError> {
trace!("delete bundle_id:{} key:{}", bundle_id, key);
fn serialize_failure(e: postcard::Error) -> StorageError {
trace!("delete: serialize failure {:?}", e);
StorageError::SerializeFailed
}
// Send request to Security Core via SecurityCoordinator
let mut request = [0u8; SECURITY_REQUEST_DATA_SIZE];
let _ = postcard::to_slice(
&DeleteKeyRequest {
bundle_id: String::from(bundle_id),
key: String::from(key),
},
&mut request[..],
)
.map_err(serialize_failure)?;
let result = &mut [0u8; SECURITY_REPLY_DATA_SIZE];
match kata_security_request(SecurityRequest::SrDeleteKey, &request, result) {
SecurityRequestError::SreSuccess => Ok(()),
e => Err(map_security_request_error(e, StorageError::DeleteFailed)),
}
}
}
// Maps a SecuritRequestError to a StorageError.
fn map_security_request_error(sre: SecurityRequestError, def: StorageError) -> StorageError {
match sre {
SecurityRequestError::SreSuccess => StorageError::Success,
SecurityRequestError::SreBundleNotFound => StorageError::BundleNotFound,
SecurityRequestError::SreKeyNotFound => StorageError::KeyNotFound,
_ => def,
}
}

View File

@ -0,0 +1,7 @@
procedure StorageInterface {
include <StorageManagerBindings.h>;
StorageManagerError read(in string key, out KeyValueData value);
StorageManagerError write(in string key, in char value[]);
StorageManagerError delete(in string key);
};

View File

@ -0,0 +1,22 @@
#ifndef __STORAGE_MANAGER_BINDINGS_H__
#define __STORAGE_MANAGER_BINDINGS_H__
/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */
#define KEY_VALUE_DATA_SIZE 100
typedef enum StorageManagerError {
SmeSuccess = 0,
SmeBundleIdInvalid,
SmeBundleNotFound,
SmeKeyNotFound,
SmeValueInvalid,
SmeKeyInvalid,
SmeReadFailed,
SmeWriteFailed,
SmeDeleteFailed,
} StorageManagerError;
typedef uint8_t KeyValueData[KEY_VALUE_DATA_SIZE];
#endif /* __STORAGE_MANAGER_BINDINGS_H__ */

View File

@ -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/StorageManager/StorageManager.camkes";
import "components/SecurityCoordinator/SecurityCoordinator.camkes";
import "components/VectorCoreDriver/VectorCoreDriver.camkes";
@ -51,6 +52,7 @@ assembly {
component MlCoordinator ml_coordinator;
component DebugConsole debug_console;
component SecurityCoordinator security_coordinator;
component StorageManager storage_manager;
// OpenTitanUARTDriver
connection seL4HardwareMMIO uart_mem(from uart_driver.mmio_region,
@ -74,6 +76,8 @@ assembly {
to process_manager.pkg_mgmt);
connection seL4RPCCall shell_ml(from debug_console.mlcoord,
to ml_coordinator.mlcoord);
connection seL4RPCCall shell_storage(from debug_console.storage,
to storage_manager.storage);
// Connect the SecurityCoordinatorInterface to each component that needs
// access to the Security Core. Note this allocates a 4KB shared memory
@ -82,6 +86,7 @@ assembly {
from debug_console.security, // NB: for debug/test
from process_manager.security,
from ml_coordinator.security, // NB: for LoadModel but not in design
from storage_manager.security,
to security_coordinator.security);
// Connect the DebugConsole to the OpenTitanUARTDriver.
@ -101,6 +106,7 @@ assembly {
from process_manager.logger,
from ml_coordinator.logger,
from security_coordinator.logger,
from storage_manager.logger,
to debug_console.logger);
// Connect the SeL4Debug interface of each component that needs access.