Skip to content

Terminal output is pushed to the webview with no backpressure, so a fast server can exhaust app memory #158

Open

Description

@Sadykhzadeh

Tested against main (894ea12), tauri 2.12.1. Reported externally as BUG-R2-C4-A1-H1; triaged in #157.

What happens

The SSH reader task (core/src/session.rs:230-260) loops on channel.wait(), batches output with OutputBatcher (at most 64 KiB per batch, 6 ms window) and hands every batch to the sink synchronously. The sink (desktop/src-tauri/src/state.rs:397) is fire-and-forget: sink.send(InvokeResponseBody::Raw(..)) on a tauri::ipc::Channel.

In tauri 2.12.1 a channel payload of 1 KiB or more is put in an in-memory map and waits there until the webview fetches it (ipc/channel.rs:38, :307-318). 2.12.1 already made that map per-webview and clears it when a webview closes, but nothing bounds it while the webview lives.

The reader never waits for the webview, so nothing pushes back on the server. OutputBatcher limits the size of each batch, not how many there are. A server that writes faster than the webview drains (on purpose, or just cat of a large file over a fast link while the UI is busy) grows that queue until the process runs out of memory, taking every session and the unlocked vault with it.

russh 0.63.3 already hands channel data over through a bounded queue and awaits the send. If the reader stopped polling channel.wait(), the stall would travel back to the server through the SSH window and TCP. Nothing makes it stop.

Fix

Use credit-based flow control. Each session meters the output it has delivered against a window of unacknowledged bytes, and the webview acknowledges what it receives. While the window is spent, the reader stops polling the channel; resizes and an already-due flush keep working. Closing a session lifts the limit, so the reader still reaches EOF.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions