Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Security Monitor (2) #200

Merged
merged 6 commits into from
Aug 21, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
68 changes: 61 additions & 7 deletions src/runtime/monitor/secapi/gates.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,12 @@ pub fn monitor_rt_spawn_thread(
thread_pointer: usize,
stack_pointer: usize,
) -> Result<ObjID, SpawnError> {
crate::thread::__monitor_rt_spawn_thread(
let monitor = crate::mon::get_monitor();
monitor.spawn_compartment_thread(
info.source_context().unwrap_or(0.into()),
args,
thread_pointer,
stack_pointer,
thread_pointer,
)
}

Expand All @@ -28,7 +29,12 @@ pub fn monitor_rt_spawn_thread(
secgate::secure_gate(options(info, api))
)]
pub fn monitor_rt_get_comp_config(info: &secgate::GateCallInfo) -> usize {
crate::thread::__monitor_rt_get_comp_config(info.source_context().unwrap_or(0.into())) as usize
use crate::api::MONITOR_INSTANCE_ID;
let monitor = crate::mon::get_monitor();
monitor
.get_comp_config(info.source_context().unwrap_or(MONITOR_INSTANCE_ID))
.map(|ptr| ptr as usize)
.unwrap_or(0)
}

#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
Expand Down Expand Up @@ -66,15 +72,63 @@ pub fn monitor_rt_object_map(
info: &secgate::GateCallInfo,
id: ObjID,
flags: twizzler_runtime_api::MapFlags,
) -> Result<usize, MapError> {
crate::object::map_object(info, id, flags)
) -> Result<crate::MappedObjectAddrs, MapError> {
use twz_rt::{RuntimeState, OUR_RUNTIME};

use crate::{api::MONITOR_INSTANCE_ID, mon::space::MapInfo};
if OUR_RUNTIME.state().contains(RuntimeState::READY) {
// Are we recursing from the monitor, with a lock held? In that case, use early_object_map
// to map the object. This will leak this mapping, but this is both rare, and then
// since the mapping is leaked, it can be used as an allocator object indefinitely
// (not currently implemented). Make sure the ThreadKey drops.
let is_monitor_recursed =
{ happylock::ThreadKey::get().is_none() && info.source_context().is_none() };
if is_monitor_recursed {
tracing::debug!(
"performing early object mapping (recursed), {} {:?}",
id,
flags
);
return Ok(crate::mon::early_object_map(MapInfo { id, flags }));
}
let monitor = crate::mon::get_monitor();
monitor
.map_object(
info.source_context().unwrap_or(MONITOR_INSTANCE_ID),
MapInfo { id, flags },
)
.map(|handle| handle.addrs())
} else {
// We need to use early_object_map, since the monitor hasn't finished initializing, but
// still needs to allocate (which may involve mapping an object).
tracing::debug!("performing early object mapping, {} {:?}", id, flags);
Ok(crate::mon::early_object_map(MapInfo { id, flags }))
}
}

