//! Process identity is minted from a kernel owned process ID. //! User requests may inspect an assigned identity, but cannot replace it. #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Principal(u64); impl Principal { pub const fn id(self) -> u64 { self.0 } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Error { Full, Duplicate, Unknown, Access, Exhausted, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Binding

{ process: P, principal: Principal, } pub struct Registry { next: u64, bindings: [Option>; N], } impl Registry { pub fn new() -> Self { Self { next: 1, bindings: [None; N] } } /// Called only after the kernel has obtained a genuine ProcessId. pub fn bind_kernel(&mut self, process: P) -> Result { if self.bindings.iter().flatten().any(|row| row.process == process) { return Err(Error::Duplicate); } let slot = self.bindings.iter_mut().find(|slot| slot.is_none()) .ok_or(Error::Full)?; let following = self.next.checked_add(1).ok_or(Error::Exhausted)?; let principal = Principal(self.next); *slot = Some(Binding { process, principal }); self.next = following; Ok(principal) } pub fn principal(&self, process: P) -> Result { self.bindings.iter().flatten() .find(|row| row.process == process) .map(|row| row.principal).ok_or(Error::Unknown) } /// The syscall path always returns an explicit denial for a live process. /// `requested` is deliberately never used to construct a Principal. pub fn request_user_change(&self, process: P, _requested: u64) -> Result<(), Error> { self.principal(process)?; Err(Error::Access) } pub fn retire_kernel(&mut self, process: P) -> Result<(), Error> { let slot = self.bindings.iter_mut() .find(|slot| slot.is_some_and(|row| row.process == process)) .ok_or(Error::Unknown)?; *slot = None; Ok(()) } pub fn snapshot(&self) -> (u64, [Option<(P, u64)>; N]) { (self.next, self.bindings.map(|row| row.map(|row| (row.process, row.principal.id())))) } } impl Default for Registry { fn default() -> Self { Self::new() } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct Handle(u64); impl Handle { pub const fn id(self) -> u64 { self.0 } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub enum Capability { ReadOnlyFile { object: u64, allow_child: bool }, KernelDevice { object: u64 }, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct Grant

{ handle: Handle, owner: P, capability: Capability, } pub struct HandleSet { next: u64, grants: [Option>; M], } impl HandleSet { pub fn new() -> Self { Self { next: 1, grants: [None; M] } } pub fn issue_kernel( &mut self, identities: &Registry, owner: P, capability: Capability, ) -> Result { identities.principal(owner)?; let slot = self.grants.iter_mut().find(|slot| slot.is_none()) .ok_or(Error::Full)?; let following = self.next.checked_add(1).ok_or(Error::Exhausted)?; let handle = Handle(self.next); *slot = Some(Grant { handle, owner, capability }); self.next = following; Ok(handle) } pub fn lookup(&self, owner: P, handle: u64) -> Result { self.grants.iter().flatten() .find(|grant| grant.owner == owner && grant.handle.id() == handle) .map(|grant| grant.capability).ok_or(Error::Unknown) } /// The caller supplies `actual_parent` from the live process table record. /// A child receives only a named, explicitly inheritable read-only file. pub fn inherit_explicit( &mut self, identities: &Registry, parent: P, child: P, actual_parent: Option

, requested: u64, ) -> Result { identities.principal(parent)?; identities.principal(child)?; if parent == child || actual_parent != Some(parent) { return Err(Error::Access); } let inherited = match self.lookup(parent, requested)? { Capability::ReadOnlyFile { object, allow_child: true } => Capability::ReadOnlyFile { object, allow_child: false }, _ => return Err(Error::Access), }; let slot = self.grants.iter_mut().find(|slot| slot.is_none()) .ok_or(Error::Full)?; let following = self.next.checked_add(1).ok_or(Error::Exhausted)?; let handle = Handle(self.next); *slot = Some(Grant { handle, owner: child, capability: inherited }); self.next = following; Ok(handle) } pub fn close_owner(&mut self, owner: P) -> usize { let mut closed = 0; for slot in &mut self.grants { if slot.is_some_and(|grant| grant.owner == owner) { *slot = None; closed += 1; } } closed } pub fn snapshot(&self) -> (u64, [Option<(u64, P, Capability)>; M]) { (self.next, self.grants.map(|grant| grant.map(|grant| (grant.handle.id(), grant.owner, grant.capability)))) } } impl Default for HandleSet { fn default() -> Self { Self::new() } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct InspectHandle(u64); impl InspectHandle { pub const fn id(self) -> u64 { self.0 } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] pub struct MapMetadata { pub resource_owner: u64, pub pages: u64, pub published: bool, } #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct InspectGrant

{ handle: InspectHandle, observer: P, target: P, } pub struct InspectSet { next: u64, grants: [Option>; M], } impl InspectSet { pub fn new() -> Self { Self { next: 1, grants: [None; M] } } /// Only the kernel binds a permit to two live process identities. pub fn issue_kernel( &mut self, identities: &Registry, observer: P, target: P, ) -> Result { identities.principal(observer)?; identities.principal(target)?; if observer == target { return Err(Error::Access); } let slot = self.grants.iter_mut().find(|slot| slot.is_none()) .ok_or(Error::Full)?; let following = self.next.checked_add(1).ok_or(Error::Exhausted)?; let handle = InspectHandle(self.next); *slot = Some(InspectGrant { handle, observer, target }); self.next = following; Ok(handle) } fn authorize( &self, identities: &Registry, observer: P, actual_target: P, requested: u64, ) -> Result<(), Error> { identities.principal(observer)?; identities.principal(actual_target)?; let grant = self.grants.iter().flatten() .find(|grant| grant.handle.id() == requested && grant.observer == observer) .ok_or(Error::Unknown)?; if grant.target != actual_target { return Err(Error::Access); } Ok(()) } /// `actual_target` and `metadata` come from one live ProcessTable record. pub fn inspect_metadata( &self, identities: &Registry, observer: P, actual_target: P, requested: u64, metadata: MapMetadata, ) -> Result { self.authorize(identities, observer, actual_target, requested)?; Ok(metadata) } /// A metadata permit never authorizes raw access to a foreign map. pub fn read_foreign_map( &self, identities: &Registry, observer: P, actual_target: P, requested: u64, ) -> Result<(), Error> { self.authorize(identities, observer, actual_target, requested)?; Err(Error::Access) } pub fn close_observer(&mut self, observer: P) -> usize { let mut closed = 0; for slot in &mut self.grants { if slot.is_some_and(|grant| grant.observer == observer) { *slot = None; closed += 1; } } closed } pub fn snapshot(&self) -> (u64, [Option<(u64, P, P)>; M]) { (self.next, self.grants.map(|grant| grant.map(|grant| (grant.handle.id(), grant.observer, grant.target)))) } } impl Default for InspectSet { fn default() -> Self { Self::new() } }