From 18b9249ee776351dc67c978c286c5566dbf1ed82 Mon Sep 17 00:00:00 2001 From: John Safranek Date: Tue, 25 Aug 2026 11:31:00 -0700 Subject: [PATCH] Make the disconnect tests prove what they claim The two disconnect tests ran on a session that had never finished user auth, so IsMessageAllowed() blocked the sends on its own and the "nothing on the wire" assertions held even with the gates removed. Both now sit past user auth. With only the shutdown gate reverted the test measures 72 bytes out and both teardown flags set, where before it measured nothing. - wolfSSH_stream_peek() reports WS_DISCONNECT when the channel is gone, the way wolfSSH_stream_read() already did; a missing channel used to read as a bad argument on a session that had simply ended - the drain test covers the no-channel case for both calls Issue: F-8837 --- src/ssh.c | 11 ++++++++++- tests/regress.c | 20 ++++++++++++++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/ssh.c b/src/ssh.c index 63b4fc6b..58378643 100644 --- a/src/ssh.c +++ b/src/ssh.c @@ -1245,9 +1245,18 @@ int wolfSSH_stream_peek(WOLFSSH* ssh, byte* buf, word32 bufSz) WLOG(WS_LOG_DEBUG, "Entering wolfSSH_stream_peek()"); - if (ssh == NULL || ssh->channelList == NULL) + if (ssh == NULL) return WS_BAD_ARGUMENT; + if (ssh->channelList == NULL) { + /* No channel left to drain, so the disconnect is all there is. */ + if (ssh->disconnected) { + ssh->error = WS_DISCONNECT; + return WS_FATAL_ERROR; + } + return WS_BAD_ARGUMENT; + } + if (ssh->isKeying) { ssh->error = WS_REKEYING; return WS_REKEYING; diff --git a/tests/regress.c b/tests/regress.c index fb3b7fad..65150ec8 100644 --- a/tests/regress.c +++ b/tests/regress.c @@ -3023,6 +3023,20 @@ static void TestDisconnectDrainsBufferedData(void) AssertIntEQ(ret, WS_FATAL_ERROR); AssertIntEQ(wolfSSH_get_error(ssh), WS_DISCONNECT); + /* With the channel gone there is no buffer left to drain, so both + * report the disconnect rather than a bad argument. */ + AssertIntEQ(ChannelRemove(ssh, ssh->channelList->channel, + WS_CHANNEL_ID_SELF), WS_SUCCESS); + AssertNull(ssh->channelList); + + ret = wolfSSH_stream_peek(ssh, NULL, 1); + AssertIntEQ(ret, WS_FATAL_ERROR); + AssertIntEQ(wolfSSH_get_error(ssh), WS_DISCONNECT); + + ret = wolfSSH_stream_read(ssh, data, sizeof(data)); + AssertIntEQ(ret, WS_FATAL_ERROR); + AssertIntEQ(wolfSSH_get_error(ssh), WS_DISCONNECT); + wolfSSH_free(ssh); wolfSSH_CTX_free(ctx); } @@ -3052,6 +3066,9 @@ static void TestDisconnectBlocksEverySend(void) AssertNotNull(ssh); AddSessionChannel(ssh); channelId = ssh->channelList->channel; + /* Past userauth, or the message filter blocks the sends on its own and + * the wire check below proves nothing. */ + ssh->connectState = CONNECT_SERVER_USERAUTH_ACCEPT_DONE; MemIoInit(&io, NULL, 0, out, sizeof(out)); wolfSSH_SetIOReadCtx(ssh, &io); @@ -3379,6 +3396,9 @@ static void TestShutdownQuietAfterDisconnect(void) AssertNotNull(ssh); AddSessionChannel(ssh); channel = ssh->channelList; + /* Past userauth, or the message filter blocks the teardown on its own + * and the wire check below proves nothing. */ + ssh->connectState = CONNECT_SERVER_USERAUTH_ACCEPT_DONE; inSz = BuildDisconnectPacket(WOLFSSH_DISCONNECT_BY_APPLICATION, in, sizeof(in));