#[cfg_attr(feature = "secgate-impl", secgate::secure_gate(options(info)))]
#[cfg_attr(
not(feature = "secgate-impl"),
secgate::secure_gate(options(info, api))
)]
pub fn monitor_rt_object_unmap(info: &secgate::GateCallInfo, slot: usize) {
crate::object::unmap_object(info, slot)
pub fn monitor_rt_object_unmap(
info: &secgate::GateCallInfo,
_slot: usize,
id: ObjID,
flags: twizzler_runtime_api::MapFlags,
) {
use twz_rt::{RuntimeState, OUR_RUNTIME};
if OUR_RUNTIME.state().contains(RuntimeState::READY) {
let monitor = crate::mon::get_monitor();
let key = happylock::ThreadKey::get().unwrap();
monitor
.comp_mgr
.write(key)
.get_mut(
info.source_context()
.unwrap_or(crate::api::MONITOR_INSTANCE_ID),
)
.unwrap()
.unmap_object(crate::mon::space::MapInfo { id, flags })
}
}
133 changes: 15 additions & 118 deletions src/runtime/monitor/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,22 +4,15 @@
#![feature(new_uninit)]
#![feature(hash_extract_if)]

use std::sync::{Arc, Mutex};

use dynlink::{engines::Backing, symbol::LookupFlags};
use state::MonitorState;
use tracing::{debug, info, trace, warn, Level};
use dynlink::engines::Backing;
use tracing::{debug, info, warn, Level};
use tracing_subscriber::{fmt::format::FmtSpan, FmtSubscriber};
use twizzler_abi::{
aux::KernelInitInfo,
object::{MAX_SIZE, NULLPAGE_SIZE},
syscall::{sys_object_create, ObjectCreate},
};
use twizzler_object::ObjID;
use twizzler_runtime_api::AuxEntry;
use twz_rt::{set_upcall_handler, CompartmentInitInfo};

use crate::{compartment::Comp, state::set_monitor_state};
use twz_rt::{set_upcall_handler, OUR_RUNTIME};

mod compartment;
mod init;
Expand All @@ -33,6 +26,8 @@ mod upcall;
mod api;
mod mon;

pub use monitor_api::MappedObjectAddrs;

#[path = "../secapi/gates.rs"]
mod gates;

Expand All @@ -51,130 +46,32 @@ pub fn main() {
}))
.unwrap();

trace!("monitor entered, discovering dynlink context");
debug!("monitor entered, discovering dynlink context");
let init =
init::bootstrap_dynlink_context().expect("failed to discover initial dynlink context");
let mut state = state::MonitorState::new(init);

let monitor_comp_id = state.dynlink.lookup_compartment("monitor").unwrap();
let monitor_comp = Comp::new(
0.into(),
state.dynlink.get_compartment_mut(monitor_comp_id).unwrap(),
)
.unwrap();
state.add_comp(monitor_comp, twizzler_runtime_api::LibraryId(0));
let mon = mon::Monitor::new(init);
mon::set_monitor(mon);

let state = Arc::new(Mutex::new(state));
tracing::info!(".. state: {:p}", state);
debug!(
"found dynlink context, with root {}",
state.lock().unwrap().root
);
// Safety: the monitor is ready, and so we can set our runtime as ready to use the monitor.
unsafe { OUR_RUNTIME.set_runtime_ready() };
// Had to wait till now to be able to spawn threads.
mon::get_monitor().start_background_threads();

debug!("Ok");
std::env::set_var("RUST_BACKTRACE", "1");

set_upcall_handler(&crate::upcall::upcall_monitor_handler).unwrap();
set_monitor_state(state.clone());

let main_thread = std::thread::spawn(|| monitor_init(state));
let main_thread = std::thread::spawn(|| monitor_init());
let _r = main_thread.join().unwrap().map_err(|e| {
tracing::error!("{:?}", e);
});
warn!("monitor main thread exited");
}

