Run threaded api-test SFTP/SCP tests on Windows#1058
Conversation
40d5909 to
58ec180
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1058
Scan targets checked: wolfssh-bugs, wolfssh-src
Findings: 1
Low (1)
Confinement test shutdown check not hardened for Windows peer-gone path
File: tests/api.c:2506
Function: test_wolfSSH_SFTP_Confinement
Category: Incorrect error handling
This PR enables test_wolfSSH_SFTP_Confinement on Windows but its shutdown check only converts WS_SOCKET_ERROR_E, not the generic WS_ERROR with wolfSSH_get_error()==WS_SOCKET_ERROR_E that the recv path returns on Windows. Every sibling Windows-enabled test (1710, 1990, 2130, 3673) was hardened for this; this one fails AssertIntEQ(ret, WS_SUCCESS) on a benign peer reset.
Recommendation: Accept ret == WS_ERROR && wolfSSH_get_error(ssh) == WS_SOCKET_ERROR_E here, matching the sibling tests.
Referenced code: tests/api.c:2506-2509 (4 lines)
This review was generated automatically by Fenrir. Findings are non-blocking.
58ec180 to
3ef3cb6
Compare
aidangarske
left a comment
There was a problem hiding this comment.
🐺 Skoll Code Review
Overall recommendation: REQUEST_CHANGES
Findings: 2 total — 2 posted, 0 skipped
Posted findings
- [High] New WSCPRINTF macro breaks Windows WSTRING_USER builds —
src/wolfscp.c:1908 - [Medium] Boundary checks reject one valid maximum-length path —
src/wolfscp.c:2594; examples/sftpclient/sftpclient.c:1467
Review generated by Skoll.
| int sz; | ||
|
|
||
| #ifdef USE_WINDOWS_API | ||
| sz = WSCPRINTF("scp -%c %s", dir, name) + 1; |
There was a problem hiding this comment.
🟠 [High] New WSCPRINTF macro breaks Windows WSTRING_USER builds
🚫 BLOCK
The PR changes the Windows length probe from WSNPRINTF(NULL, 0, ...) to WSCPRINTF(...), but WSCPRINTF is only defined inside #ifndef WSTRING_USER in wolfssh/port.h. A supported Windows build that defines WSTRING_USER and enables SCP will now compile MakeScpCmd with USE_WINDOWS_API and hit an undefined WSCPRINTF macro. This is introduced by the PR because MakeScpCmd previously only depended on the existing WSNPRINTF wrapper.
Recommendation: Provide a WSCPRINTF fallback outside the #ifndef WSTRING_USER block, or avoid adding a new required string-port macro by using a local Windows size-probe helper that is always available for USE_WINDOWS_API builds. Fix the macro availability before merge so custom string-port Windows builds do not regress.
aidangarske
left a comment
There was a problem hiding this comment.
🐺 Skoll Code Review
Overall recommendation: REQUEST_CHANGES
Findings: 2 total — 2 posted, 0 skipped
Posted findings
- [High] New WSCPRINTF macro breaks Windows WSTRING_USER builds —
src/wolfscp.c:1908 - [Medium] Boundary checks reject one valid maximum-length path —
src/wolfscp.c:2594; examples/sftpclient/sftpclient.c:1467
Review generated by Skoll.
| int sz; | ||
|
|
||
| #ifdef USE_WINDOWS_API | ||
| sz = WSCPRINTF("scp -%c %s", dir, name) + 1; |
There was a problem hiding this comment.
🟠 [High] New WSCPRINTF macro breaks Windows WSTRING_USER builds
🚫 BLOCK
The PR changes the Windows length probe from WSNPRINTF(NULL, 0, ...) to WSCPRINTF(...), but WSCPRINTF is only defined inside #ifndef WSTRING_USER in wolfssh/port.h. A supported Windows build that defines WSTRING_USER and enables SCP will now compile MakeScpCmd with USE_WINDOWS_API and hit an undefined WSCPRINTF macro. This is introduced by the PR because MakeScpCmd previously only depended on the existing WSNPRINTF wrapper.
Recommendation: Provide a WSCPRINTF fallback outside the #ifndef WSTRING_USER block, or avoid adding a new required string-port macro by using a local Windows size-probe helper that is always available for USE_WINDOWS_API builds. Fix the macro availability before merge so custom string-port Windows builds do not regress.
| if (ctx == NULL || path == NULL) | ||
| return WS_BAD_ARGUMENT; | ||
|
|
||
| if (WSTRLEN(path) >= DEFAULT_SCP_FILE_NAME_SZ - 1) |
There was a problem hiding this comment.
🟡 [Medium] Boundary checks reject one valid maximum-length path
💡 SUGGEST
The new WSTRNCPY guards compare against buffer_size - 1 and then pass buffer_size - 1 as the Windows secure-CRT destination size. That avoids the strncpy_s fastfail, but it also rejects strings that exactly fill the destination with one byte left for the terminator. For example, ctx->dirName is DEFAULT_SCP_FILE_NAME_SZ bytes, so a DEFAULT_SCP_FILE_NAME_SZ - 1 byte path should fit, but the new guard returns WS_BUFFER_E. The same off-by-one behavior exists for absolute autopilot paths in fullpath.
Recommendation: Use the real destination size in the WSTRNCPY call and guard against >= sizeof(destination), then add a boundary test for an input whose length is exactly sizeof(destination) - 1. Adjust the copy sizes so the Windows hardening does not reduce the accepted maximum path length.
Superseded by corrected review (findings now attached as inline comments).
Summary
Enables the threaded echoserver+client SFTP/SCP integration tests in
api-teston Windows CI (MSVC + AddressSanitizer). These tests were previously stubbed out on Windows because the readiness handshake was POSIX-only, so a whole class of SFTP/SCP coverage never ran there. Running them surfaced several Windows-only bugs in wolfSSH, which this PR also fixes.Net change is small (7 files, +105/−32) — most of the work was diagnosis.
What changed
Test harness / CI
windows-check.yml— fix theuser_settings.h#if 0→#if 1flip so SSHD/SFTP/SCP/CERTS/X509 are actually compiled and tested (they were silently stubbing to{ ; }).wolfssh/test.h— implement the Win32 readiness handshake fortcp_ready(aCRITICAL_SECTION+ manual-reset event, withInit/Free/Wait/SignalTcpReadyWin32 branches).WaitForSingleObjectis bounded by a 30s timeout so a stuck server can't hang CI. This lets the threaded tests run instead of being skipped.tests/api.c— drop the!USE_WINDOWS_APIguards that stubbed the threaded SFTP/SCP tests; pairInitTcpReady/FreeTcpReady; use an ephemeral port (-p 0) on Windows like POSIX, so concurrent CI runs don't collide on a fixed port.wolfSSH Windows fixes uncovered by the tests
MakeScpCmd(src/wolfscp.c) — the length-probe usedWSNPRINTF(NULL, 0, ...), but on Windows that maps to_snprintf_s, which rejects the NULL/0 form and aborts via__fastfail. Use_scprintfthrough a new Windows-onlyWSCPRINTFwrapper (wolfssh/port.h) for the length measurement.WSTRNCPYcall-site hardening — on WindowsWSTRNCPY(s1,s2,n)maps tostrncpy_s((s1),(n),(s2),(n)), which__fastfails whenstrlen(src) >= n. Audited everysrc/and example call site; fixed the unguarded ones:ScpCheckForRename— pass the real buffer size (sizeof(buf)) rather than a copy count.ScpPushDir— add an upstream length guard returningWS_BUFFER_E.echoserver.c/sftpclient.c— guard the user/server-supplied string copies (skip or return on over-long input).tests/api.c) — on Windows the post-transfer close races the client's gracefulwolfSSH_shutdown; Winsock raises an RST that the client sees on the recv path. There, wolfSSH follows its convention of returning the genericWS_ERRORwhile stashing the specific code inssh->error. The test only absorbed the directWS_SOCKET_ERROR_Ereturn (the send-path manifestation), so the recv-path reset slipped through ~30–40% of runs. The fix absorbs the benign reset viawolfSSH_get_error(ssh) == WS_SOCKET_ERROR_E, gated onargsCount == WS_ERRORso a genuine error with a differentssh->errorstill fails — no masking.Verification
api-test+unit-testpass 15/15 (was ~30–40% flaky at the SFTP-rekey shutdown).api-test+testsuiteclean under-fsanitize=address,undefined.Notes
WSTRNCPYmacro mapping — fixes are at the call sites only.CreateEvent,EnterCriticalSection,WaitForSingleObject) are used directly, consistent with existingUSE_WINDOWS_APIcode in the repo.Supersedes #1030 (which this branch already contains in full; #1058 also un-stubs the threaded tests that #1030 had excluded).