mirror of https://github.com/wolfSSL/wolfssh.git
wolfterm: bound escBuf saves and clear esc state on OSC resume
Harden the partial-sequence reassembly in wolfSSH_DoControlSeq and fix an escape-state leak in the wolfSSH_ConvertConsole OSC resume path (USE_WINDOWS_API console handling). - Tighten both escBuf partial-save branches to reject bufSz - *idx >= WOLFSSL_MAX_ESCBUF before the WMEMCPY and log via WLOG. escBuf is WOLFSSL_MAX_ESCBUF bytes, so a save of exactly that length fills it with no room for later state; rejecting the boundary keeps the two branches consistent and matches the resume check. - Add the capacity guard to the initial-parse CSI save branch, which previously copied into escBuf with no bound. In the default build getArgs caps the advance below WOLFSSL_MAX_ESCBUF so the copy was already safe; the guard prevents a custom WOLFSSH_MAX_CONSOLE_ARGS > WOLFSSL_MAX_ESCBUF build from overflowing escBuf. - Clear escState to WC_ESC_NONE when a resumed OSC sequence completes, not just escBufSz. Without this escState stayed WS_ESC_OSC and the next call re-entered OSC parsing on plain bytes instead of printing them. Extend test_wolfSSH_ConvertConsole with a CSI sequence split across three calls (ESC[ | args | command char), a trailing plain byte that must be printed once state is cleared, and a single buffer whose CSI args run to the end and complete on the next byte.pull/1113/head
parent
9702235f91
commit
0b819b0b48
|
|
@ -475,7 +475,8 @@ static int wolfSSH_DoControlSeq(WOLFSSH* ssh, WOLFSSH_HANDLE handle, byte* buf,
|
|||
numArgs = getArgs(buf, bufSz, &i, args);
|
||||
if (i >= bufSz) {
|
||||
/* save left overs for next call */
|
||||
if (bufSz - *idx > WOLFSSL_MAX_ESCBUF) {
|
||||
if (bufSz - *idx >= WOLFSSL_MAX_ESCBUF) {
|
||||
WLOG(WS_LOG_ERROR, "escBuf state exceeds capacity");
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
WMEMCPY(ssh->escBuf, buf + *idx, bufSz - *idx);
|
||||
|
|
@ -491,6 +492,10 @@ static int wolfSSH_DoControlSeq(WOLFSSH* ssh, WOLFSSH_HANDLE handle, byte* buf,
|
|||
|
||||
if (i >= bufSz) {
|
||||
/* save left overs for next call */
|
||||
if (bufSz - *idx >= WOLFSSL_MAX_ESCBUF) {
|
||||
WLOG(WS_LOG_ERROR, "escBuf state exceeds capacity");
|
||||
return WS_FATAL_ERROR;
|
||||
}
|
||||
WMEMCPY(ssh->escBuf, buf + *idx, bufSz - *idx);
|
||||
ssh->escBufSz = bufSz - *idx;
|
||||
return WS_WANT_READ;
|
||||
|
|
@ -687,6 +692,7 @@ int wolfSSH_ConvertConsole(WOLFSSH* ssh, WOLFSSH_HANDLE handle, byte* buf,
|
|||
if (ret == WS_WANT_READ) {
|
||||
return ret;
|
||||
}
|
||||
ssh->escState = WC_ESC_NONE;
|
||||
ssh->escBufSz = 0;
|
||||
break;
|
||||
|
||||
|
|
|
|||
35
tests/api.c
35
tests/api.c
|
|
@ -3370,6 +3370,18 @@ static byte osc_trunc_str[] = { /* "ESC ] 0 ; title" with no BEL terminator */
|
|||
static byte osc_full[] = { /* well formed "ESC ] 0 ; hi BEL" */
|
||||
0x1B, 0x5D, 0x30, 0x3B, 0x68, 0x69, 0x07
|
||||
};
|
||||
static byte csi_open[] = { /* "ESC [" with no args yet, escBufSz left at 0 */
|
||||
0x1B, 0x5B
|
||||
};
|
||||
static byte csi_args[] = { /* pure args "12" with no command char */
|
||||
0x31, 0x32
|
||||
};
|
||||
static byte csi_cmd[] = { /* command char 'm' completes the sequence */
|
||||
0x6D
|
||||
};
|
||||
static byte csi_inline[] = { /* "ESC [ 1 2" args run to end of one buffer */
|
||||
0x1B, 0x5B, 0x31, 0x32
|
||||
};
|
||||
#endif /* USE_WINDOWS_API */
|
||||
|
||||
|
||||
|
|
@ -3417,6 +3429,29 @@ static void test_wolfSSH_ConvertConsole(void)
|
|||
AssertIntEQ(wolfSSH_ConvertConsole(ssh, stdoutHandle, osc_full,
|
||||
sizeof(osc_full)), WS_SUCCESS);
|
||||
|
||||
/* a CSI sequence split so the first packet ends right after "ESC [" and
|
||||
* the second carries only argument bytes must not read past the buffer
|
||||
* while waiting for the command char */
|
||||
AssertIntEQ(wolfSSH_ConvertConsole(ssh, stdoutHandle, csi_open,
|
||||
sizeof(csi_open)), WS_WANT_READ);
|
||||
AssertIntEQ(wolfSSH_ConvertConsole(ssh, stdoutHandle, csi_args,
|
||||
sizeof(csi_args)), WS_WANT_READ);
|
||||
/* the trailing command char completes the reassembled sequence */
|
||||
AssertIntEQ(wolfSSH_ConvertConsole(ssh, stdoutHandle, csi_cmd,
|
||||
sizeof(csi_cmd)), WS_SUCCESS);
|
||||
/* after the split sequence completes the esc state must be cleared, so a
|
||||
* following plain argument byte is printed rather than swallowed back into
|
||||
* CSI parsing (which would return WS_WANT_READ) */
|
||||
AssertIntEQ(wolfSSH_ConvertConsole(ssh, stdoutHandle, csi_args, 1),
|
||||
WS_SUCCESS);
|
||||
|
||||
/* a single buffer whose CSI arguments run to the end with no command char
|
||||
* must save the partial args and wait, then complete on the next byte */
|
||||
AssertIntEQ(wolfSSH_ConvertConsole(ssh, stdoutHandle, csi_inline,
|
||||
sizeof(csi_inline)), WS_WANT_READ);
|
||||
AssertIntEQ(wolfSSH_ConvertConsole(ssh, stdoutHandle, csi_cmd,
|
||||
sizeof(csi_cmd)), WS_SUCCESS);
|
||||
|
||||
wolfSSH_free(ssh);
|
||||
wolfSSH_CTX_free(ctx);
|
||||
#endif /* USE_WINDOWS_API */
|
||||
|
|
|
|||
Loading…
Reference in New Issue