Skip to content

fix: negotiate SFTP read limits - #273

Merged
inureyes merged 3 commits into
mainfrom
fix/issue-271-sftp-read-limits
Aug 24, 2026
Merged

fix: negotiate SFTP read limits#273
inureyes merged 3 commits into
mainfrom
fix/issue-271-sftp-read-limits

Conversation

@inureyes

@inureyes inureyes commented Aug 24, 2026

Copy link
Copy Markdown
Member

Summary

  • Fix bssh-to-bssh SFTP downloads above 255 KiB by advertising the server's enforced limits through OpenSSH's limits@openssh.com extension and by making pipelined reads recover from legal short DATA replies before EOF.
  • Harden client chunk sizing against oversized peer-advertised read/write limits and reject empty DATA before a known EOF so malicious or buggy peers cannot cause oversized requests, protocol-length truncation, or silently truncated downloads.

What changed

  • src/server/sftp.rs advertises limits@openssh.com = 1 and answers the extended request with packet, read, write, and open-handle limits derived from the existing server configuration and enforcement constants; unknown extensions remain unsupported.
  • crates/bssh-russh-sftp/src/client/fs/file.rs preserves partial read data, reissues only the missing range, keeps offset-ordered reassembly, clamps negotiated read/write chunks to packet payload ceilings, and rejects zero-length data before the size reported by fstat.
  • crates/bssh-russh-sftp/src/extensions.rs serializes LimitsExtension with the existing extension payload machinery.
  • tests/sftp_limits_download_test.rs covers extension advertisement and wire values, 300 KiB and multi-megabyte in-process round trips, deliberate short reads, premature empty data, oversized advertised limits, and read/write packet-bound clamping.
  • ARCHITECTURE.md documents SFTP limits negotiation, short-read recovery, and untrusted peer-limit clamping.

Changes during review

  • Clamp peer-advertised transfer limits instead of trusting them directly, preventing allocation and protocol-length abuse.
  • Treat empty DATA before a known EOF as an integrity error rather than successful truncation, with dedicated regression coverage.

Test plan

  • cargo fmt --check
  • cargo clippy -- -D warnings
  • cargo test --lib (1407 passed, 9 ignored)
  • All test targets passed with four pre-existing localhost SSH cases explicitly excluded because the local known_hosts entry rejects the machine's current localhost key.
  • cargo test --test sftp_limits_download_test
  • cargo test -p bssh-russh-sftp --lib client::fs::file
  • cargo build --release
  • Release bssh to release bssh-server 3 MB upload/download round trip with byte comparison and matching SHA-256; no read-cap warning.
  • Release bssh to stock OpenSSH SFTP 3 MB upload/download round trip with byte comparison and matching SHA-256.

Closes #271

Advertise bssh-server's SFTP limits through limits@openssh.com so bssh clients size pipelined downloads below the server's enforced read cap instead of triggering a short-read failure above 255 KiB.

The pipelined client read path now accepts a legal short DATA reply before EOF, writes the partial chunk in order, and reissues the missing byte range so downloads remain correct even when a server chooses a smaller per-read cap.

Regression coverage adds in-process bssh-to-bssh SFTP transfers for 300 KiB and multi-megabyte files plus a synthetic server that deliberately returns short reads before EOF.

Refs #271
@inureyes inureyes added type:bug Something isn't working priority:high High priority issue status:review Under review labels Aug 24, 2026
@inureyes

Copy link
Copy Markdown
Member Author

Implementation Review Summary

Intent

Fix bssh-to-bssh SFTP downloads above 255 KiB by negotiating limits@openssh.com and by retrying legal short reads in the pipelined client download path.

Findings Addressed

  • No review findings requiring code changes were found.

Remaining Items

  • None.

Verification

  • All stated requirements implemented
  • No placeholder/mock code remaining
  • Integrated into project code flow
  • Project conventions followed
  • Existing modules reused where applicable
  • No unintended structural changes
  • Tests pass

Reviewer validation run:

  • cargo fmt --check
  • cargo test --test sftp_limits_download_test

Clamp advertised SFTP read and write limits to the negotiated packet payload ceiling before sizing client transfer chunks, so a peer cannot inflate allocations or trigger protocol-length truncation with oversized limits@openssh.com values.

Treat an empty DATA packet before a known file size as an unexpected short read instead of completing successfully with truncated output, while still using empty DATA as EOF when no known remaining bytes exist.

Validated with cargo fmt --check, cargo clippy --test sftp_limits_download_test -- -D warnings, cargo test --test sftp_limits_download_test, cargo test -p bssh-russh-sftp --lib client::fs::file, and cargo check --lib --tests.

Refs #271
@inureyes inureyes added status:done Completed and removed status:review Under review labels Aug 24, 2026
@inureyes
inureyes merged commit 5407e14 into main Aug 24, 2026
3 checks passed
@inureyes
inureyes deleted the fix/issue-271-sftp-read-limits branch August 24, 2026 06:43
@inureyes inureyes self-assigned this Aug 24, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

priority:high High priority issue status:done Completed type:bug Something isn't working

Projects

None yet

Development

Successfully merging this pull request may close these issues.

fix(sftp): bssh-server never advertises limits@openssh.com, so bssh-to-bssh downloads over 255 KiB fail

1 participant