fn monitor_init(state: Arc<Mutex<MonitorState>>) -> miette::Result<()> {
fn monitor_init() -> miette::Result<()> {
info!("monitor early init completed, starting init");

{
let state = state.lock().unwrap();
let comp = state.dynlink.lookup_compartment("monitor").unwrap();
let mon = state.dynlink.lookup_library(comp, "libmonitor.so").unwrap();

let mon = state.dynlink.get_library(mon)?;

for gate in mon.iter_secgates().unwrap() {
let name = gate.name().to_string_lossy();
info!("secure gate in {} => {}: {:x}", mon.name, name, gate.imp);
}
}

load_hello_world_test(&state).unwrap();

Ok(())
}

fn load_hello_world_test(state: &Arc<Mutex<MonitorState>>) -> miette::Result<()> {
let lib = dynlink::library::UnloadedLibrary::new("hello-world");
let rt_lib = dynlink::library::UnloadedLibrary::new("libtwz_rt.so");

let mut state = state.lock().unwrap();
let test_comp_id = state.dynlink.add_compartment("test")?;

let libhw_id = state
.dynlink
.load_library_in_compartment(test_comp_id, lib)?;

let rt_id = match state
.dynlink
.load_library_in_compartment(test_comp_id, rt_lib)
{
Ok(rt_id) => {
state.dynlink.add_manual_dependency(libhw_id, rt_id);
rt_id
}
Err(_) => state
.dynlink
.lookup_library(test_comp_id, "libtwz_rt.so")
.unwrap(),
};

println!("found rt_id: {}", rt_id);
let rt_lib = state.dynlink.get_library(rt_id).unwrap();

drop(rt_lib);

state.dynlink.relocate_all(libhw_id)?;

let test_comp = Comp::new(
1.into(),
state.dynlink.get_compartment_mut(test_comp_id).unwrap(),
)
.unwrap();

info!("!! root = {}", libhw_id);
let ctors = state.dynlink.build_ctors_list(libhw_id).unwrap();

let rtinfo = CompartmentInitInfo {
ctor_array_start: ctors.as_ptr() as usize,
ctor_array_len: ctors.len(),
comp_config_addr: test_comp.get_comp_config() as *const _ as usize,
};
state.add_comp(test_comp, libhw_id.into());

info!("lookup entry");

let rt_lib = state.dynlink.get_library(rt_id).unwrap();
let entry = rt_lib.get_entry_address().unwrap();

let aux = [
AuxEntry::RuntimeInfo(&rtinfo as *const _ as usize, 1),
AuxEntry::Null,
];
println!("==> {:p}", entry);
drop(state);
entry(aux.as_ptr());
/*
let sym = state
.dynlink
.lookup_symbol(libhw_id, "test_sec_call", LookupFlags::empty())?;

let addr = sym.reloc_value();
info!("addr = {:x}", addr);
let ptr: extern "C" fn() = unsafe { core::mem::transmute(addr as usize) };
(ptr)();
*/

Ok(())
}

Expand Down
5 changes: 4 additions & 1 deletion src/runtime/monitor/src/mon/compartment.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,17 @@ use std::collections::HashMap;

use twizzler_runtime_api::ObjID;

use self::runcomp::RunComp;
use crate::api::MONITOR_INSTANCE_ID;

mod compconfig;
mod compthread;
mod runcomp;

pub use compconfig::*;
pub use runcomp::*;

/// Manages compartments.
#[derive(Default)]
pub struct CompartmentMgr {
names: HashMap<String, ObjID>,
instances: HashMap<ObjID, RunComp>,
Expand Down
35 changes: 33 additions & 2 deletions src/runtime/monitor/src/mon/compartment/runcomp.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,35 @@ pub struct RunComp {
}

impl RunComp {
pub fn new(
sctx: ObjID,
instance: ObjID,
name: String,
compartment_id: CompartmentId,
deps: Vec<ObjID>,
comp_config_object: CompConfigObject,
flags: u64,
) -> Self {
let mut alloc = Talc::new(ErrOnOom);
unsafe { alloc.claim(comp_config_object.alloc_span()).unwrap() };
Self {
sctx,
instance,
name,
compartment_id,
main: None,
deps,
comp_config_object,
alloc,
mapped_objects: HashMap::default(),
flags: Box::new(AtomicU64::new(flags)),
}
}

/// Map an object into this compartment.
pub fn map_object(&mut self, info: MapInfo) -> Result<MapHandle, MapError> {
todo!()
pub fn map_object(&mut self, info: MapInfo, handle: MapHandle) -> Result<MapHandle, MapError> {
self.mapped_objects.insert(info, handle.clone());
Ok(handle)
}

/// Unmap and object from this compartment.
Expand All @@ -59,6 +85,11 @@ impl RunComp {
self.comp_config_object.read_comp_config()
}

/// Get a pointer to the compartment config.
pub fn comp_config_ptr(&self) -> *const SharedCompConfig {
self.comp_config_object.get_comp_config()
}

/// Set the compartment config.
pub fn set_comp_config(&mut self, scc: SharedCompConfig) {
self.comp_config_object.write_config(scc)
Expand Down
Loading
Loading