Skip to content

Registry entry leaks when open_uni() fails in handle_renderer_connection #411

Description

@forkwright

Finding

handle_renderer_connection adds a ConnectedRenderer entry to the shared registry and then immediately calls connection.open_uni().await?. If open_uni returns an error, the ? operator forces an early return before the registry.remove(&session_id).await cleanup, so the entry is permanently stuck in the registry.

Evidence

crates/archon/src/render/server.rs:229:

let _audio_send = connection.open_uni().await?;

The registry.add(..) call is at lines 219–226 (before this line); registry.remove(&session_id).await is at line 234 and only runs on the straight-line path after both open_uni and read_status_loop return normally. Any error from open_uni bypasses line 234 entirely.

Why this matters

Every subsequent list_renderers call (served by DynRendererRegistry) includes a stale entry for a renderer that never finished negotiating. If open_uni failures are transient (QUIC flow-control, server back-pressure), the registry grows unboundedly and a legitimate renderer reconnecting with the same name appears twice, with no way for the API consumer to distinguish live from stale entries. Under the counter-surveillance threat model an attacker who can induce repeated open_uni failures (network shaping, resource pressure) turns this into an unbounded-memory and registry-poisoning vector, and a phantom entry can mislead the operator about which endpoints are actually live.

Desired correction

Move registry.add to after open_uni succeeds, or wrap the registration in a RAII guard / defer that calls registry.remove on every exit path after add. Alternatively, replace the ? bail with an explicit registry.remove before returning the error.
Done when: a unit test exercises the open_uni-failure path and verifies the registry contains zero entries afterward.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions