Skip to content

sftp: answer every refused server request - #1372

Open
ejohnstown wants to merge 4 commits into
wolfSSL:masterfrom
ejohnstown:sftp-server-replies
Open

ejohnstown wants to merge 4 commits into
wolfSSL:masterfrom
ejohnstown:sftp-server-replies

Conversation

@ejohnstown

Copy link
Copy Markdown
Contributor

The SFTP server sends an SSH_FXP_STATUS for every request it refuses,
so a client is never left waiting on a request id.

  • FAILURE for a path that does not resolve or an unknown handle
  • BAD_MESSAGE for a request whose fields run past the packet, and for
    attributes that do not parse or carry flags outside the v3 set;
    WRITE and RENAME parse failures change from FAILURE to BAD_MESSAGE
  • READ over WOLFSSH_MAX_SFTP_RW is clamped to a short read, as
    OpenSSH's sftp-server does
  • RMDIR replies before logging a bad path; Nucleus REMOVE logging
    checks the right result
  • regress: TestSftpFailedRequestsAnswered covers each handler

Issue: F-17050, F-17051, F-17052, F-17076, F-17077

The SFTP server handlers queue an SSH_FXP_STATUS for a request they
refuse, so the client is never left waiting on its request id.
SFTP_ParseAttributes_buffer rejects attribute flag bits outside the
v3 set, which draft-ietf-secsh-filexfer-02 section 5 calls a protocol
error.

- OPEN, OPENDIR, MKDIR, REALPATH and REMOVE answer FAILURE for a path
  that does not resolve, such as one of WOLFSSH_MAX_FILENAME bytes
- FSTAT and READDIR answer FAILURE for a wrong-size or unknown handle
- READ clamps a length over WOLFSSH_MAX_SFTP_RW to a short read, as
  OpenSSH's sftp-server does and filexfer-02 section 3 allows
- OPEN, MKDIR, SETSTAT and FSETSTAT answer BAD_MESSAGE for attributes
  that do not parse
- Add TestSftpFailedRequestsAnswered and a REALPATH test hook

Issue: F-17050, F-17051, F-17076, F-17077
Copilot AI balanced review requested due to automatic review settings November 3, 2026 16:47

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.

🟡 Changes recommended

The Windows OPEN branch still bypasses attribute validation, allowing malformed requests to reach WS_CreateFileA() and potentially create or truncate files instead of returning BAD_MESSAGE.

1 open issue
What changed in this PR

This PR improves SFTP server error handling so refused requests receive status replies rather than leaving clients waiting.

Changes:

  • Adds replies for malformed requests, invalid paths, unknown handles, and unsupported attribute flags.
  • Clamps oversized READ requests to short reads and corrects failure logging.
  • Adds regression coverage and a REALPATH test hook.
File Description
wolfssh/​wolfsftp.h Declares the REALPATH test hook.
tests/​regress.c Tests refusal replies, malformed requests, and oversized reads.
src/​wolfsftp.c Updates status handling, attribute validation, read limits, and logging.

Review effort: Balanced

Comment thread src/wolfsftp.c Resolved
RecvRemove keeps the return of WREMOVE, and the Nucleus debug block
compares that against the NUF_* codes instead of ret, which still held
WS_SUCCESS there.

Issue: F-17052
A server handler that cannot parse its request, because a field runs
past the end of the packet, queues an SSH_FX_BAD_MESSAGE status for the
request id through SFTP_SendBadMessage instead of returning silently.

- Covers REALPATH, OPEN, OPENDIR, MKDIR, RMDIR, REMOVE, READ, WRITE,
  READDIR, STAT, LSTAT, FSTAT, SETSTAT, FSETSTAT and CLOSE
- The WRITE handle and RENAME path failures now say BAD_MESSAGE, not
  FAILURE
- CLOSE reads its handle length with GetSize
- TestSftpFailedRequestsAnswered sends truncated packets to each handler
RecvRMDIR answers a path GetAndCleanPath cannot resolve with FAILURE
straight away, as RecvMKDIR does, so the failure log never prints the
unfilled dir buffer.

- TestSftpFailedRequestsAnswered sends RMDIR an over-long path
@ejohnstown

Copy link
Copy Markdown
Contributor Author

@claude review

@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 #1372

Scan targets checked: wolfssh-src, wolfssh-bugs
Coverage: 3 of 3 in-scope changed file(s) opened by the reviewer

Fenrir result: Approved ✅

No new issues found in the changed files.

Advisory only — this automated result does not count as a GitHub approval.

Review tier: Lite

@claude claude 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.

Nothing blocking. The comments below are optional suggestions. There is no need to push a fix for them before merging.

Beyond the inline finding, I checked whether removing the length caps in CLOSE, READDIR and REMOVE could allow out-of-bounds reads. They can't. CLOSE and READDIR still reject any handle whose size isn't WOLFSSH_HANDLE_ID_SZ. REMOVE passes the name to GetAndCleanPath, which rejects anything of WOLFSSH_MAX_FILENAME or longer before copying it.

Extended reasoning...

The PR changes error handling across most SFTP server request handlers in src/wolfsftp.c, adds a test hook to the public header and adds regression tests. One reason not to approve is the confirmed inline finding about the shared attribute parser, which client-side parsing also uses. The other is an open Copilot thread at src/wolfsftp.c:2830 that only the PR author resolved.

Comment thread src/wolfsftp.c
Comment on lines +7261 to +7267
/* flag bits outside the v3 set are a protocol error (filexfer-02 5) */
if ((atr->flags & ~(word32)(WOLFSSH_FILEATRB_SIZE | WOLFSSH_FILEATRB_UIDGID
| WOLFSSH_FILEATRB_PERM | WOLFSSH_FILEATRB_TIME
| WOLFSSH_FILEATRB_EXT)) != 0) {
WLOG(WS_LOG_SFTP, "Unsupported attribute flags 0x%08X", atr->flags);
return WS_BUFFER_E;
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🟡 (optional) wolfSSH SFTP clients now reject a whole server reply when an attribute block sets any flag bit outside the v3 set. Affected replies are READDIR/REALPATH name lists and STAT/LSTAT results. The new flags check at src/wolfsftp.c:7261 sits in the shared SFTP_ParseAttributes_buffer, so it also runs on client-side parsing at :7662 and :8198. Fix: apply the v3-flag check only on the server request paths (MKDIR, OPEN, SETSTAT, FSETSTAT), for example through a strict flag on the parser. Leave client reply parsing as lenient as the base, which ignored unknown bits.

Why this was flagged

The condition is a server that sets a flag bit other than SIZE/UIDGID/PERM/TIME/EXT in a v3 ATTRS or NAME entry. I could not enumerate such servers from this checkout. The PR describes the check as a server request-validation change. But SFTP_ParseAttributes_buffer (src/wolfsftp.c:7249) is also called by the client's NAME-list parser at src/wolfsftp.c:7662 and by the client's STAT/LSTAT reply handler at src/wolfsftp.c:8198. On the base branch, unknown bits were ignored and the defined fields parsed normally. After this change the parser returns WS_BUFFER_E, so the client's whole directory listing (wolfSSH_SFTPNAME_list_free plus an error) or its stat call fails. Before, it would have succeeded. No caller-side guard limits the new check to server requests.

Verification: The new check at src/wolfsftp.c:7261-7267 is in the shared parser SFTP_ParseAttributes_buffer. Line 7662 is the NAME-list parser used for READDIR and REALPATH replies. At 7673-7676 the whole list is then freed and NULL is returned, so one bad entry drops the entire directory listing. On the base, unknown bits were ignored and the defined fields still parsed.

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.

3 participants