init: a protocol you were not granted does not exist
The registry consults the open rows it has been parsing since P2, so reaching a contract now takes a grant as well as a binding. A caller without one is answered exactly as it would be for a name nobody ever bound: same status, same empty reply, same absent capability, byte for byte, and no log line on either path — klog_read is ungated, so a line on one and not the other would be the oracle the design set out to remove. Refusal and absence being one answer is what lets a supervisor later narrow, fake or park a child's namespace without the child learning what it was denied. The manifest gains a third permission for a shape the plan did not foresee: attestation is one hop, but the driver tree is three deep — the PS/2 keyboard and mouse are spawned by ps2-bus, which the device manager spawned — so no row could name them and PS/2 input would simply stop. lets a delegate vouch for what its children *reach*, never for what they claim; the bind path is untouched, and the laundering deputy is still refused. The review found the receive side of a rule this track had already written down. Every process holds a sendable handle to the registrar — resolve installs one for anyone who asks — and ipc_reply_wait never asked who owned the endpoint, so a stranger could dequeue there: take the provider endpoints riding bind requests, and answer other clients' opens in the registrar's name. Receiving is the owner's privilege, like binding a signal or a timer; sending remains anyone's. Suite 109/109.
This commit is contained in:
@@ -332,7 +332,14 @@ fn systemIpcCall(state: *architecture.CpuState) void {
|
||||
/// ipc_reply_wait(handle, reply_ptr, reply_len, receive_ptr, receive_cap) -> receive_len,
|
||||
/// with the sender's badge in the secondary result register (rdx).
|
||||
fn systemIpcReplyWait(state: *architecture.CpuState) void {
|
||||
const endpoint = ipc.resolveHandle(scheduler.current(), architecture.systemCallArg(state, 0)) orelse return failErr(state, ipc.EBADF);
|
||||
const t = scheduler.current();
|
||||
const endpoint = ipc.resolveHandle(t, architecture.systemCallArg(state, 0)) orelse return failErr(state, ipc.EBADF);
|
||||
// Receiving is the owner's privilege, the same rule the notification binders
|
||||
// enforce: a sendable handle means only "you may talk to this". Anything
|
||||
// else and a mount's backend endpoint — which `fs_resolve` installs in every
|
||||
// caller's table — would let a stranger dequeue the requests meant for the
|
||||
// server, taking the capabilities they carry and answering in its name.
|
||||
if (!ipc.ownedBy(endpoint, t)) return failErr(state, ipc.EPERM);
|
||||
var badge: u64 = 0;
|
||||
var received_cap: u64 = abi.no_cap;
|
||||
const r = ipc.replyWait(endpoint, architecture.systemCallArg(state, 1), architecture.systemCallArg(state, 2), architecture.systemCallArg(state, 3), architecture.systemCallArg(state, 4), architecture.systemCallArg(state, 5), &badge, &received_cap);
|
||||
|
||||
Reference in New Issue
Block a user