feat(users): per-user sealed folders users/<id>/{home,apps,data,permissions}; storage SET_USER/LOCK/PURGE; init sign-in/sign-out loop (purge fresh/removed/guest, seed from factory, session start/stop); shell logout; pm user+system app shelves; terminal SIGNED_OUT; per-program stack (gatekeeper 12p); 128K load scratch

This commit is contained in:
2026-10-28 01:08:50 +01:00
parent 29a25bd8c2
commit 91f7d28834
38 changed files with 1156 additions and 378 deletions

View File

@@ -14,16 +14,18 @@ use libkos::syscall;
use types::bounded::CapSlot;
use types::budget::Limits;
/// Where init put them (see init's manifest: `uses`, the spawn endpoint,
/// then control).
/// Where init put them (see init's manifest: `uses`, storage (the disk,
/// the user's home), the spawn endpoint, then control).
const PERMISSION: CapSlot = CapSlot::const_new(0);
const STORAGE: CapSlot = CapSlot::const_new(1);
const INIT: CapSlot = CapSlot::const_new(2);
const CONTROL: CapSlot = CapSlot::const_new(3);
const HOME: CapSlot = CapSlot::const_new(2);
const INIT: CapSlot = CapSlot::const_new(3);
const CONTROL: CapSlot = CapSlot::const_new(4);
/// Where storage's buffers are mapped: the whole disk's, a narrowed one's.
const STORAGE_BUF_VA: types::address::VirtualAddress = types::address::VirtualAddress::from_raw(0x0180_0000);
const NARROW_BUF_VA: types::address::VirtualAddress = types::address::VirtualAddress::from_raw(0x0190_0000);
const REQUEST_PAGE_VA: types::address::VirtualAddress = types::address::VirtualAddress::from_raw(0x01C0_0000);
const HOME_BUF_VA: types::address::VirtualAddress = types::address::VirtualAddress::from_raw(0x01B0_0000);
/// Read back from the disk image by scripts/test-qemu.sh.
const NOTE: &[u8] = b"written by k-os on ext4\n";
@@ -125,9 +127,9 @@ fn revoke_stops_a_running_app(died: CapSlot) -> Result<(), &'static str> {
Ok(())
}
/// The owner's area is sealed: seeded from the factory, and what is
/// written there one boot reads back the next.
fn encrypted_home(fs: &mut Storage) -> Result<(), &'static str> {
/// The user's home is sealed: seeded from the factory, and what is written
/// there one boot reads back the next. Theirs is the only folder that opens.
fn encrypted_home(fs: &mut Storage, home_fs: &mut Storage) -> Result<(), &'static str> {
let mut home = [0u8; 512];
let mut factory = [0u8; 512];
let read = |fs: &mut Storage, path: &[u8], out: &mut [u8]| -> Result<usize, &'static str> {
@@ -136,7 +138,7 @@ fn encrypted_home(fs: &mut Storage) -> Result<(), &'static str> {
let _ = fs.close(h);
Ok(n)
};
let n = read(fs, b"home/readme.txt", &mut home)?;
let n = read(home_fs, b"readme.txt", &mut home)?;
let m = read(fs, b"factory/home/readme.txt", &mut factory)?;
if home[..n] != factory[..m] {
return Err("the encrypted home does not hold the factory's readme");
@@ -144,19 +146,29 @@ fn encrypted_home(fs: &mut Storage) -> Result<(), &'static str> {
libkos::println!("spawntest: home seeded from the factory, reads back through its seal: ok");
const NOTE: &[u8] = b"sealed across a reboot";
let mut back = [0u8; 64];
match read(fs, b"home/persist.txt", &mut back) {
match read(home_fs, b"persist.txt", &mut back) {
Ok(n) if &back[..n] == NOTE => libkos::println!("spawntest: an encrypted file from the last boot reads back: ok"),
Ok(_) => return Err("an encrypted file from the last boot reads back wrong"),
Err(_) => {
let h = fs.create(b"home/persist.txt").map_err(|_| "cannot create in home")?;
let wrote = fs.write(h, NOTE) == Ok(NOTE.len());
let _ = fs.close(h);
let h = home_fs.create(b"persist.txt").map_err(|_| "cannot create in home")?;
let wrote = home_fs.write(h, NOTE) == Ok(NOTE.len());
let _ = home_fs.close(h);
if !wrote {
return Err("cannot write in home");
}
libkos::println!("spawntest: wrote an encrypted file for the next boot");
}
}
// A made-up user's: nobody may reach it, the whole disk's holder neither.
if fs.create(b"users/0123456789abcdef/home/planted").is_ok() || fs.mkdir(b"users/0123456789abcdef").is_ok() {
return Err("someone else's folder could be written");
}
let mut folders = 0;
fs.list_dir(b"users", |e| folders += usize::from(e.name() != b"." && e.name() != b"..")).map_err(|_| "cannot list the users")?;
if folders != 1 {
return Err("not exactly one user's folder");
}
libkos::println!("spawntest: only the signed-in user's folder opens: ok");
Ok(())
}
@@ -164,7 +176,8 @@ fn check() -> Result<(), &'static str> {
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");
encrypted_home(&mut fs)?;
let mut home = Storage::attach(HOME, HOME_BUF_VA).map_err(|_| "cannot attach to home")?;
encrypted_home(&mut fs, &mut home)?;
let died = syscall::create_notification().map_err(|_| "no notification")?;
narrow_storage(&mut fs, died)?;