docs: the security-track execution plan — path flag-day, namespace phases, kernel hardening
The /loop work list for the committed design set: Phase 0 baseline, PM (unix-path flag-day), H1 copy discipline, P1 envelope + Channel, P2 registry + ServiceId retirement, P3 open grants, P4a-c protocol rebase, H2 SMEP, HS sysret guard, H3 SMAP. Ten settled decisions from the 2026-07-31 grounding pass, two corrected on review: every packet carries the envelope header folded (headerless events rejected), and bind/open authorization is chain-attested identity (name alone rejected — ungated spawn makes it a confused deputy). smep-smap.md gains the verified straggler table: nine syscalls, klog_status the ninth, with the callee-writer restructuring notes.
This commit is contained in:
@@ -52,26 +52,38 @@ The design is closer than it looks, because the IPC layer was built right:
|
||||
- **CR4 today:** the BSP inherits firmware CR4 (no kernel write anywhere);
|
||||
APs set PAE/OSFXSR/OSXMMEXCPT in `trampoline.s:62-68`. Neither path sets
|
||||
SMEP/SMAP yet, and both must.
|
||||
- **The stragglers.** A handful of syscalls still dereference user pointers
|
||||
raw after a bounds check — every one is a SMAP #PF waiting to happen, and
|
||||
- **The stragglers.** Nine syscalls still dereference user pointers raw
|
||||
after a bounds check — every one is a SMAP #PF waiting to happen, and
|
||||
every one is *already* a latent kernel fault today (an unmapped-but-in-
|
||||
range user page oopses the kernel instead of failing the call). The audit
|
||||
list, from the 2026-07-31 survey of `system/kernel/process.zig`:
|
||||
range user page oopses the kernel instead of failing the call). The
|
||||
verified sweep of `system/kernel/process.zig` (2026-07-31; a
|
||||
whole-kernel `@ptrFromInt` audit found no user-address dereference
|
||||
outside this file):
|
||||
|
||||
| Syscall | Raw access |
|
||||
|---|---|
|
||||
| `system_spawn` | name + argument blob (`:972`, `:980`) |
|
||||
| `fs_resolve` | path in, result out (`:1780`, `:1797`) |
|
||||
| `fs_mount` / `fs_unmount` | prefix + rewrite strings (`:1864`) |
|
||||
| `fs_node` | read buffer out (`:1820`) |
|
||||
| `debug_write` | message bytes (`:1700`) |
|
||||
| `klog_read` | log bytes out (`:1740`) |
|
||||
| `process_enumerate` | descriptor array out (`:1132`) |
|
||||
| `device_enumerate` | descriptor array out (`:388`) |
|
||||
| Syscall | Raw access | Direction |
|
||||
|---|---|---|
|
||||
| `system_spawn` | name + argument blob (`:972`, `:980`) | read |
|
||||
| `fs_resolve` | path in (`:1780`), result out (`:1797`) | read + write |
|
||||
| `fs_mount` | prefix + rewrite strings (`:1864`, `:1865`) | read |
|
||||
| `fs_unmount` | prefix string (`:1883`) | read |
|
||||
| `fs_node` | read buffer out (`:1820`) | write |
|
||||
| `debug_write` | message bytes (`:1700`; read twice — memcpy `:1710` and `log.append` `:1717`) | read |
|
||||
| `klog_read` | log bytes out (`:1741`) | write |
|
||||
| `klog_status` | status struct out (`:1758`) | write |
|
||||
| `process_enumerate` | descriptor array out (`:1132`) | write |
|
||||
| `device_enumerate` | descriptor array out (`:388`) | write |
|
||||
|
||||
For the write-direction rows the `@ptrFromInt` is in process.zig but the
|
||||
stores happen in callees (`scheduler.enumerate`
|
||||
`system/kernel/scheduler.zig:1209`, `devices_broker.enumerate`
|
||||
`devices-broker.zig:136`, `log.readAt` `log.zig:209`, the vfs node calls
|
||||
`vfs.zig:257/269/289`) — converting them means bounce buffers plus
|
||||
`copyToUser` around those calls, not just editing the process.zig lines.
|
||||
(Some paths already do it right — the futex word and the device-register
|
||||
descriptor go through `copyFromUser` (`:1087`, `:924`). The write
|
||||
direction has no helper yet.)
|
||||
direction has no public helper yet, but the mechanism exists:
|
||||
`copyAcross` with a kernel source is exactly how IPC replies reach user
|
||||
buffers, so `copyToUser` is a mechanical mirror.)
|
||||
|
||||
- **One known gap inside the copy layer itself:** the walk checks presence,
|
||||
not the leaf U/S and writable bits (`ipc-synchronous.zig:20-22` flags
|
||||
@@ -85,7 +97,7 @@ The design is closer than it looks, because the IPC layer was built right:
|
||||
**H1 — copy discipline (the real work).** A `user-memory` kernel module:
|
||||
`copyFromUser` / `copyToUser` (the missing write direction) via the physmap
|
||||
walk, with U/S and writable leaf checks closing the in-tree TODO. Convert
|
||||
the eight stragglers. This fixes the latent unmapped-page kernel fault on
|
||||
the nine stragglers. This fixes the latent unmapped-page kernel fault on
|
||||
its own — it is worth doing even if SMEP/SMAP never shipped. QEMU suite
|
||||
green; no behavior change visible to correct programs.
|
||||
|
||||
|
||||
Reference in New Issue
Block a user