Summary
BrokerCoreLimits are global to the broker core, but a single broker process serves every client association. One malicious or buggy local can therefore exhaust the shared budget and permanently deny object and pipe creation to all other sessions.
This is an availability issue only. Per-session ownership is enforced correctly on lookup, so there is no cross-session disclosure or confused-deputy exposure.
Details
The limits are explicitly documented as shared:
https://github.com/microsoft/litebox/blob/ulitebox/litebox_broker_core/src/lib.rs#L42-L45
/// Resource limits for broker-owned authority state.
///
/// These limits are global to the broker core, not per session.
pub struct BrokerCoreLimits {
pub max_references: usize, // DEFAULT: 4096
pub max_total_pipe_capacity: usize, // DEFAULT: 64 MiB
}
BrokerCore is a process singleton (BROKER_CORE_CREATED.compare_exchange) that hands out sessions via create_session(), and both budgets are enforced against process-wide state:
create_object_reference / create_object_reference_pair check references.len() against max_references on the shared references map (litebox_broker_core/src/session.rs:82-101, :104-133).
- Pipe capacity is reserved from the shared
reserved_pipe_capacity: AtomicUsize against max_total_pipe_capacity (litebox_broker_core/src/pipe.rs:193-201).
Ownership enforcement itself is sound — with_authorized_object rejects handles whose session_id does not match the caller (litebox_broker_core/src/session.rs:173-188) — so this is strictly a shared-budget problem.
Impact
A local that creates 4096 object references, or reserves 64 MiB of pipe capacity, causes every subsequent create_* from any session to fail with ResourceExhausted. The attacker does not need to be clever; ordinary buggy behavior in one sandbox produces the same result.
Two properties make it worse:
- The budget is only released when the offending objects are closed or the session is torn down, so a local that simply stops making progress pins the budget indefinitely.
- The host's ring capacity waits (
ControlRingProducer::wait_for_capacity, reached from UnixControlRingHostResponseSink::send_response) have no timeout. They are interruptible by shutdown or peer close, but a local that stays alive and refuses to drain its response ring holds its association — and its share of the global budget — indefinitely with nothing to evict it.
Suggested direction
Add per-session quotas alongside the existing global ceilings, so the global limit remains a backstop while no single session can consume all of it. Roughly:
- Track live reference count and reserved pipe capacity per
SessionId.
- Enforce a per-session cap in
create_object_reference, create_object_reference_pair, and the pipe capacity reservation path.
- Release the per-session accounting on object close and on session teardown.
Bounding or timing out wait_for_capacity is not the right fix on its own: any threshold that evicts a malicious local will eventually evict a legitimately slow one. It is only relevant as a way to reclaim a pinned budget, which per-session quotas address more directly.
Notes
Pre-existing; not introduced by any current PR. Surfaced while auditing the broker trust boundary during review of #1083, which does not touch litebox_broker_core.
Summary
BrokerCoreLimitsare global to the broker core, but a single broker process serves every client association. One malicious or buggy local can therefore exhaust the shared budget and permanently deny object and pipe creation to all other sessions.This is an availability issue only. Per-session ownership is enforced correctly on lookup, so there is no cross-session disclosure or confused-deputy exposure.
Details
The limits are explicitly documented as shared:
https://github.com/microsoft/litebox/blob/ulitebox/litebox_broker_core/src/lib.rs#L42-L45
BrokerCoreis a process singleton (BROKER_CORE_CREATED.compare_exchange) that hands out sessions viacreate_session(), and both budgets are enforced against process-wide state:create_object_reference/create_object_reference_paircheckreferences.len()againstmax_referenceson the sharedreferencesmap (litebox_broker_core/src/session.rs:82-101,:104-133).reserved_pipe_capacity: AtomicUsizeagainstmax_total_pipe_capacity(litebox_broker_core/src/pipe.rs:193-201).Ownership enforcement itself is sound —
with_authorized_objectrejects handles whosesession_iddoes not match the caller (litebox_broker_core/src/session.rs:173-188) — so this is strictly a shared-budget problem.Impact
A local that creates 4096 object references, or reserves 64 MiB of pipe capacity, causes every subsequent
create_*from any session to fail withResourceExhausted. The attacker does not need to be clever; ordinary buggy behavior in one sandbox produces the same result.Two properties make it worse:
ControlRingProducer::wait_for_capacity, reached fromUnixControlRingHostResponseSink::send_response) have no timeout. They are interruptible by shutdown or peer close, but a local that stays alive and refuses to drain its response ring holds its association — and its share of the global budget — indefinitely with nothing to evict it.Suggested direction
Add per-session quotas alongside the existing global ceilings, so the global limit remains a backstop while no single session can consume all of it. Roughly:
SessionId.create_object_reference,create_object_reference_pair, and the pipe capacity reservation path.Bounding or timing out
wait_for_capacityis not the right fix on its own: any threshold that evicts a malicious local will eventually evict a legitimately slow one. It is only relevant as a way to reclaim a pinned budget, which per-session quotas address more directly.Notes
Pre-existing; not introduced by any current PR. Surfaced while auditing the broker trust boundary during review of #1083, which does not touch
litebox_broker_core.