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:
@@ -28,9 +28,16 @@ fn permissions(r: usize) -> Option<PermissionSet> {
|
||||
/// The message in `a1..a5`.
|
||||
fn message(a: &[usize; 6]) -> Option<Message> {
|
||||
let msg = Message::from_words([a[1], a[2], a[3], a[4]]);
|
||||
Some(match reg_slot(a[5])? {
|
||||
Some(match reg_give(a[5])? {
|
||||
None => msg,
|
||||
Some(cap) => msg.with_cap(cap),
|
||||
Some(Give {
|
||||
slot,
|
||||
keep_delegate: false,
|
||||
}) => msg.with_cap(slot),
|
||||
Some(Give {
|
||||
slot,
|
||||
keep_delegate: true,
|
||||
}) => msg.with_cap(slot).keeping_delegate(),
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -39,12 +39,18 @@ fn send_roundtrips() {
|
||||
} else {
|
||||
None
|
||||
};
|
||||
let regs = message_regs(ep.value() as usize, words, cap);
|
||||
let keep: bool = kani::any();
|
||||
let give = cap.map(|slot| Give {
|
||||
slot,
|
||||
keep_delegate: keep,
|
||||
});
|
||||
let regs = message_regs(ep.value() as usize, words, give);
|
||||
match decode(SYS_SEND, ®s) {
|
||||
Some(Syscall::Send { endpoint, message }) => {
|
||||
assert!(endpoint == ep);
|
||||
assert!(*message.words() == words);
|
||||
assert!(message.cap() == cap);
|
||||
assert!(message.keeps_delegate() == (keep && cap.is_some()));
|
||||
}
|
||||
_ => panic!("valid send did not decode"),
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@ use domain::capability::{Capability, CapabilityTable};
|
||||
use domain::resource::Resource;
|
||||
use types::generation::Generation;
|
||||
use types::id::EndpointId;
|
||||
use types::permission::{Permission, PermissionSet};
|
||||
use types::permission::PermissionSet;
|
||||
|
||||
#[kani::proof]
|
||||
fn revoke_invalidates_cap_slot() {
|
||||
|
||||
@@ -38,23 +38,23 @@ impl<P: Platform> Kernel<P> {
|
||||
pub(super) fn transfer_cap(
|
||||
&mut self,
|
||||
from: ProcessId,
|
||||
slot: Option<CapSlot>,
|
||||
message: &Message,
|
||||
grant: bool,
|
||||
to: ProcessId,
|
||||
) -> Option<CapSlot> {
|
||||
let slot = slot?;
|
||||
let slot = message.cap()?;
|
||||
if !grant {
|
||||
return None;
|
||||
}
|
||||
// The receiver gets the capability but not the right to pass it
|
||||
// on; a sender that wants that uses Delegate with explicit rights.
|
||||
// on, unless the sender says so; it can only give what it holds.
|
||||
let source = self.check_cap(from, slot, Permission::Delegate).ok()?;
|
||||
let copy = Capability::new(
|
||||
*source.resource(),
|
||||
source.permissions().without(Permission::Delegate),
|
||||
*source.generation(),
|
||||
)
|
||||
.with_badge(source.badge());
|
||||
let permissions = match message.keeps_delegate() {
|
||||
true => *source.permissions(),
|
||||
false => source.permissions().without(Permission::Delegate),
|
||||
};
|
||||
let copy = Capability::new(*source.resource(), permissions, *source.generation())
|
||||
.with_badge(source.badge());
|
||||
let parent = self.cap_ref(from, slot);
|
||||
self.insert_derived(to, copy, parent).ok()
|
||||
}
|
||||
@@ -71,7 +71,7 @@ impl<P: Platform> Kernel<P> {
|
||||
let from = self.thread_process(sender);
|
||||
let to = self.thread_process(receiver);
|
||||
let cap = match (from, to) {
|
||||
(Some(from), Some(to)) => self.transfer_cap(from, out.message.cap(), out.grant, to),
|
||||
(Some(from), Some(to)) => self.transfer_cap(from, &out.message, out.grant, to),
|
||||
_ => None,
|
||||
};
|
||||
if kind == DeliveryKind::Call {
|
||||
@@ -234,7 +234,7 @@ impl<P: Platform> Kernel<P> {
|
||||
}
|
||||
let to = self.thread_process(caller.tid);
|
||||
// A reply may always carry a capability the server can delegate.
|
||||
let cap = to.and_then(|to| self.transfer_cap(pid, message.cap(), true, to));
|
||||
let cap = to.and_then(|to| self.transfer_cap(pid, &message, true, to));
|
||||
let delivery = Delivery {
|
||||
kind: DeliveryKind::Message,
|
||||
badge: 0,
|
||||
|
||||
@@ -917,6 +917,67 @@ fn a_received_cap_cannot_be_passed_on() {
|
||||
));
|
||||
}
|
||||
|
||||
/// What `b` holds in `slot`, by permission.
|
||||
fn rights_of(t: &Ipc, pid: ProcessId, slot: CapSlot) -> PermissionSet {
|
||||
*t.k.processes
|
||||
.get(pid)
|
||||
.unwrap()
|
||||
.capabilities()
|
||||
.get(slot)
|
||||
.unwrap()
|
||||
.permissions()
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_sender_can_let_the_receiver_pass_a_cap_on() {
|
||||
let mut t = Ipc::new();
|
||||
let (a, b, ta, tb, a_send, b_recv) = (t.a, t.b, t.ta, t.tb, t.a_send, t.b_recv);
|
||||
let other = t.k.create_endpoint(a).unwrap();
|
||||
let gift =
|
||||
t.k.grant_cap_for_test(a, Resource::Endpoint(other), perms(SEND_GRANT));
|
||||
t.run(
|
||||
ta,
|
||||
Syscall::Send {
|
||||
endpoint: a_send,
|
||||
message: msg([0; 4]).with_cap(gift).keeping_delegate(),
|
||||
},
|
||||
);
|
||||
let d = delivered(&t.run(tb, Syscall::Receive { endpoint: b_recv })).unwrap();
|
||||
let got = d.cap.expect("the cap arrives");
|
||||
assert_eq!(
|
||||
rights_of(&t, b, got),
|
||||
rights_of(&t, a, gift),
|
||||
"with exactly the sender's rights"
|
||||
);
|
||||
let mint = t.run(
|
||||
tb,
|
||||
Syscall::Mint {
|
||||
slot: got,
|
||||
badge: Badge::new(1),
|
||||
permissions: perms(SEND),
|
||||
},
|
||||
);
|
||||
assert!(error(&mint).is_none(), "so it can derive from it");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn keeping_delegate_cannot_give_what_the_sender_lacks() {
|
||||
let mut t = Ipc::new();
|
||||
let (a, ta, tb, a_send, b_recv) = (t.a, t.ta, t.tb, t.a_send, t.b_recv);
|
||||
let other = t.k.create_endpoint(a).unwrap();
|
||||
let gift =
|
||||
t.k.grant_cap_for_test(a, Resource::Endpoint(other), perms(SEND));
|
||||
t.run(
|
||||
ta,
|
||||
Syscall::Send {
|
||||
endpoint: a_send,
|
||||
message: msg([0; 4]).with_cap(gift).keeping_delegate(),
|
||||
},
|
||||
);
|
||||
let d = delivered(&t.run(tb, Syscall::Receive { endpoint: b_recv })).unwrap();
|
||||
assert_eq!(d.cap, None, "a cap without Delegate never travels");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn an_irq_has_one_owner_until_it_dies() {
|
||||
let mut t = Ipc::new();
|
||||
|
||||
Reference in New Issue
Block a user