feat(boot): gatekeeper gates boot (init→UI→gatekeeper→data); keystore disk + virtio-rng discovery; terminal READ_SECRET; storage SET_KEY; PageCount ≤8192, alloc cap gone; device window 0x01D0_0000; test-qemu types passcode over 2 boots
This commit is contained in:
@@ -7,8 +7,78 @@
|
||||
|
||||
extern crate alloc;
|
||||
|
||||
pub mod devices;
|
||||
pub mod flow;
|
||||
|
||||
#[cfg(test)]
|
||||
#[path = "tests/mod.rs"]
|
||||
mod tests;
|
||||
|
||||
use alloc::vec;
|
||||
use keystore::{Block, KdfParams};
|
||||
use libkos::syscall::{self, Received};
|
||||
use types::bounded::CapSlot;
|
||||
use types::gatekeeper::{KEY, UNLOCK, reply};
|
||||
|
||||
/// Where init's manifest put them: its own endpoint (devices arrive on
|
||||
/// it, then init's calls), then the terminal.
|
||||
const EP: CapSlot = CapSlot::const_new(0);
|
||||
const TERMINAL: CapSlot = CapSlot::const_new(1);
|
||||
|
||||
/// Answers init's next call, if it is `op`, with `words`.
|
||||
fn answer(op: usize, words: [usize; 4]) -> bool {
|
||||
loop {
|
||||
match syscall::receive_msg(EP) {
|
||||
Ok(Received::Call { badge: 0, words: [w, ..], .. }) if w == op => {
|
||||
return syscall::reply(words, None).is_ok();
|
||||
}
|
||||
// Anyone else, or anything else: refused.
|
||||
Ok(Received::Call { .. }) => {
|
||||
let _ = syscall::reply([reply::FAILED, 0, 0, 0], None);
|
||||
}
|
||||
Ok(_) => {}
|
||||
Err(_) => return false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn run() -> ! {
|
||||
// Init hands over the keystore disk, then the randomness device.
|
||||
let keystore = libkos::device::receive_device(EP).mmio.and_then(driver_block_virtio::VirtioBlockDevice::new);
|
||||
let random = libkos::device::receive_device(EP).mmio.and_then(driver_rng_virtio::VirtioRng::new);
|
||||
let (Some(keystore), Some(random)) = (keystore, random) else {
|
||||
libkos::println!("gatekeeper: no keystore or no randomness, nothing to unlock with");
|
||||
let _ = answer(UNLOCK, [reply::FAILED, 0, 0, 0]);
|
||||
syscall::exit();
|
||||
};
|
||||
let mut memory = vec![Block::default(); KdfParams::DEFAULT.memory_kib as usize];
|
||||
libkos::println!("gatekeeper: waiting for the owner");
|
||||
let key = flow::run(
|
||||
&mut devices::Disk(keystore),
|
||||
&mut devices::Hardware(random),
|
||||
&mut devices::Terminal(TERMINAL),
|
||||
KdfParams::DEFAULT,
|
||||
&mut memory,
|
||||
);
|
||||
// The guesses' working memory goes before anything else happens.
|
||||
for b in memory.iter_mut() {
|
||||
*b = Block::default();
|
||||
}
|
||||
drop(memory);
|
||||
match key {
|
||||
Ok(key) => {
|
||||
libkos::println!("gatekeeper: unlocked");
|
||||
libkos::terminal::clear(TERMINAL);
|
||||
let word = |i: usize| usize::from_le_bytes(key.0[i * 8..i * 8 + 8].try_into().unwrap_or([0; 8]));
|
||||
if answer(UNLOCK, [reply::OK, 0, 0, 0]) {
|
||||
let _ = answer(KEY, [word(0), word(1), word(2), word(3)]);
|
||||
}
|
||||
}
|
||||
Err(why) => {
|
||||
libkos::println!("gatekeeper: cannot go on: {:?}", why);
|
||||
let _ = answer(UNLOCK, [reply::FAILED, 0, 0, 0]);
|
||||
}
|
||||
}
|
||||
// Its capabilities go with it.
|
||||
syscall::exit()
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user