Files
danos/system/configuration/protocol.csv
T
Daniel Samson d56b1b81c0 volume-manager: discovery and probe — V3a
The storage layer gains its policy home (storage-architecture.md): a new
system/services/volume-manager, spawned by init, that acquires the mass-
storage block channel through the device manager (the same lineage a
filesystem uses), reads block 0, and parses the first volume out of it. The
partition-table walk that lived in the FAT engine moves here, above the
driver where it belongs (partition.zig, host-tested: MBR entry, bare-FAT,
no-signature). Identity is the MBR disk signature + partition index — the
weak rung of the ladder; GPT GUID and FAT serial refine identityOf without
changing shape.

This increment is discovery + probe + log only, additive: the FAT service
still acquires its own volume, so nothing changes for it. Confining each
filesystem to its partition and spawning one per volume (the flip) lands
next, keeping fat working throughout.

Grants + wiring: init.csv spawns it after the device manager; protocol.csv
grants bind volume-manager + open device-manager. Verified: volume-probe
asserts the parse (bare-FAT volume at lba 0), neutral 10/10 across storage,
restart, display, logging, confinement — the volume manager now runs in
every boot and disturbs nothing.
2026-08-09 18:10:43 +01:00

13 KiB

1# /system/configuration/protocol.csv — who may claim, and who may reach, a name
2# under /protocol (docs/os-development/protocol-namespace.md).
3#
4# init is the registrar: it serves /protocol, and every bind AND every open is
5# checked against this file. It is AUTHORITATIVE — a name no row grants cannot be
6# bound or reached, and a missing file means nothing may be bound or reached at
7# all.
8#
9# A refused open is answered exactly as a name nobody bound is: -ENOENT, and no
10# capability. That is not politeness, it is the model — the namespace IS the
11# restriction, so what a process may not open simply does not exist for it, and
12# Which is why a missing row here shows up as a client retrying forever rather
13# than as an error: check this file first, and `readdir /protocol` second.
14#
15# '#' starts a comment (whole-line or trailing); blank lines are ignored.
16# Whitespace around a field is trimmed, so columns may be padded. Four
17# comma-separated fields per row:
18#
19# binary the claimant's binary path, exactly as the kernel stamped it at
20# spawn (argv[0]) — unforgeable, read from the process records
21# supervisor the authorized supervising TASK, written as the binary it runs —
22# the path init was started as for its own services, the device
23# manager's path for the drivers it starts. The one word that is not
24# a path is 'kernel', because a kernel task has no binary; that is
25# what the test harness's direct spawns look like.
26# Matched by IDENTITY, not by spelling. Name alone is not identity —
27# spawn is ungated, so a hostile process can start a granted binary
28# itself and inherit its grants; and it can equally start its own
29# instance of the *supervisor's* binary and have that spawn the
30# granted one, at which point both names read correctly (the
31# laundering deputy). So init also asks which task the supervisor
32# is: 'kernel' means supervisor id 0, which only the kernel can
33# confer; init's own path means this init; any other path means a
34# task init spawned itself or one the kernel spawned. Task ids are
35# monotonic and never reused, so an id cannot be borrowed.
36# permission bind (provide this contract) | open (speak to it) |
37# supervise (stand in someone else's chain — see below)
38# name the contract, relative to /protocol
39#
40# A trailing '*' on any field matches any tail — how a subtree is granted whole.
41#
42# 'supervise' exists because attestation is one hop deep and the driver tree is
43# three: the device manager starts the PS/2 bus, and the bus starts the keyboard
44# and mouse drivers. Init never met the bus, so it cannot vouch for it by
45# acquaintance — and it must not vouch for it by name, or the laundering deputy
46# walks straight in. A 'supervise' row is the manifest saying it: a task running
47# this binary, under this supervisor, may be the supervising task an 'open' row
48# names, for this contract and no other. It grants the delegate nothing itself,
49# and it is deliberately open-only — a delegate may vouch for what its children
50# REACH, never for what they CLAIM, so every bind refusal is untouched by it.
51#
52# binary supervisor permission name
53# --- the services init spawns from init.csv ---------------------------------
54/system/services/input, /system/services/init, bind, input
55/system/services/device-manager, /system/services/init, bind, device-manager
56/system/services/volume-manager, /system/services/init, bind, volume-manager
57/system/services/fat, /system/services/init, bind, vfs
58/system/services/display, /system/services/init, bind, display
59# The discovery service ships under one neutral name per firmware (docs/discovery.md);
60# on x86 it is the acpi service, and what it provides is the power contract.
61/system/services/discovery, /system/services/device-manager, bind, power
62# --- the drivers, which the device manager spawns ---------------------------
63# usb-transfer and block have NO bind rows: several processes provide each (one
64# per controller, one per volume), so neither is ever a registry name —
65# consumers get their provider's channel from the device manager's hello,
66/system/drivers/ps2-bus, /system/services/device-manager, bind, ps2-bus
67/system/drivers/virtio-gpu, /system/services/device-manager, bind, scanout
68# --- the same providers when the kernel test harness starts them directly ---
69# A scenario boot spawns its own providers instead of letting init do it
70# (docs/security-track-plan.md, decision 9), so the same binaries appear with
71# 'kernel' as the supervisor. Nothing else changes: the binary must still match.
72/system/services/input, kernel, bind, input
73/system/services/device-manager, kernel, bind, device-manager
74/system/services/fat, kernel, bind, vfs
75/system/services/display, kernel, bind, display
76/system/services/discovery, kernel, bind, power
77# --- test fixtures ----------------------------------------------------------
78# The subtree rule, dogfooded: anything installed under /test may claim anything
79# under /protocol/test, and nothing above it — whether the harness spawned it or
80# another fixture did.
81/test/*, kernel, bind, test/*
82/test/*, /test/*, bind, test/*
83# ============================================================================
84# open — who may REACH each contract. One row per client per contract; a client
85# with no row here simply finds the name absent, forever.
86# ============================================================================
87# --- init's own services ----------------------------------------------------
88# fat reaches the device manager to be routed to its volume's block provider
89# (block is not a name — see the bind section); the compositor reaches the
90# scanout its driver announced, its own endpoint (the mouse-listener thread
91# opens /protocol/display like any other client — threads share no handles),
92# and the input stream that moves the cursor.
93/system/services/fat, /system/services/init, open, device-manager
94# The volume manager reaches the device manager to be routed to each storage
95# provider's block channel, the same lineage acquisition fat makes today.
96/system/services/volume-manager, /system/services/init, open, device-manager
97/system/services/display, /system/services/init, open, scanout
98/system/services/display, /system/services/init, open, display
99/system/services/display, /system/services/init, open, input
100/system/services/display-demo, /system/services/init, open, display
101# --- the same two when the kernel test harness starts them directly ---------
102/system/services/display, kernel, open, scanout
103/system/services/display, kernel, open, display
104/system/services/display, kernel, open, input
105/system/services/display-demo, kernel, open, display
106# --- the drivers, and the discovery service ---------------------------------
107# Every driver says hello to the manager that started it — one row for the whole
108# subtree, because that handshake is what being a driver means. The rest are per
109# driver: the storage and HID class drivers talk to their controller, the HID
110# drivers publish into the input stream, and the GPU driver announces its scanout
111# to the compositor.
112/system/drivers/*, /system/services/device-manager, open, device-manager
113/system/services/discovery, /system/services/device-manager, open, device-manager
114/system/drivers/usb-hid-keyboard, /system/services/device-manager, open, input
115/system/drivers/usb-hid-mouse, /system/services/device-manager, open, input
116/system/drivers/virtio-gpu, /system/services/device-manager, open, display
117# --- the PS/2 child drivers, one hop further down ---------------------------
118# The keyboard and mouse drivers are started by the BUS driver, not by the
119# device manager — the one three-deep chain in the tree. Init cannot vouch for
120# the bus by acquaintance (it never started it), so the manifest authorizes it
121# explicitly, and only for the two contracts its children need.
122/system/drivers/ps2-bus, /system/services/device-manager, supervise, ps2-bus
123/system/drivers/ps2-bus, /system/services/device-manager, supervise, input
124/system/drivers/ps2-keyboard, /system/drivers/ps2-bus, open, ps2-bus
125/system/drivers/ps2-keyboard, /system/drivers/ps2-bus, open, input
126/system/drivers/ps2-mouse, /system/drivers/ps2-bus, open, ps2-bus
127/system/drivers/ps2-mouse, /system/drivers/ps2-bus, open, input
128# --- test fixtures ----------------------------------------------------------
129# The /protocol/test subtree is theirs whole, the way the bind rows give it to
130# them. Everything ABOVE that subtree is named one fixture at a time, so a
131# fixture reaches a system contract only where a scenario needs it — which is
132# what leaves the rest genuinely absent for the rest of them (the protocol-denied
133# case asks for one it was not given, and is told there is no such thing).
134/test/*, kernel, open, test/*
135/test/*, /test/*, open, test/*
136/test/*, kernel, open, device-manager
137/test/*, /system/services/device-manager, open, device-manager
138/test/system/services/input-source, kernel, open, input
139/test/system/services/input-test, kernel, open, input
140# The guessable-id probe (test/system/services/badge-scope-test) runs as two
141# processes of one binary: the owner, which the scenario spawns, and the intruder,
142# which the owner spawns with the ids it holds. Both reach the compositor — the
143# owner to create the layer, the intruder to be refused it — so the binary is
144# named twice, once per supervisor. The second row needs no 'supervise'
145# delegation: the owner was spawned by the KERNEL, which is a chain init can
146# vouch for on its own.
147/test/system/services/badge-scope-test, kernel, open, display
148/test/system/services/badge-scope-test, /test/*, open, display
149# The conformance probe (test/system/services/protocol-conformance-test) asks
150# every provider its boot bound for the envelope's reserved verbs. It reaches
151# ONLY the two contracts its own scenario boots a provider for, named one at a
152# time exactly like the two rows above — no subtree, no wildcard. Everything else
153# under /protocol stays absent for it, which is the point: the fixture walks the
154# namespace listing and reports what it could not open rather than being handed
155# the tree to make the test look broad.
156/test/system/services/protocol-conformance-test, kernel, open, input
157/test/system/services/protocol-conformance-test, kernel, open, display
158# The laundering-deputy probe (test/system/services/protocol-registry-test) runs
159# a grandchild whose supervisor is a fixture nobody authorized — that is the
160# point of it, and its bind must stay refused. It still has to report the verdict
161# it got, so its reporting channel, and nothing else, is delegated.
162/test/*, /test/*, supervise, test/verdict