feat(storage): scoped grants (subtree, ro/rw), narrow-only, release revokes all holders; IPC KEEP_DELEGATE opt-in; shell cd/pwd, programs get ro cwd
This commit is contained in:
@@ -15,6 +15,24 @@ fn optional_slots_roundtrip() {
|
||||
assert!(reg_slot(slot_reg(s)) == Some(s));
|
||||
}
|
||||
|
||||
#[kani::proof]
|
||||
fn gives_roundtrip() {
|
||||
let g = any_slot().map(|slot| Give {
|
||||
slot,
|
||||
keep_delegate: kani::any(),
|
||||
});
|
||||
assert!(reg_give(give_reg(g)) == Some(g));
|
||||
}
|
||||
|
||||
/// The flag never turns one slot into another.
|
||||
#[kani::proof]
|
||||
fn a_give_register_names_the_slot_it_carries() {
|
||||
let r: usize = kani::any();
|
||||
if let Some(Some(g)) = reg_give(r) {
|
||||
assert!(g.slot.value() as usize == r & !KEEP_DELEGATE);
|
||||
}
|
||||
}
|
||||
|
||||
#[kani::proof]
|
||||
fn every_register_decodes_to_none_or_a_valid_slot() {
|
||||
let r: usize = kani::any();
|
||||
|
||||
@@ -27,6 +27,12 @@ pub mod op {
|
||||
pub const MKDIR: usize = 9;
|
||||
/// Carries the log endpoint; only from the unbadged holder (init).
|
||||
pub const SET_LOG: usize = 10;
|
||||
/// A capability to the path in the buffer, inside the caller's scope;
|
||||
/// word 2 non-zero asks for write (only if the caller has it).
|
||||
pub const GRANT: usize = 11;
|
||||
/// Takes back the grant this is called through, and everything
|
||||
/// granted from it, from every holder.
|
||||
pub const RELEASE: usize = 12;
|
||||
}
|
||||
|
||||
/// Reply tags (word 0).
|
||||
@@ -42,4 +48,8 @@ pub mod reply {
|
||||
pub const ERROR: usize = 8;
|
||||
pub const READ_ONLY: usize = 9;
|
||||
pub const NOT_ATTACHED: usize = 10;
|
||||
/// Carries the new capability.
|
||||
pub const GRANTED: usize = 11;
|
||||
/// Outside the caller's scope, beyond its rights, or no grant at all.
|
||||
pub const DENIED: usize = 12;
|
||||
}
|
||||
|
||||
@@ -52,6 +52,10 @@ pub const PERMS_READ_EXECUTE: usize = 2;
|
||||
/// "No capability" in a capability argument or result register.
|
||||
pub const NONE: usize = usize::MAX;
|
||||
|
||||
/// Set in a message's capability register: the receiver may pass the
|
||||
/// capability on (it keeps `Delegate`). Without it the receiver may not.
|
||||
pub const KEEP_DELEGATE: usize = 1 << 8;
|
||||
|
||||
/// What a receiving syscall got, returned in `a7`.
|
||||
pub const KIND_MESSAGE: usize = 0;
|
||||
pub const KIND_CALL: usize = 1;
|
||||
@@ -115,6 +119,53 @@ pub fn reg_slot(reg: usize) -> Option<Option<CapSlot>> {
|
||||
}
|
||||
}
|
||||
|
||||
/// A capability sent with a message.
|
||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||
pub struct Give {
|
||||
pub slot: CapSlot,
|
||||
/// The receiver gets it with `Delegate`, so it can pass it on; only
|
||||
/// if the sender's own copy has `Delegate` to give.
|
||||
pub keep_delegate: bool,
|
||||
}
|
||||
|
||||
impl Give {
|
||||
pub const fn keeping_delegate(slot: CapSlot) -> Self {
|
||||
Self {
|
||||
slot,
|
||||
keep_delegate: true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<CapSlot> for Give {
|
||||
fn from(slot: CapSlot) -> Self {
|
||||
Self {
|
||||
slot,
|
||||
keep_delegate: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn give_reg(give: Option<Give>) -> usize {
|
||||
match give {
|
||||
None => NONE,
|
||||
Some(g) => g.slot.value() as usize | if g.keep_delegate { KEEP_DELEGATE } else { 0 },
|
||||
}
|
||||
}
|
||||
|
||||
/// Decodes a message's capability register: `Some(None)` for `NONE`,
|
||||
/// `None` for anything but a valid slot, optionally with `KEEP_DELEGATE`.
|
||||
pub fn reg_give(reg: usize) -> Option<Option<Give>> {
|
||||
if reg == NONE {
|
||||
return Some(None);
|
||||
}
|
||||
let slot = reg_slot(reg & !KEEP_DELEGATE)??;
|
||||
Some(Some(Give {
|
||||
slot,
|
||||
keep_delegate: reg & KEEP_DELEGATE != 0,
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn perms_reg(perms: PagePerms) -> usize {
|
||||
match perms {
|
||||
PagePerms::ReadOnly => PERMS_READ_ONLY,
|
||||
@@ -133,14 +184,14 @@ pub fn reg_perms(reg: usize) -> Option<PagePerms> {
|
||||
}
|
||||
|
||||
/// Argument registers `a0..a5` of a message-carrying call.
|
||||
pub fn message_regs(target: usize, words: [usize; 4], cap: Option<CapSlot>) -> [usize; 6] {
|
||||
pub fn message_regs(target: usize, words: [usize; 4], cap: Option<Give>) -> [usize; 6] {
|
||||
[
|
||||
target,
|
||||
words[0],
|
||||
words[1],
|
||||
words[2],
|
||||
words[3],
|
||||
slot_reg(cap),
|
||||
give_reg(cap),
|
||||
]
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user