XMPP: geen stroomregeling op inbound stanzas tijdens live sessie — vijandige server kan demux/handlers overstromen #1420

Closed
opened 2026-08-09 18:25:35 +00:00 by brenno · 0 comments
Owner

Bevinding

lib/xmpp/xmpp_session.dart_startDispatch (regels 498–509) parsed elke inbound frame tot een Stanza en voegt hem toe aan _inbound (een broadcast StreamController). Tijdens de handshake is er een frame-queue-cap (256) en een frame-grootte-cap (512 KiB), maar in de live sessie (drain-mode) is er geen stroomregeling — elke frame wordt direct doorgegeven aan de demux.

lib/xmpp/companion_demux.dart_onStanza (regels 56–82) roept de handler aan met handler(stanza).catchError(...)fire-and-forget, niet awaited. Elke stanza start een asynchrone handler die kan proberen een verzegeling te openen (CPU-intensief: AEAD-decryptie, handtekeningverificatie). Een vloed stanzas start een vloed gelijktijdige handlers.

Wat er gebeurt

Een vijandige server stuurt een stroom stanzas (binnen de 512 KiB frame-cap per stuk). Elke stanza wordt geparsed, aan _inbound toegevoegd, door de demux gerouteerd naar een handler, en de handler start een async open/verificatie. Omdat handlers niet worden geserialiseerd, lopen er tientallen gelijktijdig — elk met crypto-operaties. Dit veroorzaakt:

  • CPU-exhaustie: tientallen gelijktijdige AEAD-decrypties en Ed25519-verificaties.
  • Geheugen-exhaustie: elke in-flight handler houdt een Stanza en tijdelijke crypto-buffers vast.
  • Stilstand van de UI: de event-loop wordt overspoeld met crypto-werk, waardoor de UI niet meer reageert.

De _FrameReader-queue-cap (256) geldt alleen vóór de drain-modus — zodra de sessie live is, is er geen backpressure.

Trust boundary

Netwerk (vijandige XMPP-server) → Applicatie (stanza-dispatch + crypto).

Impact

Een vijandige server kan de app onresponsief maken door een stroom stanzas te sturen. De aanval is stil — geen crash, maar de UI bevriest en het geheugen groeit.

Oplossingsrichting

  1. Serialiseer handler-aanroepen in de demux: in plaats van fire-and-forget, await elke handler vóór de volgende stanza te verwerken. Dit beperkt de gelijktijdigheid tot 1 en voorkomt CPU-overspoeling. De afruil is dat een trage handler (een zware snapshot-reassemblage) de verwerking van latere stanzas vertraagt — maar dat is acceptabeler dan een onresponsieve app.
  2. Aanvullend: overweeg een inbound rate-limiter op sessie-niveau — als de server meer dan N stanzas/seconde stuurt, dropp de overvloed (of sluit de verbinding fail-closed bij aanhoudende overvloed).
  3. Aanvullend: overweeg een work-queue met begrensde gelijktijdigheid (bijv. max 4 parallelle handlers) in plaats van ofwel onbegrensd (nu) ofwel strikt serieel (optie 1).

Locatie

  • lib/xmpp/xmpp_session.dart regels 498–509 (_startDispatch — drain zonder backpressure)
  • lib/xmpp/companion_demux.dart regels 56–82 (_onStanza — fire-and-forget handler-aanroep)

Severity

MEDIUM — CPU/geheugen-DoS door een vijandige server, met UI-bevriezing als zichtbaar effect.

## Bevinding `lib/xmpp/xmpp_session.dart` — `_startDispatch` (regels 498–509) parsed elke inbound frame tot een `Stanza` en voegt hem toe aan `_inbound` (een broadcast `StreamController`). Tijdens de handshake is er een frame-queue-cap (256) en een frame-grootte-cap (512 KiB), maar in de **live sessie** (drain-mode) is er geen stroomregeling — elke frame wordt direct doorgegeven aan de demux. `lib/xmpp/companion_demux.dart` — `_onStanza` (regels 56–82) roept de handler aan met `handler(stanza).catchError(...)` — **fire-and-forget**, niet awaited. Elke stanza start een asynchrone handler die kan proberen een verzegeling te openen (CPU-intensief: AEAD-decryptie, handtekeningverificatie). Een vloed stanzas start een vloed gelijktijdige handlers. ### Wat er gebeurt Een vijandige server stuurt een stroom stanzas (binnen de 512 KiB frame-cap per stuk). Elke stanza wordt geparsed, aan `_inbound` toegevoegd, door de demux gerouteerd naar een handler, en de handler start een async open/verificatie. Omdat handlers niet worden geserialiseerd, lopen er tientallen gelijktijdig — elk met crypto-operaties. Dit veroorzaakt: - **CPU-exhaustie:** tientallen gelijktijdige AEAD-decrypties en Ed25519-verificaties. - **Geheugen-exhaustie:** elke in-flight handler houdt een `Stanza` en tijdelijke crypto-buffers vast. - **Stilstand van de UI:** de event-loop wordt overspoeld met crypto-werk, waardoor de UI niet meer reageert. De `_FrameReader`-queue-cap (256) geldt alleen vóór de drain-modus — zodra de sessie live is, is er geen backpressure. ### Trust boundary Netwerk (vijandige XMPP-server) → Applicatie (stanza-dispatch + crypto). ### Impact Een vijandige server kan de app onresponsief maken door een stroom stanzas te sturen. De aanval is stil — geen crash, maar de UI bevriest en het geheugen groeit. ### Oplossingsrichting 1. **Serialiseer handler-aanroepen in de demux:** in plaats van fire-and-forget, await elke handler vóór de volgende stanza te verwerken. Dit beperkt de gelijktijdigheid tot 1 en voorkomt CPU-overspoeling. De afruil is dat een trage handler (een zware snapshot-reassemblage) de verwerking van latere stanzas vertraagt — maar dat is acceptabeler dan een onresponsieve app. 2. **Aanvullend:** overweeg een inbound rate-limiter op sessie-niveau — als de server meer dan N stanzas/seconde stuurt, dropp de overvloed (of sluit de verbinding fail-closed bij aanhoudende overvloed). 3. **Aanvullend:** overweeg een work-queue met begrensde gelijktijdigheid (bijv. max 4 parallelle handlers) in plaats van ofwel onbegrensd (nu) ofwel strikt serieel (optie 1). ### Locatie - `lib/xmpp/xmpp_session.dart` regels 498–509 (`_startDispatch` — drain zonder backpressure) - `lib/xmpp/companion_demux.dart` regels 56–82 (`_onStanza` — fire-and-forget handler-aanroep) ### Severity MEDIUM — CPU/geheugen-DoS door een vijandige server, met UI-bevriezing als zichtbaar effect.
brenno 2026-08-09 20:56:29 +00:00
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#1420
No description provided.