Skip to content

Commit

Permalink
Add example logging service for monitor secure gates (#223)
Browse files Browse the repository at this point in the history
* Fixing linking errors.

* Allow self-reference for monitor.

* Reorg and cleanup.
  • Loading branch information
dbittman authored Dec 3, 2024
1 parent 8d80b8c commit 5dfcdff
Show file tree
Hide file tree
Showing 23 changed files with 269 additions and 65 deletions.
25 changes: 25 additions & 0 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

5 changes: 5 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,9 @@ members = [
"src/runtime/minruntime",
"src/abi/rt-abi",
"src/abi/types",
"src/srv/logboi",
"src/srv/logboi/logboi-srv",
"src/srv/logboi/logboi-test",
]

exclude = ["toolchain/src/rust"]
Expand All @@ -51,6 +54,8 @@ initrd = [
"lib:montest-lib",
"crate:mnemosyne",
"crate:stdfs_demo",
"crate:logboi-test",
"lib:logboi-srv",
#"third-party:hello-world-rs"
]

Expand Down
4 changes: 2 additions & 2 deletions src/bin/bootstrap/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ use dynlink::{
compartment::MONITOR_COMPARTMENT_ID,
context::{runtime::RuntimeInitInfo, NewCompartmentFlags},
engines::{Backing, ContextEngine},
library::UnloadedLibrary,
library::{AllowedGates, UnloadedLibrary},
symbol::LookupFlags,
DynlinkError, DynlinkErrorKind,
};
Expand Down Expand Up @@ -74,7 +74,7 @@ fn start_runtime(_runtime_monitor: ObjID, _runtime_library: ObjID) -> ! {
.unwrap();

let monitor_id = ctx
.load_library_in_compartment(monitor_comp_id, unlib, true)
.load_library_in_compartment(monitor_comp_id, unlib, AllowedGates::PublicInclSelf)
.unwrap()[0]
.lib;

Expand Down
2 changes: 1 addition & 1 deletion src/kernel/src/initrd.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,7 +65,7 @@ pub fn init(modules: &[BootModule]) {
}
let obj = Arc::new(obj);
obj::register_object(obj.clone());
if e.filename().as_str() == "bootstrap" {
if e.filename().as_str() == "init" {
boot_objects.init = Some(obj.clone());
}
boot_objects
Expand Down
21 changes: 13 additions & 8 deletions src/runtime/dynlink/src/context/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ use crate::{
compartment::{Compartment, CompartmentId},
context::NewCompartmentFlags,
engines::{LoadDirective, LoadFlags},
library::{Library, LibraryId, SecgateInfo, UnloadedLibrary},
library::{AllowedGates, Library, LibraryId, SecgateInfo, UnloadedLibrary},
tls::TlsModule,
DynlinkError, DynlinkErrorKind, HeaderError,
};
Expand Down Expand Up @@ -128,7 +128,7 @@ impl Context {
comp_id: CompartmentId,
unlib: UnloadedLibrary,
idx: NodeIndex,
allows_gates: bool,
allowed_gates: AllowedGates,
) -> Result<Library, DynlinkError> {
let backing = self.engine.load_object(&unlib)?;
let elf = backing.get_elf()?;
Expand Down Expand Up @@ -279,7 +279,7 @@ impl Context {
tls_id,
ctor_info,
secgate_info,
allows_gates,
allowed_gates,
))
}

Expand Down Expand Up @@ -340,7 +340,7 @@ impl Context {
comp_id: CompartmentId,
root_unlib: UnloadedLibrary,
idx: NodeIndex,
allows_gates: bool,
allowed_gates: AllowedGates,
) -> Result<Vec<LoadIds>, DynlinkError> {
let root_comp_name = self.get_compartment(comp_id)?.name.clone();
debug!(
Expand All @@ -350,7 +350,7 @@ impl Context {
let mut ids = vec![];
// First load the main library.
let lib = self
.load(comp_id, root_unlib.clone(), idx, allows_gates)
.load(comp_id, root_unlib.clone(), idx, allowed_gates)
.map_err(|e| {
DynlinkError::new_collect(
DynlinkErrorKind::LibraryLoadFail {
Expand Down Expand Up @@ -418,8 +418,13 @@ impl Context {

let comp = self.get_compartment_mut(load_comp)?;
comp.library_names.insert(dep_unlib.name.clone(), idx);
let allowed_gates = if comp.id == comp_id {
AllowedGates::Private
} else {
AllowedGates::Public
};
let mut recs = self
.load_library(load_comp, dep_unlib.clone(), idx, false)
.load_library(load_comp, dep_unlib.clone(), idx, allowed_gates)
.map_err(|e| {
DynlinkError::new_collect(
DynlinkErrorKind::LibraryLoadFail {
Expand Down Expand Up @@ -453,7 +458,7 @@ impl Context {
&mut self,
comp_id: CompartmentId,
unlib: UnloadedLibrary,
allows_gates: bool,
allowed_gates: AllowedGates,
) -> Result<Vec<LoadIds>, DynlinkError> {
let idx = self.add_library(unlib.clone());
// Step 1: insert into the compartment's library names.
Expand All @@ -469,6 +474,6 @@ impl Context {
comp.library_names.insert(unlib.name.clone(), idx);

// Step 2: load the library. This call recurses on dependencies.
self.load_library(comp_id, unlib.clone(), idx, allows_gates)
self.load_library(comp_id, unlib.clone(), idx, allowed_gates)
}
}
14 changes: 8 additions & 6 deletions src/runtime/dynlink/src/context/syms.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
use tracing::trace;

use super::{Context, LoadedOrUnloaded};
use crate::{
library::{Library, LibraryId},
Expand All @@ -21,7 +19,7 @@ impl Context {
let start_lib = self.get_library(start_id)?;
// First try looking up within ourselves.
if !lookup_flags.contains(LookupFlags::SKIP_SELF) {
if let Ok(sym) = start_lib.lookup_symbol(name, allow_weak) {
if let Ok(sym) = start_lib.lookup_symbol(name, allow_weak, false) {
return Ok(sym);
}
}
Expand All @@ -40,7 +38,9 @@ impl Context {
{
let allow_weak =
allow_weak && dep.in_same_compartment_as(start_lib);
if let Ok(sym) = dep.lookup_symbol(name, allow_weak) {
let try_prefix =
dep.in_same_compartment_as(start_lib) || dep.allows_gates();
if let Ok(sym) = dep.lookup_symbol(name, allow_weak, try_prefix) {
return Ok(sym);
}
}
Expand All @@ -52,7 +52,7 @@ impl Context {

// Fall back to global search.
if !lookup_flags.contains(LookupFlags::SKIP_GLOBAL) {
trace!("falling back to global search for {}", name);
tracing::trace!("falling back to global search for {}", name);

let res = self.lookup_symbol_global(start_lib, name, lookup_flags);
if res.is_ok() {
Expand Down Expand Up @@ -89,7 +89,9 @@ impl Context {
{
let allow_weak = lookup_flags.contains(LookupFlags::ALLOW_WEAK)
&& dep.in_same_compartment_as(start_lib);
if let Ok(sym) = dep.lookup_symbol(name, allow_weak) {
let try_prefix = (idx != start_lib.id().0 || dep.allows_self_gates())
&& (dep.allows_gates() || dep.in_same_compartment_as(start_lib));
if let Ok(sym) = dep.lookup_symbol(name, allow_weak, try_prefix) {
return Ok(sym);
}
}
Expand Down
75 changes: 66 additions & 9 deletions src/runtime/dynlink/src/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,16 @@ pub(crate) enum RelocState {
Relocated,
}

#[derive(PartialEq, PartialOrd, Ord, Eq, Debug, Clone, Copy)]
pub enum AllowedGates {
/// Gates are not exported
Private,
/// Gates are exported to other compartments only
Public,
/// Gates are exported to all compartments
PublicInclSelf,
}

#[repr(C)]
/// An unloaded library. It's just a name, really.
#[derive(Debug, Clone, PartialEq, PartialOrd, Ord, Eq, Hash)]
Expand Down Expand Up @@ -84,7 +94,7 @@ pub struct Library {
pub full_obj: Backing,
/// State of relocation.
pub(crate) reloc_state: RelocState,
allows_gates: bool,
allowed_gates: AllowedGates,

pub backings: Vec<Backing>,

Expand All @@ -108,7 +118,7 @@ impl Library {
tls_id: Option<TlsModId>,
ctors: CtorSet,
secgate_info: SecgateInfo,
allows_gates: bool,
allowed_gates: AllowedGates,
) -> Self {
Self {
name,
Expand All @@ -121,11 +131,16 @@ impl Library {
comp_id,
comp_name,
secgate_info,
allows_gates,
allowed_gates,
}
}

pub fn allows_gates(&self) -> bool {
self.allows_gates
self.allowed_gates != AllowedGates::Private
}

pub fn allows_self_gates(&self) -> bool {
self.allowed_gates == AllowedGates::PublicInclSelf
}

pub fn is_binary(&self) -> bool {
Expand Down Expand Up @@ -228,13 +243,29 @@ impl Library {
}))
}

pub(crate) fn lookup_symbol(
fn do_lookup_symbol(
&self,
name: &str,
allow_weak: bool,
) -> Result<RelocatedSymbol<'_>, DynlinkError> {
let elf = self.get_elf()?;
let common = elf.find_common_data()?;
tracing::trace!("lookup {} in {}", name, self.name);

/*
if self.is_relocated() {
if let Some(gates) = self.iter_secgates() {
for sc in gates {
if let Ok(gname) = sc.name().to_str() {
if gname == name {
tracing::info!("found as secure gate");
return Ok(RelocatedSymbol::new_sc(sc.imp, self));
}
}
}
}
}
*/

// Try the GNU hash table, if present.
if let Some(h) = &common.gnu_hash {
Expand All @@ -258,7 +289,10 @@ impl Library {
{
if !sym.is_undefined() {
// TODO: proper weak symbol handling.
if sym.st_bind() != STB_WEAK || allow_weak {
if sym.st_bind() != STB_WEAK
|| allow_weak
|| (self.is_relocated() && self.is_secgate(name))
{
return Ok(RelocatedSymbol::new(sym, self));
} else {
tracing::debug!("lookup symbol {} skipping weak binding in {}", name, self);
Expand Down Expand Up @@ -295,7 +329,10 @@ impl Library {
{
if !sym.is_undefined() {
// TODO: proper weak symbol handling.
if sym.st_bind() != STB_WEAK {
if sym.st_bind() != STB_WEAK
|| allow_weak
|| (self.is_relocated() && self.is_secgate(name))
{
return Ok(RelocatedSymbol::new(sym, self));
} else {
tracing::info!("lookup symbol {} skipping weak binding in {}", name, self);
Expand All @@ -305,21 +342,41 @@ impl Library {
}
}
}

Err(DynlinkErrorKind::NameNotFound {
name: name.to_string(),
}
.into())
}

pub(crate) fn lookup_symbol(
&self,
name: &str,
allow_weak: bool,
allow_prefix: bool,
) -> Result<RelocatedSymbol<'_>, DynlinkError> {
let ret = self.do_lookup_symbol(&name, allow_weak);
if allow_prefix && ret.is_err() && !name.starts_with("__TWIZZLER_SECURE_GATE_") {
let name = format!("__TWIZZLER_SECURE_GATE_{}", name);
if let Ok(o) = self.do_lookup_symbol(&name, allow_weak) {
return Ok(o);
}
}
ret
}

pub(crate) fn is_local_or_secgate_from(&self, other: &Library, name: &str) -> bool {
self.in_same_compartment_as(other)
|| (self.reloc_state == RelocState::Relocated && self.is_secgate(name))
self.in_same_compartment_as(other) || (self.is_relocated() && self.is_secgate(name))
}

pub(crate) fn in_same_compartment_as(&self, other: &Library) -> bool {
other.comp_id == self.comp_id
}

pub fn is_relocated(&self) -> bool {
self.reloc_state == RelocState::Relocated
}

fn is_secgate(&self, name: &str) -> bool {
self.iter_secgates()
.map(|gates| {
Expand Down
2 changes: 1 addition & 1 deletion src/runtime/dynlink/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ impl<'lib> RelocatedSymbol<'lib> {
/// Returns the relocated address of the symbol, i.e. the value of the symbol added to the base
/// address of the library it comes from.
pub fn reloc_value(&self) -> u64 {
self.sym.st_value + self.lib.base_addr() as u64
self.raw_value() + self.lib.base_addr() as u64
}

/// Returns the raw symbol value (unrelocated).
Expand Down
1 change: 1 addition & 0 deletions src/runtime/monitor-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
//! dependency.
#![feature(naked_functions)]
#![feature(linkage)]
#![feature(result_flattening)]
#![feature(thread_local)]
#![feature(pointer_is_aligned_to)]
Expand Down
Loading

0 comments on commit 5dfcdff

Please sign in to comment.