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:
@@ -7,6 +7,7 @@
|
||||
|
||||
extern crate libkos;
|
||||
|
||||
use libkos::fs::{FsError, Storage};
|
||||
use libkos::spawn::{SpawnError, spawn};
|
||||
use libkos::syscall;
|
||||
use types::bounded::CapSlot;
|
||||
@@ -17,8 +18,9 @@ use types::budget::Limits;
|
||||
const STORAGE: CapSlot = CapSlot::const_new(0);
|
||||
const INIT: CapSlot = CapSlot::const_new(1);
|
||||
const CONTROL: CapSlot = CapSlot::const_new(2);
|
||||
/// Where storage's buffer is mapped.
|
||||
/// Where storage's buffers are mapped: the whole disk's, a narrowed one's.
|
||||
const STORAGE_BUF_VA: usize = 0x0180_0000;
|
||||
const NARROW_BUF_VA: usize = 0x0190_0000;
|
||||
/// Read back from the disk image by scripts/test-qemu.sh.
|
||||
const NOTE: &[u8] = b"written by k-os on ext4\n";
|
||||
|
||||
@@ -26,9 +28,14 @@ const NOTE: &[u8] = b"written by k-os on ext4\n";
|
||||
/// the first has died and its limits came back.
|
||||
const HELLO: Limits = Limits { pages: 80, endpoints: 0, notifications: 0, regions: 0 };
|
||||
|
||||
/// Spawns hello, runs it, and waits for it to die.
|
||||
fn run_hello(died: CapSlot) -> Result<(), &'static str> {
|
||||
/// Spawns hello, runs it, and waits for it to die; hands it `grant`
|
||||
/// first, if there is one.
|
||||
fn run_hello(died: CapSlot, grant: Option<CapSlot>) -> Result<(), &'static str> {
|
||||
let child = spawn(INIT, b"hello.elf", HELLO).map_err(|_| "init would not spawn hello")?;
|
||||
let call = types::permission::PermissionSet::empty().with(types::permission::Permission::Execute);
|
||||
if grant.is_some_and(|g| child.give(g, call).is_none()) {
|
||||
return Err("a storage grant could not be passed on");
|
||||
}
|
||||
syscall::watch_death(child.process, died).map_err(|_| "cannot watch hello")?;
|
||||
if !child.start() {
|
||||
return Err("cannot start hello");
|
||||
@@ -38,8 +45,7 @@ fn run_hello(died: CapSlot) -> Result<(), &'static str> {
|
||||
}
|
||||
|
||||
/// A file written through storage, which the host then checks with e2fsck.
|
||||
fn write_a_file() -> Result<(), &'static str> {
|
||||
let mut fs = libkos::fs::Storage::attach(STORAGE, STORAGE_BUF_VA).map_err(|_| "cannot attach to storage")?;
|
||||
fn write_a_file(fs: &mut Storage) -> Result<(), &'static str> {
|
||||
let h = fs.create(b"selftest.txt").map_err(|_| "cannot create a file")?;
|
||||
if fs.write(h, NOTE) != Ok(NOTE.len()) {
|
||||
return Err("short write");
|
||||
@@ -55,12 +61,40 @@ fn write_a_file() -> Result<(), &'static str> {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// A read-only grant to one directory reaches nothing else and changes
|
||||
/// nothing, can be passed on, and is gone everywhere once released.
|
||||
fn narrow_storage(fs: &mut Storage, died: CapSlot) -> Result<(), &'static str> {
|
||||
let grant = fs.grant(b"lost+found", false).map_err(|_| "storage refused a grant")?;
|
||||
let mut inner = Storage::attach(grant, NARROW_BUF_VA).map_err(|_| "cannot attach through the grant")?;
|
||||
inner.list_dir(b"", |_| {}).map_err(|_| "cannot list its own directory")?;
|
||||
if inner.open(b"../selftest.txt").err() != Some(FsError::Denied) {
|
||||
return Err("a grant reached outside its directory");
|
||||
}
|
||||
if inner.create(b"x").err() != Some(FsError::Denied) {
|
||||
return Err("a read-only grant created a file");
|
||||
}
|
||||
let widened = inner.grant(b"", true).and_then(|g| Storage::attach(g, NARROW_BUF_VA + 0x10_0000));
|
||||
if widened.and_then(|mut w| w.create(b"x")).is_ok() {
|
||||
return Err("a grant was widened to write");
|
||||
}
|
||||
run_hello(died, Some(grant))?;
|
||||
libkos::fs::release(grant).map_err(|_| "release failed")?;
|
||||
if inner.list_dir(b"", |_| {}).is_ok() {
|
||||
return Err("a released grant still works");
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn check() -> Result<(), &'static str> {
|
||||
write_a_file()?;
|
||||
let mut fs = Storage::attach(STORAGE, STORAGE_BUF_VA).map_err(|_| "cannot attach to storage")?;
|
||||
write_a_file(&mut fs)?;
|
||||
libkos::println!("spawntest: a file written to ext4 reads back: ok");
|
||||
|
||||
let died = syscall::create_notification().map_err(|_| "no notification")?;
|
||||
run_hello(died)?;
|
||||
narrow_storage(&mut fs, died)?;
|
||||
libkos::println!("spawntest: storage grants stay in scope, pass on, release: ok");
|
||||
|
||||
run_hello(died, None)?;
|
||||
libkos::println!("spawntest: spawned program runs and its death is heard: ok");
|
||||
|
||||
let greedy = Limits { pages: 200, ..HELLO };
|
||||
@@ -73,7 +107,7 @@ fn check() -> Result<(), &'static str> {
|
||||
}
|
||||
libkos::println!("spawntest: allowance and missing files refused: ok");
|
||||
|
||||
run_hello(died)?;
|
||||
run_hello(died, None)?;
|
||||
libkos::println!("spawntest: allowance comes back when a child dies: ok");
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user