ssh: correct what a late app-channels enable does

DoChannelRequest() reads ssh->appChannels when the request arrives, so
turning the mode on after accept() established the session still refuses
an uncallbacked shell, exec or subsystem request from then on. Only
accept()'s stopping point is pinned, by the guard around stopState.

- say the flag reaches the requests that follow, and that what it cannot
  do is move where accept() returns
- drive a shell request over the wire in both modes from the late-enable
  test, pinning the behaviour the header now describes
pull/1235/head
John Safranek 2026-09-03 22:20:29 -07:00 committed by Paul Adelsbach
parent 2c832010d2
commit 4ac4484afd
2 changed files with 27 additions and 3 deletions

View File

@ -1646,11 +1646,21 @@ static void TestAppChannelsCtxInherits(void)
}
/* Turning the mode on after accept() established the session must not leave
* the accept loop hunting for a state it has already stepped past. */
* the accept loop hunting for a state it has already stepped past. The flag
* still reaches DoChannelRequest() from there, which is what ssh.h promises,
* so pin both halves: accept() stays put, the requests that follow flip. */
static void TestAppChannelsLateEnableReturns(void)
{
KexReplyHarness harness;
KexReplyRunResult result;
/* SSH_MSG_CHANNEL_REQUEST body: channel 0, "shell", wantReply. */
static byte payShell[] = {
0x00,0x00,0x00,0x00, /* channelId = 0 */
0x00,0x00,0x00,0x05, /* typeSz = 5 */
0x73,0x68,0x65,0x6C,0x6C, /* "shell" */
0x01 /* wantReply = 1 */
};
word32 idx;
InitKexReplyHarness(&harness, "rsa-sha2-256", REGRESS_SERVER_KEY_PATH,
0, NULL);
@ -1661,11 +1671,24 @@ static void TestAppChannelsLateEnableReturns(void)
AssertIntEQ(harness.server->acceptState,
ACCEPT_CLIENT_SESSION_ESTABLISHED);
/* Default mode, no callback registered: the request is granted. */
idx = 0;
AssertIntEQ(wolfSSH_TestDoChannelRequest(harness.server, payShell,
(word32)sizeof(payShell), &idx), WS_SUCCESS);
AssertIntEQ(wolfSSH_worker(harness.client, NULL), WS_SUCCESS);
AssertIntEQ(wolfSSH_SetAppChannels(harness.server, 1), WS_SUCCESS);
AssertIntEQ(wolfSSH_accept(harness.server), WS_SUCCESS);
AssertIntEQ(harness.server->acceptState,
ACCEPT_CLIENT_SESSION_ESTABLISHED);
/* Same request, same session, mode now on: refused instead. */
idx = 0;
AssertIntEQ(wolfSSH_TestDoChannelRequest(harness.server, payShell,
(word32)sizeof(payShell), &idx), WS_SUCCESS);
AssertTrue(wolfSSH_worker(harness.client, NULL) < WS_SUCCESS);
AssertIntEQ(wolfSSH_get_error(harness.client), WS_CHANOPEN_FAILED);
FreeKexReplyHarness(&harness);
}

View File

@ -475,8 +475,9 @@ WOLFSSH_API void* wolfSSH_GetChannelReqCtx(WOLFSSH* ssh);
* accept() already returned, nothing is left to service it.
*
* Set it on the context before wolfSSH_new(), or on a session before the
* first wolfSSH_accept() call. Turning it on once accept() has established
* the session has no effect on that session.
* first wolfSSH_accept() call. Turning it on later still applies to the
* channel requests that follow, but it cannot move where accept() returns
* on a session that has already gone past the user-auth stop.
*
* The mode drives the session channels itself, so it does not combine with
* the built-in wolfSSH_SFTP_accept() and WS_SCP_INIT entry points; an