Skip to content

Commit

Permalink
Add support for compartments to dynamic linker and monitor, part 1/N (#…
Browse files Browse the repository at this point in the history
…173)

* Fix debug runtime in twzrt to use sec call to monitor.

* Move object slot management to monitor runtime only.

* Support library info reading for debugging.
  • Loading branch information
dbittman authored Apr 3, 2024
1 parent 68aee81 commit 47bcd88
Show file tree
Hide file tree
Showing 29 changed files with 479 additions and 165 deletions.
1 change: 1 addition & 0 deletions Cargo.lock

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

4 changes: 2 additions & 2 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ initrd = [
"crate:netmgr",
"crate:nettest",
"crate:pager",
"lib:twz-rt",
"lib:monitor",
#"lib:twz-rt",
#"lib:monitor",
#"third-party:hello-world-rs"
]

Expand Down
2 changes: 1 addition & 1 deletion rust-toolchain
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
[toolchain]
channel = 'nightly-2023-09-19'
channel = 'nightly-2024-01-01'
components = [ "rustfmt", "clippy", "cargo", "rust-src" ]
13 changes: 6 additions & 7 deletions src/lib/twizzler-abi/src/runtime/debug.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Null implementation of the debug runtime.
use twizzler_runtime_api::{DebugRuntime, Library, LibraryId, MapFlags};
use twizzler_runtime_api::{AddrRange, DebugRuntime, Library, LibraryId, MapFlags};

use crate::object::{InternalObject, ObjID, Protections, NULLPAGE_SIZE};
use crate::object::{InternalObject, ObjID, Protections, MAX_SIZE, NULLPAGE_SIZE};

