host/taint: pin what "resolved" must mean before F11-1 is implemented
Round 12 re-examined the deferral and agreed it holds while evaluate() is audit-only, and that the recorded rule closes the path without unbounding Pulse-emulated apps — but only under one reading of "a node whose Client cannot be resolved at all". The trap is worth writing down before anyone implements it: reading "resolved" as "a unique Client object exists" passes for a unique Client with sec_pid = None, which supplies no protected identity and leaves exactly the self-claimed-PID hole the rule exists to close. It has to mean an unambiguous Client yielding Some(pipewire.sec.pid), taken before pipewire-pulse suppression. That also means the §5.1 matrix needs five Client cases rather than two: absent, ambiguous, unique-but-pid-less, resolved-native, and resolved-to-pipewire-pulse. The pid-less row is the one that distinguishes the two readings and the one a two-case matrix skips without saying so. Docs only. Still deferred, still to be decided with matrix data in hand. 220 tests green, clippy clean. Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
This commit is contained in:
@@ -300,6 +300,28 @@ fn keys_of(node: &NodeSnapshot, ctx: &OwnerCtx) -> Vec<(OwnerKey, KeyValue)> {
|
||||
/// ⚠️ Do this **with the §5.1 matrix data in hand**, not before: the whole
|
||||
/// question is how much over-exclusion the rule actually causes on a real
|
||||
/// graph, and that is measurable rather than arguable.
|
||||
///
|
||||
/// ## Round 12 — the deferral holds, and "resolved" has a trap in it
|
||||
///
|
||||
/// Codex re-examined this and agreed the deferral is defensible while
|
||||
/// `evaluate()` is audit-only, and that the rule above closes the recorded path
|
||||
/// without unbounding normal Pulse-emulated apps — **but only under one
|
||||
/// reading of "resolves"**, and the wrong reading reintroduces the hole:
|
||||
///
|
||||
/// - ✅ "Resolved" must mean **an unambiguous Client that yields
|
||||
/// `Some(pipewire.sec.pid)`**, taken *before* the pipewire-pulse suppression
|
||||
/// step. A Pulse app then still has the daemon's protected PID as
|
||||
/// provenance, even though that value is omitted from the bridge keys, so it
|
||||
/// stays bounded and the eligible half survives.
|
||||
/// - ❌ **Do not** implement it as "a unique Client object exists". A unique
|
||||
/// Client with `sec_pid = None` would satisfy that test while providing no
|
||||
/// protected identity at all, leaving exactly the self-claimed-PID hole this
|
||||
/// rule is meant to close.
|
||||
///
|
||||
/// So the matrix needs five Client cases, not two: **absent**, **ambiguous**,
|
||||
/// **unique but pid-less**, **resolved-native**, and
|
||||
/// **resolved-to-pipewire-pulse**. The third is the one that distinguishes the
|
||||
/// two readings, and it is the row a two-case matrix would silently skip.
|
||||
pub fn owner_is_bounded(node: &NodeSnapshot, ctx: &OwnerCtx) -> bool {
|
||||
keys_of(node, ctx)
|
||||
.iter()
|
||||
|
||||
Reference in New Issue
Block a user