Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 11 additions & 1 deletion src/internal.c
Original file line number Diff line number Diff line change
Expand Up @@ -12225,7 +12225,17 @@ static int DoPacket(WOLFSSH* ssh, byte* bufferConsumed)
return WS_MSGID_NOT_ALLOWED_E;
}

switch (msg) {
/* The session is over, RFC 4253 section 11.1, so skip the whole dispatch:
* the handlers that answer must not, and what the rest would record is of
* no use to a caller that can no longer send. Inbound data from here on is
* dropped rather than buffered. The frame advance at the end steps over
* the packet, so the stream stays in step. A DISCONNECT still dispatches,
* since DoDisconnect() sends nothing and latches the error. */
if (ssh->disconnected && msg != MSGID_DISCONNECT) {
WLOG(WS_LOG_DEBUG, "Ignoring message ID %u after a disconnect",
(word32)msg);
}
else switch (msg) {

case MSGID_DISCONNECT:
WLOG(WS_LOG_DEBUG, "Decoding MSGID_DISCONNECT");
Expand Down
28 changes: 27 additions & 1 deletion src/ssh.c
Original file line number Diff line number Diff line change
Expand Up @@ -550,6 +550,10 @@ int wolfSSH_CTX_UseTpmHostKey(WOLFSSH_CTX* ctx,
#endif /* WOLFSSH_TPM */


/* Defined below, ahead of both drivers; either can be the only one built. */
static int SendAfterDisconnect(WOLFSSH* ssh);


#ifndef NO_WOLFSSH_SERVER

const char acceptError[] = "accept error: %s, %d";
Expand All @@ -563,6 +567,11 @@ int wolfSSH_accept(WOLFSSH* ssh)
if (ssh == NULL)
return WS_BAD_ARGUMENT;

/* No handshake on a session that is over. The pending-send block below
* would flush a queued disconnect as the next handshake message. */
if (SendAfterDisconnect(ssh))
return WS_FATAL_ERROR;

/* clear want read/writes for retry */
if (ssh->error == WS_WANT_READ || ssh->error == WS_WANT_WRITE || ssh->error == WS_AUTH_PENDING)
ssh->error = 0;
Expand Down Expand Up @@ -826,6 +835,11 @@ int wolfSSH_connect(WOLFSSH* ssh)
if (ssh == NULL)
return WS_BAD_ARGUMENT;

/* See wolfSSH_accept(). No error-state test here, so the peer's
* disconnect reaches the state machine like a local one. */
if (SendAfterDisconnect(ssh))
return WS_FATAL_ERROR;

/* check if data pending to be sent */
if (ssh->outputBuffer.length > 0 &&
ssh->connectState < CONNECT_SERVER_CHANNEL_REQUEST_DONE) {
Expand Down Expand Up @@ -3590,6 +3604,16 @@ int wolfSSH_worker(WOLFSSH* ssh, word32* channelId)
if (ssh == NULL)
ret = WS_BAD_ARGUMENT;

/* Nothing left to drive: no reply may go out and inbound messages are
* skipped, so every pass from here on would answer WS_SUCCESS off a
* dispatch that did nothing and a caller turning the crank would never
* see the session end. What arrived before the disconnect is still the
* caller's, through the read calls. RFC 4253 section 11.1. */
if (ret == WS_SUCCESS && SendAfterDisconnect(ssh)) {
WLOG(WS_LOG_DEBUG, "Leaving wolfSSH_worker(), session disconnected");
return WS_FATAL_ERROR;
}

#ifdef WOLFSSH_TEST_BLOCK
/* In forced non-blocking test mode, keep legacy ordering (send before
* receive) to match the harness expectations and avoid synthetic spins. */
Expand Down Expand Up @@ -3639,7 +3663,9 @@ int wolfSSH_worker(WOLFSSH* ssh, word32* channelId)
}

/* WS_EXTDATA is raised once, on arrival; masking it would strand the
* buffered stderr and its window credit. */
* buffered stderr and its window credit. A disconnect cannot be seen
* here: the gate at the top returns before this, and the DISCONNECT
* that sets the flag mid-pass leaves ret fatal. */
if (ssh->isKeying && ret != WS_EXTDATA) {
ssh->error = WS_REKEYING;
return WS_REKEYING;
Expand Down
Loading
Loading