Enforce LoginGraceTime in wolfsshd on Windows and make the grace flag per connection#1028
Enforce LoginGraceTime in wolfsshd on Windows and make the grace flag per connection#1028yosuke-wolfssl wants to merge 1 commit into
Conversation
There was a problem hiding this comment.
Pull request overview
This PR fixes a fail-open behavior in wolfsshd where LoginGraceTime was not enforced on Windows, and corrects the timeout bookkeeping so it is safe under the Windows thread-per-connection model. It also updates logging behavior and adds/reenables tests to prevent regressions across Unix and Windows CI.
Changes:
- Enforce
LoginGraceTimeon Windows using a per-connection threadpool timer and move the timeout flag intoWOLFSSHD_CONNECTION. - Adjust authentication result handling to cancel grace timers/alarms on successful authentication.
- Rework and expand tests (Bash + PowerShell) and extend Windows CI to exercise the Windows enforcement path.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 6 comments.
Show a summary per file
| File | Description |
|---|---|
| apps/wolfsshd/wolfsshd.c | Adds per-connection timeout state and Windows threadpool timer enforcement; logging flush behavior updated. |
| apps/wolfsshd/test/sshd_login_grace_test.sh | Makes grace-time test deterministic by stalling with a raw TCP connection; reorders logic accordingly. |
| apps/wolfsshd/test/sshd_login_grace_test.ps1 | Adds Windows regression test for grace-time enforcement. |
| apps/wolfsshd/test/run_all_sshd_tests.sh | Re-enables the grace-time test in the SSHD test suite and updates skipped count. |
| .github/workflows/windows-check.yml | Adds a workflow step to locate wolfsshd.exe, stage wolfssl.dll, and run the new Windows grace-time test. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
de58d1d to
14e248f
Compare
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1028
Scan targets checked: none
Failed targets: wolfssh-bugs, wolfssh-src
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1028
Scan targets checked: wolfssh-bugs, wolfssh-src
No new issues found in the changed files. ✅
e0befb8 to
15b6718
Compare
There was a problem hiding this comment.
Pull request overview
Copilot reviewed 5 out of 5 changed files in this pull request and generated 3 comments.
Comments suppressed due to low confidence (1)
apps/wolfsshd/wolfsshd.c:2046
conn->timeOutcan be set asynchronously by the Windows threadpool timer, but the accept loop only checksLoginGraceExpired(conn)in thewhilecondition. If the grace timer expires while blocked intcp_select(), the loop body can still callwolfSSH_accept()once more (without re-checking the timeout) and potentially accept a connection after the grace deadline.
while (LoginGraceExpired(conn) == 0 && (ret != WS_SUCCESS
&& ret != WS_SCP_INIT && ret != WS_SFTP_COMPLETE)
&& (error == WS_WANT_READ || error == WS_WANT_WRITE)) {
select_ret = tcp_select(conn->fd, 1);
wolfSSL-Fenrir-bot
left a comment
There was a problem hiding this comment.
Fenrir Automated Review — PR #1028
Scan targets checked: wolfssh-bugs, wolfssh-src
No new issues found in the changed files. ✅
15b6718 to
9cc926d
Compare
Enforce LoginGraceTime in wolfsshd on Windows and make the grace flag per-connection
Summary
Two related fixes to
LoginGraceTimehandling inwolfsshd:Close a fail-open default on Windows. The Windows build never armed a
grace timer.
LoginGraceTimewas accepted from the config but only logged a"not enforced on this platform" warning, so an unauthenticated connection
could stay open indefinitely. Windows now arms a one-shot threadpool timer
that drops the connection at the deadline, matching the POSIX
SIGALRMbehavior.
Fix a latent shared-flag bug. The grace timeout was tracked in a single
file-scope
timeOutvariable (static volatile inton Windows,__thread intelsewhere). POSIX alwaysfork()s per connection so the flagwas effectively per-process there, but Windows daemon connections run as
threads via
CreateThread, so one connection timing out could be observed byanother. The flag now lives in
WOLFSSHD_CONNECTION, making itper-connection on every platform.
Details
timeOut(and, on Windows, aPTP_TIMER loginTimer) toWOLFSSHD_CONNECTION, initialized per connection inStartSSHD.SIGALRMhandler sets a file-scopevolatile sig_atomic_t loginGraceTimedOut(a signal handler may only touch asig_atomic_t). Theflag is cleared before
alarm()is armed to avoid stale state from a reusedprocess.
CreateThreadpoolTimerschedulesGraceTimeoutCb, which marksthe connection timed out at the deadline.
CancelLoginTimerdoesSetThreadpoolTimer(NULL)->WaitForThreadpoolTimerCallbacks(timer, TRUE)->CloseThreadpoolTimer, and is NULL-guarded and idempotent. It is reachedunconditionally when
graceTime > 0, plus early on auth success.GraceTimeoutCbruns on a threadpool threadwhile the accept loop reads the flag on the connection thread. To avoid a
cross-thread data race on
conn->timeOut, the callback publishes it withInterlockedExchange8and the accept loop reads it withInterlockedOr8(the field stays a single
byte; noLONGwidening). The POSIXsig_atomic_tflag is left as-is, which is the correct primitive for a signalhandler.
LoginGraceExpired()abstracts the read of the timeout state for the acceptloop across both platforms (interlocked read of
conn->timeOuton Windows,the
loginGraceTimedOutglobal on POSIX). The logging and grace-period checksgo through this one accessor, so there is a single source of truth on each
platform.
UserAuthResultnow receives the connection viawolfSSH_SetUserAuthResultCtxand cancels the grace timer (
CancelLoginTimeron Windows,alarm(0)onPOSIX) as soon as authentication succeeds.
complete in the same accept iteration, avoiding a misleading "Failed login
within grace period" message on a timer-vs-success race.
while the daemon runs sees output immediately.
Tests
(which never stalled without a TTY in CI) to opening a raw TCP connection and
measuring, behaviorally, when the daemon drops it relative to the grace
deadline.
.shtest installs anEXITtrap right after starting the daemon, sowolfsshdis stopped on every exit path (including the early failure exits)and cannot leak into later tests.
sshd_login_grace_test.ps1) for the Windowspath, wired into
windows-check.yml. It cleans up the daemon in afinallyblock and decides "connection dropped" from the measured elapsed time, so a
server-side reset (which surfaces as an
IOExceptionrather than a gracefulEOF) near the deadline is still counted as enforcement rather than a false
failure.
windows-check.ymlnow genuinely enables the sshd/sftp settings so theWindows build path is exercised.