Skip to content

Bound SFTP handle length against received payload in GetHandle#1083

Open
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/f_6696
Open

Bound SFTP handle length against received payload in GetHandle#1083
yosuke-wolfssl wants to merge 1 commit into
wolfSSL:masterfrom
yosuke-wolfssl:fix/f_6696

Conversation

@yosuke-wolfssl

Copy link
Copy Markdown
Contributor

Summary

Fixes a heap over-read in the SFTP client when parsing a server's SSH_FXP_HANDLE reply.

wolfSSH_SFTP_GetHandle allocates state->buffer to exactly the server-declared payload size, then reads the handle-string length prefix sz and validates it only against WOLFSSH_MAX_HANDLE and the caller's *handleSz — never against the bytes actually present in the buffer. A malicious or compromised server can declare a 4-byte payload (just the length prefix) while encoding sz = 256. Both existing guards pass (256 > 256 is false; the caller sets *handleSz = WOLFSSH_MAX_HANDLE = 256, so 256 < 256 is false), and:

WMEMCPY(handle,
        (wolfSSH_SFTP_buffer_data(&state->buffer) + UINT32_SZ),
        *handleSz);

copies 256 bytes out of a 4-byte allocation — reading ~252 bytes past the buffer. Those bytes land in the client's handle, which is echoed verbatim to the server on every later READ/WRITE/CLOSE/READDIR, disclosing client heap memory; a read crossing an unmapped page crashes the client instead.

Addressed by f_6696.

Fix

Add a payload bound to the guard in wolfSSH_SFTP_GetHandle — reject when the declared handle length exceeds what the buffer actually holds:

if (wolfSSH_SFTP_buffer_ato32(&state->buffer, &sz) != WS_SUCCESS
       || sz > WOLFSSH_MAX_HANDLE || *handleSz < sz
       || UINT32_SZ + sz
              > wolfSSH_SFTP_buffer_size(&state->buffer)) {

sz is capped at WOLFSSH_MAX_HANDLE (256) by the earlier check, so UINT32_SZ + sz cannot overflow. This matches the bound GetStringRef already enforces on length-prefixed strings elsewhere.

Tests

  • Added a WOLFSSH_TEST_INTERNAL hook wolfSSH_TestSftpGetHandle to drive the static function.
  • Added test_SftpGetHandle_sizeBound, which injects a crafted HANDLE reply into a channel and drives wolfSSH_SFTP_GetHandle:
    • Reject case — payload=4, declared length=256 → must return non-success with ssh->error == WS_BUFFER_E (no over-read).
    • Accept case — payload=8 carrying a 4-byte handle (exact fit) → must return WS_SUCCESS with a clean ssh->error.

Verification

  • Unit suite passes: SftpGetHandle_sizeBound: SUCCESS, exit 0.
  • Negative control: reverting only the guard makes ASan report heap-buffer-overflow READ of size 256 at the WMEMCPY in wolfSSH_SFTP_GetHandle, confirming the test exercises the exact over-read.

Files changed

  • src/wolfsftp.c — payload bound in the guard; wolfSSH_TestSftpGetHandle hook.
  • wolfssh/wolfsftp.h — prototype for the new test hook.
  • tests/unit.c — injection helper, bound test, and registration.

@yosuke-wolfssl yosuke-wolfssl self-assigned this Jul 6, 2026
Copilot AI review requested due to automatic review settings July 6, 2026 06:06

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR hardens the SFTP client handle-parsing path by bounding the server-declared handle length against the actual received payload size in wolfSSH_SFTP_GetHandle, preventing a heap over-read and potential client heap disclosure/crash when processing SSH_FXP_HANDLE replies.

Changes:

  • Add a payload-size bound check before copying the handle bytes in wolfSSH_SFTP_GetHandle.
  • Add a WOLFSSH_TEST_INTERNAL test hook to drive wolfSSH_SFTP_GetHandle deterministically from unit tests.
  • Add a unit test that validates both the reject (truncated payload, large declared handle) and accept (exact-fit handle) cases.

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/wolfsftp.c Adds the missing payload-bound guard in wolfSSH_SFTP_GetHandle and exposes an internal test hook.
wolfssh/wolfsftp.h Declares the new wolfSSH_TestSftpGetHandle prototype under WOLFSSH_TEST_INTERNAL.
tests/unit.c Adds an injection helper and a unit test that reproduces the prior over-read and asserts correct bounded behavior.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #1083

Scan targets checked: wolfssh-bugs, wolfssh-src

Findings: 1
1 finding(s) posted as inline comments (see file-level comments below)

This review was generated automatically by Fenrir. Findings are non-blocking.

Comment thread tests/unit.c
Comment thread tests/unit.c

@wolfSSL-Fenrir-bot wolfSSL-Fenrir-bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fenrir Automated Review — PR #1083

Scan targets checked: wolfssh-bugs, wolfssh-src

No new issues found in the changed files. ✅

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

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants