use crate::manifest::RvfManifest;
use ruvix_cap::BootCapabilitySet;
use ruvix_types::{CapRights, KernelError, ObjectType};
#[cfg(feature = "alloc")]
use alloc::vec::Vec;
#[derive(Debug, Clone)]
pub struct CapabilityDistribution {
#[cfg(feature = "alloc")]
pub component_grants: Vec<ComponentCapabilityGrant>,
#[cfg(not(feature = "alloc"))]
pub component_grants: [Option<ComponentCapabilityGrant>; 256],
#[cfg(not(feature = "alloc"))]
pub grant_count: usize,
pub root_dropped_to_minimum: bool,
pub root_minimum_set: MinimumCapabilitySet,
}
impl CapabilityDistribution {
pub fn from_manifest(
manifest: &RvfManifest,
_boot_capabilities: &BootCapabilitySet,
) -> Result<Self, KernelError> {
let mut distribution = Self {
#[cfg(feature = "alloc")]
component_grants: Vec::new(),
#[cfg(not(feature = "alloc"))]
component_grants: [const { None }; 256],
#[cfg(not(feature = "alloc"))]
grant_count: 0,
root_dropped_to_minimum: false,
root_minimum_set: MinimumCapabilitySet::default(),
};
distribution.create_grants_from_manifest(manifest)?;
Ok(distribution)
}
fn create_grants_from_manifest(&mut self, manifest: &RvfManifest) -> Result<(), KernelError> {
let component_count = manifest.component_graph.component_count();
for i in 0..component_count {
if i >= 256 {
return Err(KernelError::LimitExceeded);
}
let grant = ComponentCapabilityGrant {
component_index: i as u32,
grants: [None; 32],
grant_count: 0,
};
#[cfg(feature = "alloc")]
self.component_grants.push(grant);
#[cfg(not(feature = "alloc"))]
{
self.component_grants[i] = Some(grant);
self.grant_count += 1;
}
}
Ok(())
}
#[inline]
#[must_use]
pub fn grant_count(&self) -> usize {
#[cfg(feature = "alloc")]
{
self.component_grants.len()
}
#[cfg(not(feature = "alloc"))]
{
self.grant_count
}
}
}
#[derive(Debug, Clone)]
pub struct ComponentCapabilityGrant {
pub component_index: u32,
pub grants: [Option<CapabilityGrant>; 32],
pub grant_count: usize,
}
impl ComponentCapabilityGrant {
pub fn add_grant(&mut self, grant: CapabilityGrant) -> Result<(), KernelError> {
if self.grant_count >= 32 {
return Err(KernelError::LimitExceeded);
}
self.grants[self.grant_count] = Some(grant);
self.grant_count += 1;
Ok(())
}
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
#[repr(C)]
pub struct CapabilityGrant {
pub object_id: u64,
pub object_type: ObjectType,
pub rights: CapRights,
pub badge: u64,
}
impl CapabilityGrant {
#[must_use]
pub const fn new(
object_id: u64,
object_type: ObjectType,
rights: CapRights,
badge: u64,
) -> Self {
Self {
object_id,
object_type,
rights,
badge,
}
}
#[must_use]
pub const fn region_readonly(object_id: u64, badge: u64) -> Self {
Self {
object_id,
object_type: ObjectType::Region,
rights: CapRights::READ,
badge,
}
}
#[must_use]
pub const fn region_readwrite(object_id: u64, badge: u64) -> Self {
Self {
object_id,
object_type: ObjectType::Region,
rights: CapRights::READ.union(CapRights::WRITE),
badge,
}
}
#[must_use]
pub const fn queue_send(object_id: u64, badge: u64) -> Self {
Self {
object_id,
object_type: ObjectType::Queue,
rights: CapRights::WRITE,
badge,
}
}
#[must_use]
pub const fn queue_recv(object_id: u64, badge: u64) -> Self {
Self {
object_id,
object_type: ObjectType::Queue,
rights: CapRights::READ,
badge,
}
}
}
#[derive(Debug, Clone, Default)]
pub struct MinimumCapabilitySet {
pub witness_log: Option<CapabilityGrant>,
pub timer: Option<CapabilityGrant>,
pub self_task: Option<CapabilityGrant>,
pub syscall_queue: Option<CapabilityGrant>,
}
impl MinimumCapabilitySet {
#[must_use]
pub fn for_root_task(
witness_log_id: u64,
timer_id: u64,
task_id: u64,
syscall_queue_id: u64,
) -> Self {
Self {
witness_log: Some(CapabilityGrant::new(
witness_log_id,
ObjectType::WitnessLog,
CapRights::WRITE, 0,
)),
timer: Some(CapabilityGrant::new(
timer_id,
ObjectType::Timer,
CapRights::READ.union(CapRights::WRITE),
0,
)),
self_task: Some(CapabilityGrant::new(
task_id,
ObjectType::Task,
CapRights::READ.union(CapRights::EXECUTE),
0,
)),
syscall_queue: Some(CapabilityGrant::new(
syscall_queue_id,
ObjectType::Queue,
CapRights::READ.union(CapRights::WRITE),
0,
)),
}
}
#[inline]
#[must_use]
pub fn count(&self) -> usize {
let mut count = 0;
if self.witness_log.is_some() { count += 1; }
if self.timer.is_some() { count += 1; }
if self.self_task.is_some() { count += 1; }
if self.syscall_queue.is_some() { count += 1; }
count
}
#[inline]
#[must_use]
pub fn is_valid(&self) -> bool {
self.witness_log.is_some()
&& self.timer.is_some()
&& self.self_task.is_some()
}
}
pub struct RootCapabilityDrop {
pub revoked_count: usize,
pub completed: bool,
pub final_capability_count: usize,
}
impl RootCapabilityDrop {
#[must_use]
pub fn new() -> Self {
Self {
revoked_count: 0,
completed: false,
final_capability_count: 0,
}
}
pub fn execute(
&mut self,
boot_capabilities: &BootCapabilitySet,
minimum_set: &MinimumCapabilitySet,
) -> Result<(), KernelError> {
let total_boot_caps = boot_capabilities.total_count();
let minimum_caps = minimum_set.count();
self.revoked_count = total_boot_caps.saturating_sub(minimum_caps);
self.final_capability_count = minimum_caps;
self.completed = true;
Ok(())
}
#[must_use]
pub fn verify(&self, minimum_set: &MinimumCapabilitySet) -> bool {
self.completed
&& self.final_capability_count == minimum_set.count()
&& minimum_set.is_valid()
}
}
impl Default for RootCapabilityDrop {
fn default() -> Self {
Self::new()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_capability_grant_creation() {
let grant = CapabilityGrant::new(
0x1000,
ObjectType::Region,
CapRights::READ,
42,
);
assert_eq!(grant.object_id, 0x1000);
assert_eq!(grant.object_type, ObjectType::Region);
assert_eq!(grant.rights, CapRights::READ);
assert_eq!(grant.badge, 42);
}
#[test]
fn test_capability_grant_shortcuts() {
let ro = CapabilityGrant::region_readonly(0x1000, 1);
assert!(ro.rights.contains(CapRights::READ));
assert!(!ro.rights.contains(CapRights::WRITE));
let rw = CapabilityGrant::region_readwrite(0x2000, 2);
assert!(rw.rights.contains(CapRights::READ));
assert!(rw.rights.contains(CapRights::WRITE));
let send = CapabilityGrant::queue_send(0x3000, 3);
assert!(send.rights.contains(CapRights::WRITE));
assert!(!send.rights.contains(CapRights::READ));
}
#[test]
fn test_minimum_capability_set() {
let min_set = MinimumCapabilitySet::for_root_task(
0x1000, 0x2000, 0x3000, 0x4000, );
assert_eq!(min_set.count(), 4);
assert!(min_set.is_valid());
}
#[test]
fn test_minimum_capability_set_validity() {
let invalid_set = MinimumCapabilitySet::default();
assert!(!invalid_set.is_valid());
assert_eq!(invalid_set.count(), 0);
}
#[test]
fn test_root_capability_drop() {
let mut drop = RootCapabilityDrop::new();
let boot_caps = BootCapabilitySet::full(1, 0x1000, 0x10000, 0x2000, 0xCAFE);
let min_set = MinimumCapabilitySet::for_root_task(0x1000, 0x2000, 0x3000, 0x4000);
drop.execute(&boot_caps, &min_set).unwrap();
assert!(drop.completed);
assert_eq!(drop.final_capability_count, 4);
assert!(drop.verify(&min_set));
}
#[test]
fn test_component_capability_grant() {
let mut grant = ComponentCapabilityGrant {
component_index: 0,
grants: [None; 32],
grant_count: 0,
};
grant.add_grant(CapabilityGrant::region_readonly(0x1000, 0)).unwrap();
grant.add_grant(CapabilityGrant::queue_send(0x2000, 1)).unwrap();
assert_eq!(grant.grant_count, 2);
}
#[test]
fn test_component_capability_grant_limit() {
let mut grant = ComponentCapabilityGrant {
component_index: 0,
grants: [None; 32],
grant_count: 0,
};
for i in 0..32 {
grant.add_grant(CapabilityGrant::region_readonly(i as u64, 0)).unwrap();
}
let result = grant.add_grant(CapabilityGrant::region_readonly(32, 0));
assert_eq!(result, Err(KernelError::LimitExceeded));
}
}