P1 of docs/establishment-planes-plan.md. The bus no longer binds
/protocol/usb-transfer — the bind race made whichever instance came second
unreachable, which on a real three-controller Ryzen meant a mouse no class
driver could reach ("could not open device 50"). Each instance hands its
serving endpoint up in the hello that already delegates its controller, and
class drivers receive their OWN controller's channel from helloForChannel —
routed by the manager's lineage, retried while a provider is mid-restart,
on one manager handle so retries never spend handle-table slots.
usb.open(bus, id) now takes the channel it used to look up; the name rows
leave protocol.csv with the code (bind 67, opens 119/120/122); the
conformance fixture's prose stops claiming the bus binds; and the stale
input-client import leaves the bus with the channel one.
Gate: 19 QEMU cases green (usb family, hubs, both IOMMU variants, fat chain,
boot-from-USB, orderly shutdown, conformance).
176 lines
12 KiB
CSV
176 lines
12 KiB
CSV
# /system/configuration/protocol.csv — who may claim, and who may reach, a name
|
|
# under /protocol (docs/os-development/protocol-namespace.md).
|
|
#
|
|
# init is the registrar: it serves /protocol, and every bind AND every open is
|
|
# checked against this file. It is AUTHORITATIVE — a name no row grants cannot be
|
|
# bound or reached, and a missing file means nothing may be bound or reached at
|
|
# all.
|
|
#
|
|
# A refused open is answered exactly as a name nobody bound is: -ENOENT, and no
|
|
# capability. That is not politeness, it is the model — the namespace IS the
|
|
# restriction, so what a process may not open simply does not exist for it, and
|
|
# there is no "permission denied" for it to tell apart from "no such contract".
|
|
# Which is why a missing row here shows up as a client retrying forever rather
|
|
# than as an error: check this file first, and `readdir /protocol` second.
|
|
#
|
|
# '#' starts a comment (whole-line or trailing); blank lines are ignored.
|
|
# Whitespace around a field is trimmed, so columns may be padded. Four
|
|
# comma-separated fields per row:
|
|
#
|
|
# binary the claimant's binary path, exactly as the kernel stamped it at
|
|
# spawn (argv[0]) — unforgeable, read from the process records
|
|
# supervisor the authorized supervising TASK, written as the binary it runs —
|
|
# the path init was started as for its own services, the device
|
|
# manager's path for the drivers it starts. The one word that is not
|
|
# a path is 'kernel', because a kernel task has no binary; that is
|
|
# what the test harness's direct spawns look like.
|
|
# Matched by IDENTITY, not by spelling. Name alone is not identity —
|
|
# spawn is ungated, so a hostile process can start a granted binary
|
|
# itself and inherit its grants; and it can equally start its own
|
|
# instance of the *supervisor's* binary and have that spawn the
|
|
# granted one, at which point both names read correctly (the
|
|
# laundering deputy). So init also asks which task the supervisor
|
|
# is: 'kernel' means supervisor id 0, which only the kernel can
|
|
# confer; init's own path means this init; any other path means a
|
|
# task init spawned itself or one the kernel spawned. Task ids are
|
|
# monotonic and never reused, so an id cannot be borrowed.
|
|
# permission bind (provide this contract) | open (speak to it) |
|
|
# supervise (stand in someone else's chain — see below)
|
|
# name the contract, relative to /protocol
|
|
#
|
|
# A trailing '*' on any field matches any tail — how a subtree is granted whole.
|
|
#
|
|
# 'supervise' exists because attestation is one hop deep and the driver tree is
|
|
# three: the device manager starts the PS/2 bus, and the bus starts the keyboard
|
|
# and mouse drivers. Init never met the bus, so it cannot vouch for it by
|
|
# acquaintance — and it must not vouch for it by name, or the laundering deputy
|
|
# walks straight in. A 'supervise' row is the manifest saying it: a task running
|
|
# this binary, under this supervisor, may be the supervising task an 'open' row
|
|
# names, for this contract and no other. It grants the delegate nothing itself,
|
|
# and it is deliberately open-only — a delegate may vouch for what its children
|
|
# REACH, never for what they CLAIM, so every bind refusal is untouched by it.
|
|
#
|
|
# binary supervisor permission name
|
|
|
|
# --- the services init spawns from init.csv ---------------------------------
|
|
/system/services/input, /system/services/init, bind, input
|
|
/system/services/device-manager, /system/services/init, bind, device-manager
|
|
/system/services/fat, /system/services/init, bind, vfs
|
|
/system/services/display, /system/services/init, bind, display
|
|
|
|
# The discovery service ships under one neutral name per firmware (docs/discovery.md);
|
|
# on x86 it is the acpi service, and what it provides is the power contract.
|
|
/system/services/discovery, /system/services/device-manager, bind, power
|
|
|
|
# --- the drivers, which the device manager spawns ---------------------------
|
|
# usb-transfer has NO bind row: several bus processes provide it (one per
|
|
# controller), so it is never a registry name — consumers get their controller's
|
|
# channel from the device manager's hello, routed by lineage (communication.md
|
|
# "Establishment: two planes, one namespace").
|
|
/system/drivers/ps2-bus, /system/services/device-manager, bind, ps2-bus
|
|
/system/drivers/usb-storage, /system/services/device-manager, bind, block
|
|
/system/drivers/virtio-gpu, /system/services/device-manager, bind, scanout
|
|
|
|
# --- the same providers when the kernel test harness starts them directly ---
|
|
# A scenario boot spawns its own providers instead of letting init do it
|
|
# (docs/security-track-plan.md, decision 9), so the same binaries appear with
|
|
# 'kernel' as the supervisor. Nothing else changes: the binary must still match.
|
|
/system/services/input, kernel, bind, input
|
|
/system/services/device-manager, kernel, bind, device-manager
|
|
/system/services/fat, kernel, bind, vfs
|
|
/system/services/display, kernel, bind, display
|
|
/system/services/discovery, kernel, bind, power
|
|
|
|
# --- test fixtures ----------------------------------------------------------
|
|
# The subtree rule, dogfooded: anything installed under /test may claim anything
|
|
# under /protocol/test, and nothing above it — whether the harness spawned it or
|
|
# another fixture did.
|
|
/test/*, kernel, bind, test/*
|
|
/test/*, /test/*, bind, test/*
|
|
|
|
|
|
# ============================================================================
|
|
# open — who may REACH each contract. One row per client per contract; a client
|
|
# with no row here simply finds the name absent, forever.
|
|
# ============================================================================
|
|
|
|
# --- init's own services ----------------------------------------------------
|
|
# fat reaches the block device behind the volume it mounts; the compositor
|
|
# reaches the scanout its driver announced, its own endpoint (the mouse-listener
|
|
# thread opens /protocol/display like any other client — threads share no
|
|
# handles), and the input stream that moves the cursor.
|
|
/system/services/fat, /system/services/init, open, block
|
|
/system/services/display, /system/services/init, open, scanout
|
|
/system/services/display, /system/services/init, open, display
|
|
/system/services/display, /system/services/init, open, input
|
|
/system/services/display-demo, /system/services/init, open, display
|
|
|
|
# --- the same two when the kernel test harness starts them directly ---------
|
|
/system/services/display, kernel, open, scanout
|
|
/system/services/display, kernel, open, display
|
|
/system/services/display, kernel, open, input
|
|
/system/services/display-demo, kernel, open, display
|
|
|
|
# --- the drivers, and the discovery service ---------------------------------
|
|
# Every driver says hello to the manager that started it — one row for the whole
|
|
# subtree, because that handshake is what being a driver means. The rest are per
|
|
# driver: the storage and HID class drivers talk to their controller, the HID
|
|
# drivers publish into the input stream, and the GPU driver announces its scanout
|
|
# to the compositor.
|
|
/system/drivers/*, /system/services/device-manager, open, device-manager
|
|
/system/services/discovery, /system/services/device-manager, open, device-manager
|
|
/system/drivers/usb-hid-keyboard, /system/services/device-manager, open, input
|
|
/system/drivers/usb-hid-mouse, /system/services/device-manager, open, input
|
|
/system/drivers/virtio-gpu, /system/services/device-manager, open, display
|
|
|
|
# --- the PS/2 child drivers, one hop further down ---------------------------
|
|
# The keyboard and mouse drivers are started by the BUS driver, not by the
|
|
# device manager — the one three-deep chain in the tree. Init cannot vouch for
|
|
# the bus by acquaintance (it never started it), so the manifest authorizes it
|
|
# explicitly, and only for the two contracts its children need.
|
|
/system/drivers/ps2-bus, /system/services/device-manager, supervise, ps2-bus
|
|
/system/drivers/ps2-bus, /system/services/device-manager, supervise, input
|
|
/system/drivers/ps2-keyboard, /system/drivers/ps2-bus, open, ps2-bus
|
|
/system/drivers/ps2-keyboard, /system/drivers/ps2-bus, open, input
|
|
/system/drivers/ps2-mouse, /system/drivers/ps2-bus, open, ps2-bus
|
|
/system/drivers/ps2-mouse, /system/drivers/ps2-bus, open, input
|
|
|
|
# --- test fixtures ----------------------------------------------------------
|
|
# The /protocol/test subtree is theirs whole, the way the bind rows give it to
|
|
# them. Everything ABOVE that subtree is named one fixture at a time, so a
|
|
# fixture reaches a system contract only where a scenario needs it — which is
|
|
# what leaves the rest genuinely absent for the rest of them (the protocol-denied
|
|
# case asks for one it was not given, and is told there is no such thing).
|
|
/test/*, kernel, open, test/*
|
|
/test/*, /test/*, open, test/*
|
|
/test/*, kernel, open, device-manager
|
|
/test/*, /system/services/device-manager, open, device-manager
|
|
/test/system/services/input-source, kernel, open, input
|
|
/test/system/services/input-test, kernel, open, input
|
|
|
|
# The guessable-id probe (test/system/services/badge-scope-test) runs as two
|
|
# processes of one binary: the owner, which the scenario spawns, and the intruder,
|
|
# which the owner spawns with the ids it holds. Both reach the compositor — the
|
|
# owner to create the layer, the intruder to be refused it — so the binary is
|
|
# named twice, once per supervisor. The second row needs no 'supervise'
|
|
# delegation: the owner was spawned by the KERNEL, which is a chain init can
|
|
# vouch for on its own.
|
|
/test/system/services/badge-scope-test, kernel, open, display
|
|
/test/system/services/badge-scope-test, /test/*, open, display
|
|
|
|
# The conformance probe (test/system/services/protocol-conformance-test) asks
|
|
# every provider its boot bound for the envelope's reserved verbs. It reaches
|
|
# ONLY the two contracts its own scenario boots a provider for, named one at a
|
|
# time exactly like the two rows above — no subtree, no wildcard. Everything else
|
|
# under /protocol stays absent for it, which is the point: the fixture walks the
|
|
# namespace listing and reports what it could not open rather than being handed
|
|
# the tree to make the test look broad.
|
|
/test/system/services/protocol-conformance-test, kernel, open, input
|
|
/test/system/services/protocol-conformance-test, kernel, open, display
|
|
|
|
# The laundering-deputy probe (test/system/services/protocol-registry-test) runs
|
|
# a grandchild whose supervisor is a fixture nobody authorized — that is the
|
|
# point of it, and its bind must stay refused. It still has to report the verdict
|
|
# it got, so its reporting channel, and nothing else, is delegated.
|
|
/test/*, /test/*, supervise, test/verdict
|