From 1af27f35c4216450d054d206b044845ac08f5f1b Mon Sep 17 00:00:00 2001 From: Ashley Lee Date: Fri, 10 Jan 2025 11:54:59 -0800 Subject: [PATCH] Naming Secure Gate Service (#239) * Switch init to use new runtime. * Cleanup tests. * Reorg. * Added secure gate naming library * reverted changes * refactored naming service * removed changes in main * did fmt * removed unnecessary dependency --------- Co-authored-by: Daniel Bittman --- Cargo.lock | 28 +++++ Cargo.toml | 5 + src/bin/init/src/main.rs | 15 +++ src/bin/naming-test/Cargo.toml | 7 ++ src/bin/naming-test/src/main.rs | 18 ++++ src/lib/naming/Cargo.toml | 12 +++ src/lib/naming/src/lib.rs | 86 ++++++++++++++++ src/srv/naming-srv/Cargo.toml | 18 ++++ src/srv/naming-srv/src/lib.rs | 174 ++++++++++++++++++++++++++++++++ 9 files changed, 363 insertions(+) create mode 100644 src/bin/naming-test/Cargo.toml create mode 100644 src/bin/naming-test/src/main.rs create mode 100644 src/lib/naming/Cargo.toml create mode 100644 src/lib/naming/src/lib.rs create mode 100644 src/srv/naming-srv/Cargo.toml create mode 100644 src/srv/naming-srv/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index 408acbf4..692a07f6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3611,6 +3611,34 @@ dependencies = [ "twizzler-runtime", ] +[[package]] +name = "naming" +version = "0.1.0" +dependencies = [ + "naming-srv", + "secgate", + "twizzler-rt-abi", +] + +[[package]] +name = "naming-srv" +version = "0.1.0" +dependencies = [ + "arrayvec", + "lazy_static", + "secgate", + "twizzler-abi", + "twizzler-rt-abi", + "twizzler-runtime", +] + +[[package]] +name = "naming-test" +version = "0.1.0" +dependencies = [ + "naming", +] + [[package]] name = "native-tls" version = "0.2.12" diff --git a/Cargo.toml b/Cargo.toml index 5ae03a93..45c3095c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -41,6 +41,9 @@ members = [ "src/srv/pager-srv", "src/bin/logboi-test", "src/lib/virtio-net", + "src/lib/naming", + "src/srv/naming-srv", + "src/bin/naming-test", "src/bin/object-store-test", "src/lib/pager", ] @@ -63,6 +66,8 @@ initrd = [ "crate:random_validation", "crate:randtest", "crate:genrandom", + "lib:naming-srv", + "crate:naming-test", "crate:object-store-test", "lib:twz-rt", "lib:montest-lib", diff --git a/src/bin/init/src/main.rs b/src/bin/init/src/main.rs index b88a4823..00416fd7 100644 --- a/src/bin/init/src/main.rs +++ b/src/bin/init/src/main.rs @@ -56,6 +56,21 @@ fn main() { tracing::info!("logboi ready"); std::mem::forget(lbcomp); + let nmcomp: CompartmentHandle = CompartmentLoader::new( + "naming", + "libnaming_srv.so", + NewCompartmentFlags::EXPORT_GATES, + ) + .args(&["naming"]) + .load() + .unwrap(); + let mut flags = nmcomp.info().flags; + while !flags.contains(CompartmentFlags::READY) { + flags = nmcomp.wait(flags); + } + tracing::info!("naming ready"); + std::mem::forget(nmcomp); + let create = ObjectCreate::new( BackingType::Normal, LifetimeType::Volatile, diff --git a/src/bin/naming-test/Cargo.toml b/src/bin/naming-test/Cargo.toml new file mode 100644 index 00000000..c33d6aa6 --- /dev/null +++ b/src/bin/naming-test/Cargo.toml @@ -0,0 +1,7 @@ +[package] +name = "naming-test" +version = "0.1.0" +edition = "2021" + +[dependencies] +naming = { path = "../../lib/naming" } diff --git a/src/bin/naming-test/src/main.rs b/src/bin/naming-test/src/main.rs new file mode 100644 index 00000000..fe4fc3c3 --- /dev/null +++ b/src/bin/naming-test/src/main.rs @@ -0,0 +1,18 @@ +use std::fs::File; + +use naming::NamingHandle; + +fn main() { + let mut handle = NamingHandle::new().unwrap(); + + match handle.get(&"hello world!") { + Some(x) => { + handle.put(&"hello world!", x - 1); + println!("{} bottles of beer on the wall. {} bottles of beer! Take one down pass it around you got {} bottles of beer on the wall", x, x, x-1); + } + None => { + handle.put(&"hello world!", 99); + println!("No more bottles of beer on the wall, no more bottles of beer! Go to the store and buy some more, {} bottles of beer on the wall...", 99); + } + } +} diff --git a/src/lib/naming/Cargo.toml b/src/lib/naming/Cargo.toml new file mode 100644 index 00000000..a1556b0a --- /dev/null +++ b/src/lib/naming/Cargo.toml @@ -0,0 +1,12 @@ +[package] +name = "naming" +version = "0.1.0" +edition = "2021" + +[lib] +crate-type = ["rlib"] + +[dependencies] +naming-srv = { path = "../../srv/naming-srv" } +secgate = { path = "../../lib/secgate" } +twizzler-rt-abi = "0.99" diff --git a/src/lib/naming/src/lib.rs b/src/lib/naming/src/lib.rs new file mode 100644 index 00000000..4d555ee6 --- /dev/null +++ b/src/lib/naming/src/lib.rs @@ -0,0 +1,86 @@ +#[link(name = "naming_srv")] +extern "C" {} + +use naming_srv::{Schema, MAX_KEY_SIZE}; +use secgate::util::{Descriptor, Handle, SimpleBuffer}; +use twizzler_rt_abi::object::MapFlags; + +pub struct NamingHandle { + desc: Descriptor, + buffer: SimpleBuffer, +} + +impl Handle for NamingHandle { + type OpenError = (); + + type OpenInfo = (); + + fn open(_info: Self::OpenInfo) -> Result + where + Self: Sized, + { + let (desc, id) = naming_srv::open_handle().ok().flatten().ok_or(())?; + let handle = + twizzler_rt_abi::object::twz_rt_map_object(id, MapFlags::READ | MapFlags::WRITE) + .map_err(|_| ())?; + let sb = SimpleBuffer::new(handle); + Ok(Self { desc, buffer: sb }) + } + + fn release(&mut self) { + naming_srv::close_handle(self.desc); + } +} + +impl Drop for NamingHandle { + fn drop(&mut self) { + self.release() + } +} + +impl NamingHandle { + /// Open a new logging handle. + pub fn new() -> Option { + Self::open(()).ok() + } + + pub fn put(&mut self, key: &str, val: u128) { + let mut buffer = [0u8; MAX_KEY_SIZE]; + let key_bytes = key.as_bytes(); + + let length = key_bytes.len().min(MAX_KEY_SIZE); + buffer[..length].copy_from_slice(&key_bytes[..length]); + + // I should write directly to the simple buffer + let mut s = naming_srv::Schema { key: buffer, val }; + + // Interpret schema as a slice + let bytes = + unsafe { std::mem::transmute::()]>(s) }; + + let handle = self.buffer.write(&bytes); + + naming_srv::put(self.desc); + } + + pub fn get(&mut self, key: &str) -> Option { + let mut buffer = [0u8; MAX_KEY_SIZE]; + let key_bytes = key.as_bytes(); + + let length = key_bytes.len().min(MAX_KEY_SIZE); + buffer[..length].copy_from_slice(&key_bytes[..length]); + + // I should write directly to the simple buffer + let mut s = naming_srv::Schema { + key: buffer, + val: 0, + }; + + // Interpret schema as a slice + let bytes = + unsafe { std::mem::transmute::()]>(s) }; + let handle = self.buffer.write(&bytes); + + naming_srv::get(self.desc).unwrap() + } +} diff --git a/src/srv/naming-srv/Cargo.toml b/src/srv/naming-srv/Cargo.toml new file mode 100644 index 00000000..40fe4cef --- /dev/null +++ b/src/srv/naming-srv/Cargo.toml @@ -0,0 +1,18 @@ +[package] +name = "naming-srv" +version = "0.1.0" +edition = "2021" + +# Important: this should be compiled as both an rlib, for exporting the trampoline, +# and as a cdylib, as the actual .so file that will be exporting the gates. +[lib] +crate-type = ["cdylib", "rlib"] + +[dependencies] +lazy_static = "1.5.0" +secgate = { path = "../../lib/secgate" } +twizzler-runtime = { path = "../../rt" } +twizzler-rt-abi = { path = "../../abi/rt-abi" } +twizzler-abi = { path = "../../lib/twizzler-abi" } + +[features] diff --git a/src/srv/naming-srv/src/lib.rs b/src/srv/naming-srv/src/lib.rs new file mode 100644 index 00000000..e4bf5b8c --- /dev/null +++ b/src/srv/naming-srv/src/lib.rs @@ -0,0 +1,174 @@ +#![feature(naked_functions)] +#![feature(linkage)] + +use std::{default, sync::Mutex}; + +use lazy_static::lazy_static; +use secgate::{ + secure_gate, + util::{Descriptor, HandleMgr, SimpleBuffer}, +}; +use twizzler_abi::{ + aux::KernelInitInfo, + object::{ObjID, MAX_SIZE, NULLPAGE_SIZE}, + syscall::{sys_object_create, BackingType, LifetimeType, ObjectCreate, ObjectCreateFlags}, +}; +use twizzler_rt_abi::object::MapFlags; + +fn get_kernel_init_info() -> &'static KernelInitInfo { + unsafe { + (((twizzler_abi::slot::RESERVED_KERNEL_INIT * MAX_SIZE) + NULLPAGE_SIZE) + as *const KernelInitInfo) + .as_ref() + .unwrap() + } +} + +pub struct NamespaceClient { + buffer: SimpleBuffer, +} + +impl NamespaceClient { + fn new() -> Option { + // Create and map a handle for the simple buffer. + let id = sys_object_create( + ObjectCreate::new( + BackingType::Normal, + LifetimeType::Volatile, + None, + ObjectCreateFlags::empty(), + ), + &[], + &[], + ) + .ok()?; + let handle = + twizzler_rt_abi::object::twz_rt_map_object(id, MapFlags::WRITE | MapFlags::READ) + .ok()?; + let buffer = SimpleBuffer::new(handle); + Some(Self { buffer }) + } + + fn sbid(&self) -> ObjID { + self.buffer.handle().id() + } +} + +pub const MAX_KEY_SIZE: usize = 256; + +#[repr(C)] +pub struct Schema { + pub key: [u8; MAX_KEY_SIZE], + pub val: u128, +} + +struct Namer { + handles: HandleMgr, + names: Vec, + count: usize, +} + +impl Namer { + const fn new() -> Self { + Self { + handles: HandleMgr::new(None), + names: Vec::::new(), + count: 0, + } + } +} + +struct NamerSrv { + inner: Mutex, +} + +lazy_static! { + static ref NAMINGSERVICE: NamerSrv = { + let mut namer = Namer::new(); + + let init_info = get_kernel_init_info(); + + for n in init_info.names() { + let mut s = Schema { + key: [0u8; 256], + val: 0, + }; + let bytes = n.name().as_bytes(); + s.key[..bytes.len()].copy_from_slice(&bytes[..bytes.len()]); + s.val = n.id().raw(); + namer.names.push(s); + } + + NamerSrv { + inner: Mutex::new(namer), + } + }; +} + +#[secure_gate(options(info))] +pub fn put(info: &secgate::GateCallInfo, desc: Descriptor) { + let mut namer = NAMINGSERVICE.inner.lock().unwrap(); + let Some(client) = namer + .handles + .lookup(info.source_context().unwrap_or(0.into()), desc) + else { + return; + }; + + // should use buffer rather than copying + let mut buf = [0u8; std::mem::size_of::()]; + client.buffer.read(&mut buf); + let provided = + unsafe { std::mem::transmute::<[u8; std::mem::size_of::()], Schema>(buf) }; + + let foo = namer + .names + .iter_mut() + .find(|search| search.key == provided.key); + match foo { + Some(found) => found.val = provided.val, + None => namer.names.push(provided), + }; +} + +#[secure_gate(options(info))] +pub fn get(info: &secgate::GateCallInfo, desc: Descriptor) -> Option { + let mut namer = NAMINGSERVICE.inner.lock().unwrap(); + let Some(client) = namer + .handles + .lookup(info.source_context().unwrap_or(0.into()), desc) + else { + return None; + }; + + let mut buf = [0u8; std::mem::size_of::()]; + client.buffer.read(&mut buf); + let provided = + unsafe { std::mem::transmute::<[u8; std::mem::size_of::()], Schema>(buf) }; + + let foo: Option<&Schema> = namer.names.iter().find(|search| search.key == provided.key); + match foo { + Some(found) => Some(found.val), + None => None, + } +} + +#[secure_gate(options(info))] +pub fn open_handle(info: &secgate::GateCallInfo) -> Option<(Descriptor, ObjID)> { + let mut namer = NAMINGSERVICE.inner.lock().ok()?; + let client = NamespaceClient::new()?; + let id = client.sbid(); + let desc = namer + .handles + .insert(info.source_context().unwrap_or(0.into()), client)?; + + Some((desc, id)) +} + +#[secure_gate(options(info))] +pub fn close_handle(info: &secgate::GateCallInfo, desc: Descriptor) { + let mut namer = NAMINGSERVICE.inner.lock().unwrap(); + namer + .handles + .remove(info.source_context().unwrap_or(0.into()), desc); +}