wolfsftp: buffer the SFTP DATA length across partial reads - #1181
wolfsftp: buffer the SFTP DATA length across partial reads#1181yosuke-wolfssl wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes a high-severity short-read handling defect in the client SFTP read path by ensuring the 4-byte DATA string-length prefix is buffered across calls, preventing decoding from partially filled/uninitialized memory. It also adds a focused unit regression test that simulates a DATA reply split inside the length prefix and verifies correct WS_WANT_READ behavior and retry completion.
Changes:
- Update
wolfSSH_SFTP_SendReadPacket()to read the DATA length prefix viawolfSSH_SFTP_buffer_*APIs so partial reads are accumulated safely. - Remove the stack-based
szFlatlength buffer and decode the length from the persistent state buffer. - Add a unit test that injects a split DATA reply and asserts state retention and correct payload on retry.
Reviewed changes
Copilot reviewed 2 out of 2 changed files in this pull request and generated 1 comment.
| File | Description |
|---|---|
| src/wolfsftp.c | Buffer the 4-byte DATA length prefix across partial reads using persistent send-read state buffering. |
| tests/unit.c | Add a regression test that splits the DATA length prefix across reads and validates retry behavior/payload integrity. |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
- STATE_SEND_READ_FTP_DATA reads the four byte string length through wolfSSH_SFTP_buffer_read() into state->buffer and decodes it with ato32() from that buffer. - The szFlat stack array is removed from wolfSSH_SFTP_SendReadPacket(). - tests/unit.c gains test_SftpSendReadPacketSplit(), with the SftpBuildData() and SftpClientDriveReadSplit() helpers, driving a DATA reply split inside the length prefix through wolfSSH_SFTP_SendReadPacket(). Issue: F-8828
62dbb03 to
65e417d
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1181
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.
Problem
wolfSSH_SFTP_SendReadPacket()decoded the 4-byte string length prefixing an SFTPDATAreply with a single unchecked read into a stack buffer:wolfSSH_stream_read()returnsmin(bufSz, available), so a short positive return is normal whenever the channel input buffer holds fewer than 4 bytes — routine when a peer'sDATAreply straddles SSH packets. Onlyret < 0was checked, so 1-3 delivered bytes reachedato32(), which read the rest ofszFlatas uninitialized stack (CWE-457). The decoded length was then garbage: a bogus allocation size, a spurious "Server sent more data then expected", or — as the regression test shows — a length of0that drops intoSTATE_SEND_READ_REMAINDERwith a zero-byte request and fails withWS_BAD_ARGUMENT. BecauseszFlatwas a stack local, the prefix bytes already consumed were unrecoverable, so the retry could not resynchronize. Severity: High. Closes f-8828.Fix (
src/wolfsftp.c)STATE_SEND_READ_FTP_DATAnow reads the length throughwolfSSH_SFTP_buffer_read()intostate->bufferinstead of a rawwolfSSH_stream_read()intoszFlat:wolfSSH_SFTP_buffer_read()accumulates short positive reads within a call, andstate->bufferlives inssh->sendReadState, so a partial prefix survives across calls.wolfSSH_SFTP_buffer_create(..., UINT32_SZ)is a no-op on re-entry (data != NULL && sz == UINT32_SZ), preservingidxso the retry resumes mid-prefix.szFlatis removed;ato32()decodes from the state buffer.This is the same change commit
6f0cbe3fmade for the sibling VERSION-header defect (f-7505), so both halves of the client read path now use one pattern.STATE_SEND_READ_FTP_DATAwas the last live rawstream_readin the file without short-read handling —STATE_SEND_READ_GET_HEADERalready went throughSFTP_GetHeader(), andSTATE_SEND_READ_REMAINDERalready accumulated intostate->recvSz.Test harness (
tests/unit.c)test_SftpSendReadPacketSplit()— network-free, built on the existingSftpClientNewSession()+wolfSSH_TestChannelPutData()harness. It stages aDATAreply split inside the length prefix (1-of-4 and 2-of-4 bytes) and asserts the first call returnsWS_FATAL_ERROR/WS_WANT_READwith the send-read state retained, and the retry returns the full payload intact. No new test hooks.SftpBuildData()delegates to the existingSftpBuildVersion()rather than re-packing the header.Verification
make check: 11 passed, 0 failed, 1 skipped (external).-Werroracross 6 configs (enable-all, zephyr-defines, sftp-only, scp-only, default, smallstack).