PiROS — a provable-runtime x86 OS (proof of concept)
A from-scratch x86_64 operating system whose organizing principle is: a program runs only if it can prove it is the exact, unmodified thing the package authority signed. Every hardware interaction goes through a lowest-common-denominator abstraction, so any backend can be swapped for another that meets the same API and the OS is unaffected.
It has grown from a kernel that boots and runs echo into a small multi-user system: ring-3 isolated programs loaded from a signed /bin, per-user encrypted persistent storage, cross-user publishing, a full-screen editor, shell scripting, and runtime program installation — all still gated by the same rule (a program runs only if it verifies, A + B = C). See GUIDE.md to use it and ARCHITECTURE.md for the design.
What works today
A multi-user system you log into on the serial console, where every command is an authorized, integrity-verified, ring-3 tool invocation:
login: bob bobpw
bob@pros> echo bob secret notes > files/notes # written through the encryption vault
bob@pros> grep secret files/notes # grep is a separate loaded ELF
bob secret notes
bob@pros> iamgood iambad # bob holds the iamgood grant
Yes bob, you are good!
bob@pros> logout
login: mary marypw
mary@pros> ls files # Mary cannot see Bob's /data
(empty)
mary@pros> iamgood iambad # Mary wasn't granted iamgood
[DENIED] no grant for service 'iamgood'
Every tool is a real ELF loaded from the ramdisk, verified, and run unprivileged. Tamper a program's ELF and the loader refuses it (image does not match signed hash); run a privileged instruction and the process is killed while the shell survives.
Proven end-to-end:
- Boots on bare x86_64 (long mode) in QEMU; all hardware access goes through a HAL
(today a 16550 UART on COM1).
- Microkernel + signed
/binramdisk — tools are not in the kernel. Each is a
separately-compiled freestanding ELF, packed into a ramdisk the bootloader hands the kernel. The kernel loads it into an RWX window, verifies its ELF against the signed manifest, and runs it via a syscall table. The kernel binary is byte-identical when a tool changes — OS and toolchain are decoupled.
- Isolation (ring 3) — tools run unprivileged; their only path to the kernel is
an int 0x80 syscall trap. A tool that runs a privileged instruction or touches memory it doesn't own is killed, and the shell survives — not a kernel crash.
- Integrity over real code — verification now covers the actual executable bytes
(ed25519 signature + SHA-256 of the ELF). Tamper the ELF in the ramdisk → denied.
- Authorization — signed capability grants decide what user
bobmay run.
core is the ambient namespace (its tools run bare); a service is a namespace, not a macro (text_tools cat … uses the cluster grant). iambad is in neither core nor text_tools, so it is denied bare and reachable only via iamgood. Deny-by-default.
- Multi-user — authority-signed users (
root,bob,mary), login/su/logout,
password-hash auth. Each user has an isolated /data/$user; ownership is enforced at the syscall trap, so a tool can only ever touch its owner's data. Grants are per-user.
- Persistent, encrypted storage —
/datais backed by an ATA disk image
(write-through), auto-mounted at boot, so files survive reboots. Every file is sealed with ChaCha20 + HMAC-SHA256 (per-user key) before storage — the raw disk holds ciphertext (verified: file contents don't appear in the image).
- Dev tools —
cp,rm, andprano(a full-screen editor: arrows,^Osave,
^X exit). Edit a file, reboot, and it's still there.
- Cross-user publishing —
publish <file> <user>shares a file;argo owner:name
fetches it if you're in the audience. The kernel decrypts with the owner's key and enforces access — Mary can publish to Bob, and a non-audience user is denied.
- Shell scripting + history —
run <file>executes a file of commands;history
and ↑/↓ recall recent commands. Author a script with prano, run it, and it persists on the encrypted disk.
- Persistent
/bin+ install — the baked ramdisk is the immutable core; a signed
program can be installed into a writable disk overlay and it persists across reboots, no OS rebuild. Safe because the kernel verifies signatures at load — a tampered install is refused. (This is how you add a compiled program, e.g. a browser.)
- Userland heap + scripting — tools can use
alloc(Vec/String/Box).pshis a
small PHP/bash-style scripting language ($vars, if/while, string interpolation, file I/O). Author a .psh script and run it with psh <file>.
- Ownership —
/data/$user/{files,logs,tmp}: the user directs writes into
files/; programs author logs//tmp/, readable but not user-writable (so logs are provenance-preserving).
Beyond the base — networking, multitasking, services
- A from-scratch network stack — RTL8139 driver → ARP → IPv4/ICMP → UDP/DNS → TCP →
HTTP, with RTT/RTO estimation and Reno-style congestion control (slow start + congestion avoidance) on the TCP send side. ping, nslookup/host, curl (prints the raw response), wget <url> [dest] (saves the body into files/), and a text-mode web reader all hit the real internet from ring-3 programs via server/client socket syscalls.
- SSH both ways — a from-scratch SSH-2 stack (curve25519 / ed25519 / aes-ctr / hmac):
a client that verifies GitHub's host key, and a server you can log into with a password or an authorized_keys pubkey (real OpenSSH clients interoperate). The server spawns one worker task per accepted connection, so several users hold sessions concurrently — each with its own identity and privileges (bounded by the task table, ~3–5 at once; a full table refuses a new connection with a one-line hint). ssh <box> '<cmd>' runs a single command non-interactively (output + exit status), so a monitoring tool can probe the box like a Linux server.
- Cached file descriptors — a RAM storage cache backs a POSIX-style file-descriptor API
(fopen/fread/fwrite/fflush/fclose/fsize): a ring-3 program opens a file in its own store into a plaintext cache, reads and writes it by offset (random access), then flushes/closes it back through the encryption vault — turning the whole-file vfs into random-access, write-back descriptors. The same cache stages OS upgrades.
- Live administration — root mints users, grants, and services at runtime, signed
by a per-box machine key (the offline authority key never touches the machine). admin user create / admin grant / admin service create.
- Shared read-only
/mnt— a volume built from a host folder at build time, readable
by all users (e.g. mnt/authorized_keys for provisioning SSH keys).
- Real multitasking — per-process address spaces (each process its own page table),
a cooperative scheduler (kernel-stack context switch), and spawn — so a program runs as a sandboxed, isolated, scheduled process.
- Background services —
admin service start/stop <name>(root-only) runs a daemon in
the background while the console stays usable: sshd (kernel-hosted), tintin (HTTP), nemo (FTP), queequeg (SQL) — the last three as sandboxed ring-3 processes running as their own no-login service user. ps lists them; syslog records events + resource snapshots (the run-up to a crash).
Users: root/rootpw, bob/bobpw, mary/marypw (root+bob get all services; mary gets core). Tools (in /bin): echo, cat, ls, grep, cp, rm, prano, publish, argo, curl, wget, asterix, psh, list_build/list_get/list_save, iambad, hello. publish=produce, argo=consume what another user published (argo owner:name [dest], argo --list owner; no network); wget/curl=HTTP. Services: core (echo, cat, ls, grep, cp, rm, prano, publish, wget, argo, asterix, hello, psh), text_tools, iamgood, and admin (list_build, list_get, list_save — root only).
New here? See GUIDE.md for the full command reference, the publish/fetch workflow, and how to write, sign, and install your own programs. UAT.md has step-by-step acceptance tests (incl. the admin list workflow).
Build & run
Prerequisites (installed automatically if you used the setup in this repo): a Rust nightly toolchain with rust-src + llvm-tools-preview, and qemu-system-x86_64.
./build.sh # compile tools, sign them, pack /bin, build the kernel, boot in QEMU
./build.sh --build # build the bootable image only (dist/pros-bios.img)
QEMU emulates x86 on non-x86 hosts, so the kernel takes a few seconds to reach the pros> prompt. Type quit to power the machine off.
Rebuild only the tools (kernel untouched) to see the decoupling:
(cd programs && cargo build --release) # tools only
cargo test --manifest-path crates/cert/Cargo.toml # host-side SHA-256 tests
Layout
| Path | Role |
|---|---|
kernel/ | The no_std microkernel (/os): HAL/IO, auth/verify, program loader, builtins. Holds only the authority PUBLIC key. |
crates/abi/ | The program ABI: entry signature + syscall table both sides compile against. |
crates/cert/ | The manifest/grant schema + verifier (/manifest/schema). Shared by signer and kernel. |
crates/rt/ | Tool runtime: entry glue, panic handler, syscall wrapper. Every tool links it. |
programs/<name>/ | A tool — a freestanding binary crate (echo, cat, ls, grep, cp, rm, prano, publish, wget, asterix, …), built independently of the kernel. |
tools/manifest/ | The authority (/manifest/bin). Holds the PRIVATE key: signs programs, grants, users; never runs them. |
tools/ramdisk/ | Packs the signed programs into the baked /bin ramdisk. |
tools/install/ | Installs a signed program into the persistent /bin overlay on data.img (no OS rebuild). |
tools/bootbuild/ | Joins the kernel ELF + ramdisk into a bootable BIOS image. |
See ARCHITECTURE.md for the design, the certificate model, and the roadmap toward the full runtime directory tree (/os, /bin, /manifest, /data/$user).
License
PiROS is GPL-2.0 — see LICENSE.
The TCP send-side control logic (kernel/src/net/tcp_input.rs, and the parts of kernel/src/net/tcp.rs that drive it) is derived from the Linux kernel: net/ipv4/tcp_input.c, net/ipv4/tcp_cong.c, and include/net/tcp.h. Because tcp_input.c is GPL-2.0 only (not "or later"), the combined work is GPL-2.0 only. Every other dependency is MIT or MIT/Apache-2.0 dual-licensed, so all are GPL-2.0-compatible under their MIT option.
Distributing a pros-rN.img therefore means offering the corresponding source under the GPL.
Developing across more than one machine (or more than one agent)? See CONTRIBUTING.md for the branch/merge workflow, the Ubuntu + KVM + bare-metal setup, and the component-ownership map that keeps parallel work from colliding — plus TASKS.md, the live board of who owns what.