use super::{
MinimalRuntime, __twz_get_runtime,
Expand All @@ -28,7 +28,10 @@ impl DebugRuntime for MinimalRuntime {
.map_object(get_execid().as_u128(), MapFlags::READ)
.ok()?;
Some(Library {
range: (unsafe { mapping.start.add(NULLPAGE_SIZE) }, mapping.meta),
range: AddrRange {
start: mapping.start as usize + NULLPAGE_SIZE,
len: MAX_SIZE - NULLPAGE_SIZE,
},
mapping,
dl_info: None,
next_id: None,
Expand Down Expand Up @@ -71,8 +74,4 @@ impl DebugRuntime for MinimalRuntime {
) -> core::ffi::c_int {
0
}

fn get_library_name(&self, _lib: &Library, _buf: &mut [u8]) -> Option<usize> {
Some(0)
}
}
21 changes: 13 additions & 8 deletions src/lib/twizzler-runtime-api/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -230,7 +230,7 @@ pub enum MapError {

bitflags::bitflags! {
/// Mapping protections for mapping objects into the address space.
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct MapFlags: u32 {
/// Read allowed.
const READ = 1;
Expand All @@ -245,7 +245,8 @@ bitflags::bitflags! {
/// A handle to an internal object. This has similar semantics to Arc, but since this crate
/// must be #[no_std], we need to implement refcounting ourselves.
pub struct ObjectHandle {
internal_refs: NonNull<InternalHandleRefs>,
/// Pointer to refcounter.
pub internal_refs: NonNull<InternalHandleRefs>,
/// The ID of the object.
pub id: ObjID,
/// The flags of this handle.
Expand Down Expand Up @@ -489,10 +490,10 @@ pub struct Library {
/// How this library is mapped.
pub mapping: ObjectHandle,
/// Actual range of addresses that comprise the library binary data.
pub range: (*const u8, *const u8),
pub range: AddrRange,
/// Information for dl_iterate_phdr
pub dl_info: Option<DlPhdrInfo>,
/// The Library ID of the next library, either the first dependency of this library, or a sibling.
/// The Library ID of first dependency.
pub next_id: Option<LibraryId>,
}

Expand All @@ -502,6 +503,12 @@ impl AsRef<Library> for Library {
}
}

impl Library {
pub fn name(&self) -> Option<&CStr> {
unsafe { Some(CStr::from_ptr(self.dl_info?.name as *const i8)) }
}
}

#[repr(transparent)]
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
/// Internal library ID type.
Expand All @@ -516,7 +523,7 @@ pub type ElfAddr = usize;
#[cfg(any(target_arch = "x86_64", target_arch = "aarch64"))]
pub type ElfHalf = u32;

#[derive(Copy, Clone)]
#[derive(Copy, Clone, Debug)]
#[repr(C)]
pub struct DlPhdrInfo {
pub addr: ElfAddr,
Expand All @@ -533,9 +540,6 @@ pub struct DlPhdrInfo {
pub trait DebugRuntime {
/// Gets a handle to a library given the ID.
fn get_library(&self, id: LibraryId) -> Option<Library>;
/// Get library name. If the buffer is too small, returns Err(()). Otherwise,
/// returns the length of the name in bytes.
fn get_library_name(&self, lib: &Library, buf: &mut [u8]) -> Option<usize>;
/// Returns the ID of the main executable, if there is one.
fn get_exeid(&self) -> Option<LibraryId>;
/// Get a segment of a library, if the segment index exists. All segment IDs are indexes, so they range from [0, N).
Expand All @@ -546,6 +550,7 @@ pub trait DebugRuntime {
fn iterate_phdr(&self, f: &mut dyn FnMut(DlPhdrInfo) -> core::ffi::c_int) -> core::ffi::c_int;
}

#[derive(Clone, Copy, Debug, PartialEq, PartialOrd, Ord, Eq)]
/// An address range.
pub struct AddrRange {
/// Starting virtual address.
Expand Down
33 changes: 31 additions & 2 deletions src/runtime/dynlink/src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,12 +199,20 @@ impl<Engine: ContextEngine> Context<Engine> {
}
}

pub fn libraries(&self) -> LibraryIter<'_, Engine> {
LibraryIter { ctx: self, next: 0 }
}

pub(crate) fn add_library(&mut self, lib: UnloadedLibrary) -> NodeIndex {
self.library_deps.add_node(LoadedOrUnloaded::Unloaded(lib))
}

pub(crate) fn add_dep(&mut self, parent: &Library<Engine::Backing>, dep: NodeIndex) {
self.library_deps.add_edge(parent.idx, dep, ());
pub(crate) fn add_dep(&mut self, parent: NodeIndex, dep: NodeIndex) {
self.library_deps.add_edge(parent, dep, ());
}

pub fn add_manual_dependency(&mut self, parent: LibraryId, dependee: LibraryId) {
self.add_dep(parent.0, dependee.0);
}

/// Create a new compartment with a given name.
Expand All @@ -217,3 +225,24 @@ impl<Engine: ContextEngine> Context<Engine> {
Ok(CompartmentId(idx))
}
}

pub struct LibraryIter<'a, Engine: ContextEngine> {
ctx: &'a Context<Engine>,
next: usize,
}

impl<'a, Engine: ContextEngine> Iterator for LibraryIter<'a, Engine> {
type Item = &'a Library<Engine::Backing>;

fn next(&mut self) -> Option<Self::Item> {
loop {
let idx = self.ctx.library_deps.node_indices().nth(self.next)?;
self.next += 1;
let node = &self.ctx.library_deps[idx];
match node {
LoadedOrUnloaded::Unloaded(_) => {}
LoadedOrUnloaded::Loaded(lib) => return Some(lib),
}
}
}
}
3 changes: 2 additions & 1 deletion src/runtime/dynlink/src/context/load.rs
Original file line number Diff line number Diff line change
Expand Up @@ -256,6 +256,7 @@ impl<Engine: ContextEngine> Context<Engine> {
Ok(Library::new(
unlib.name,
idx,
comp.id,
comp.name.clone(),
backing,
backings,
Expand Down Expand Up @@ -373,7 +374,7 @@ impl<Engine: ContextEngine> Context<Engine> {
)
})?
};
self.add_dep(&lib, idx);
self.add_dep(lib.idx, idx);
Ok(idx)
})
.collect::<Vec<Result<_, DynlinkError>>>();
Expand Down
24 changes: 17 additions & 7 deletions src/runtime/dynlink/src/context/syms.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
use tracing::trace;

use crate::{
library::LibraryId,
library::{Library, LibraryId},
symbol::{LookupFlags, RelocatedSymbol},
DynlinkError, DynlinkErrorKind,
};
Expand All @@ -17,9 +17,9 @@ impl<Engine: ContextEngine> Context<Engine> {
name: &str,
lookup_flags: LookupFlags,
) -> Result<RelocatedSymbol<'a, Engine::Backing>, DynlinkError> {
let start_lib = self.get_library(start_id)?;
// First try looking up within ourselves.
if !lookup_flags.contains(LookupFlags::SKIP_SELF) {
let start_lib = self.get_library(start_id)?;
if let Ok(sym) = start_lib.lookup_symbol(name) {
return Ok(sym);
}
Expand All @@ -34,8 +34,12 @@ impl<Engine: ContextEngine> Context<Engine> {
match dep {
LoadedOrUnloaded::Unloaded(_) => {}
LoadedOrUnloaded::Loaded(dep) => {
if let Ok(sym) = dep.lookup_symbol(name) {
return Ok(sym);
if lookup_flags.contains(LookupFlags::SKIP_SECGATE_CHECK)
|| dep.is_local_or_secgate_from(start_lib, name)
{
if let Ok(sym) = dep.lookup_symbol(name) {
return Ok(sym);
}
}
}
}
Expand All @@ -46,7 +50,7 @@ impl<Engine: ContextEngine> Context<Engine> {
// Fall back to global search.
if !lookup_flags.contains(LookupFlags::SKIP_GLOBAL) {
trace!("falling back to global search for {}", name);
self.lookup_symbol_global(name)
self.lookup_symbol_global(start_lib, name, lookup_flags)
} else {
Err(DynlinkErrorKind::NameNotFound {
name: name.to_string(),
Expand All @@ -57,15 +61,21 @@ impl<Engine: ContextEngine> Context<Engine> {

pub(crate) fn lookup_symbol_global<'a>(
&'a self,
start_lib: &Library<Engine::Backing>,
name: &str,
lookup_flags: LookupFlags,
) -> Result<RelocatedSymbol<'a, Engine::Backing>, DynlinkError> {
for idx in self.library_deps.node_indices() {
let dep = &self.library_deps[idx];
match dep {
LoadedOrUnloaded::Unloaded(_) => {}
LoadedOrUnloaded::Loaded(dep) => {
if let Ok(sym) = dep.lookup_symbol(name) {
return Ok(sym);
if lookup_flags.contains(LookupFlags::SKIP_SECGATE_CHECK)
|| dep.is_local_or_secgate_from(start_lib, name)
{
if let Ok(sym) = dep.lookup_symbol(name) {
return Ok(sym);
}
}
}
}
Expand Down
4 changes: 4 additions & 0 deletions src/runtime/dynlink/src/engines/twizzler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,10 @@ impl BackingData for Backing {
fn to_inner(self) -> Self::InnerType {
self.obj
}

fn inner(&self) -> &Self::InnerType {
&self.obj
}
}

pub struct Engine;
Expand Down
45 changes: 42 additions & 3 deletions src/runtime/dynlink/src/library.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,10 @@ use elf::{
use petgraph::stable_graph::NodeIndex;
use secgate::RawSecGateInfo;

use crate::{symbol::RelocatedSymbol, tls::TlsModId, DynlinkError, DynlinkErrorKind};
use crate::{
compartment::CompartmentId, symbol::RelocatedSymbol, tls::TlsModId, DynlinkError,
DynlinkErrorKind,
};

pub(crate) enum RelocState {
/// Relocation has not started.
Expand Down Expand Up @@ -41,6 +44,7 @@ pub trait BackingData: Clone {
type InnerType;
/// Get the inner implementation type.
fn to_inner(self) -> Self::InnerType;
fn inner(&self) -> &Self::InnerType;

/// Get the ELF file for this backing.
fn get_elf(&self) -> Result<elf::ElfBytes<'_, NativeEndian>, ParseError> {
Expand Down Expand Up @@ -69,6 +73,18 @@ impl UnloadedLibrary {
#[repr(transparent)]
pub struct LibraryId(pub(crate) NodeIndex);

impl From<twizzler_runtime_api::LibraryId> for LibraryId {
fn from(value: twizzler_runtime_api::LibraryId) -> Self {
LibraryId(NodeIndex::new(value.0))
}
}

impl Into<twizzler_runtime_api::LibraryId> for LibraryId {
fn into(self) -> twizzler_runtime_api::LibraryId {
twizzler_runtime_api::LibraryId(self.0.index())
}
}

impl Display for LibraryId {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{}", &self.0.index())
Expand All @@ -82,8 +98,10 @@ pub struct Library<Backing: BackingData> {
pub name: String,
/// Node index for the dependency graph.
pub(crate) idx: NodeIndex,
/// Compartment name this library is loaded in.
pub(crate) comp_name: String,
/// Compartment ID this library is loaded in.
pub(crate) comp_id: CompartmentId,
/// Just for debug and logging purposes.
comp_name: String,
/// Object containing the full ELF data.
pub full_obj: Backing,
/// State of relocation.
Expand All @@ -104,6 +122,7 @@ impl<Backing: BackingData> Library<Backing> {
pub(crate) fn new(
name: String,
idx: NodeIndex,
comp_id: CompartmentId,
comp_name: String,
full_obj: Backing,
backings: Vec<Backing>,
Expand All @@ -119,6 +138,7 @@ impl<Backing: BackingData> Library<Backing> {
tls_id,
ctors,
reloc_state: RelocState::Unrelocated,
comp_id,
comp_name,
secgate_info,
}
Expand All @@ -129,6 +149,11 @@ impl<Backing: BackingData> Library<Backing> {
LibraryId(self.idx)
}

/// Get the compartment ID for this library.
pub fn compartment(&self) -> CompartmentId {
self.comp_id
}

/// Get a raw pointer to the program headers for this library.
pub fn get_phdrs_raw(&self) -> Option<(*const Elf64_Phdr, usize)> {
Some((
Expand Down Expand Up @@ -263,6 +288,20 @@ impl<Backing: BackingData> Library<Backing> {
.into())
}

pub(crate) fn is_local_or_secgate_from(&self, other: &Library<Backing>, name: &str) -> bool {
other.comp_id == self.comp_id || self.is_secgate(name)
}

fn is_secgate(&self, name: &str) -> bool {
self.iter_secgates()
.map(|gates| {
gates
.iter()
.any(|gate| gate.name().to_bytes() == name.as_bytes())
})
.unwrap_or(false)
}

pub fn iter_secgates(&self) -> Option<&[RawSecGateInfo]> {
let addr = self.secgate_info.info_addr?;

Expand Down
2 changes: 2 additions & 0 deletions src/runtime/dynlink/src/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -40,5 +40,7 @@ bitflags::bitflags! {
const SKIP_DEPS = 2;
/// Don't do a global search.
const SKIP_GLOBAL = 4;
/// Allow any symbols, not just secgates.
const SKIP_SECGATE_CHECK = 8;
}
}
Loading

0 comments on commit 47bcd88

Please sign in to comment.