Files
ESP32_Serial_Swiss_Army_Knife/tests/wolfssh_parser_contract/pr918.patch
T
Commander1024 51f835c22f Harden SSH parsing and add notice tooling
- Enforce exact service and channel names with bounded failure parsing
- Add hash-pinned offline notice assembly and regression coverage
- Record advisory dispositions, provenance, integration evidence, and
  remaining gates
2026-09-16 15:06:38 +02:00

308 lines
8.8 KiB
Diff

From fd82a4bcf55935f0801b14bca6be9c71e32ae914 Mon Sep 17 00:00:00 2001
From: Yosuke Shimizu <yosuke@wolfssl.com>
Date: Wed, 15 Apr 2026 11:33:07 +0900
Subject: [PATCH] Fix DoGlobalRequestFwd and Add the regress tests
---
src/internal.c | 27 +++++-
tests/regress.c | 214 ++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 237 insertions(+), 4 deletions(-)
diff --git a/src/internal.c b/src/internal.c
index 11902b7b4..5db18ddb4 100644
--- a/src/internal.c
+++ b/src/internal.c
@@ -8496,16 +8496,35 @@ static int DoGlobalRequestFwd(WOLFSSH* ssh,
isCancel ? " cancel" : "", bindAddr, bindPort);
}
- if (ret == WS_SUCCESS && wantReply) {
- ret = SendGlobalRequestFwdSuccess(ssh, 1, bindPort);
- }
-
if (ret == WS_SUCCESS) {
if (ssh->ctx->fwdCb) {
ret = ssh->ctx->fwdCb(isCancel ? WOLFSSH_FWD_REMOTE_CLEANUP :
WOLFSSH_FWD_REMOTE_SETUP,
ssh->fwdCbCtx, bindAddr, bindPort);
}
+ else {
+ WLOG(WS_LOG_WARN, "No forwarding callback set, rejecting request. "
+ "Set one with wolfSSH_CTX_SetFwdCb().");
+ ret = WS_UNIMPLEMENTED_E;
+ }
+ }
+
+ if (wantReply) {
+ if (ret == WS_SUCCESS) {
+ if (isCancel) {
+ ret = SendRequestSuccess(ssh, 1);
+ }
+ else {
+ ret = SendGlobalRequestFwdSuccess(ssh, 1, bindPort);
+ }
+ }
+ else {
+ ret = SendRequestSuccess(ssh, 0);
+ }
+ }
+ else if (ret == WS_UNIMPLEMENTED_E) {
+ /* No reply expected; silently reject without terminating connection. */
+ ret = WS_SUCCESS;
}
if (bindAddr != NULL)
diff --git a/tests/regress.c b/tests/regress.c
index 5d069d7fc..bf37202d1 100644
--- a/tests/regress.c
+++ b/tests/regress.c
@@ -231,6 +231,21 @@ static word32 BuildDirectTcpipExtra(const char* host, word32 hostPort,
return idx;
}
+
+static word32 BuildGlobalRequestFwdPacket(const char* bindAddr, word32 bindPort,
+ int isCancel, byte wantReply, byte* out, word32 outSz)
+{
+ byte payload[256];
+ word32 idx = 0;
+ const char* reqName = isCancel ? "cancel-tcpip-forward" : "tcpip-forward";
+
+ idx = AppendString(payload, sizeof(payload), idx, reqName);
+ idx = AppendByte (payload, sizeof(payload), idx, wantReply);
+ idx = AppendString(payload, sizeof(payload), idx, bindAddr);
+ idx = AppendUint32(payload, sizeof(payload), idx, bindPort);
+
+ return WrapPacket(MSGID_GLOBAL_REQUEST, payload, idx, out, outSz);
+}
#endif
/* Simple in-memory transport harness */
@@ -957,6 +972,94 @@ static void AssertChannelOpenFailResponse(const ChannelOpenHarness* harness,
AssertTrue(harness->ssh->channelList == NULL);
}
+#ifdef WOLFSSH_FWD
+static word32 ParsePayloadLen(const byte* packet, word32 packetSz)
+{
+ word32 packetLen;
+ byte padLen;
+
+ AssertNotNull(packet);
+ AssertTrue(packetSz >= 6);
+
+ WMEMCPY(&packetLen, packet, sizeof(packetLen));
+ packetLen = ntohl(packetLen);
+ padLen = packet[4];
+
+ AssertTrue(packetLen >= (word32)padLen + 1);
+ AssertTrue(packetSz >= packetLen + 4);
+
+ return packetLen - padLen - 1;
+}
+
+static const byte* ParseGlobalRequestName(const byte* packet, word32 packetSz,
+ word32* nameSz)
+{
+ word32 packetLen;
+ word32 payloadLen;
+ word32 strSz;
+ const byte* payload;
+
+ AssertNotNull(packet);
+ AssertNotNull(nameSz);
+ AssertTrue(packetSz >= 10);
+
+ WMEMCPY(&packetLen, packet, sizeof(packetLen));
+ packetLen = ntohl(packetLen);
+ AssertTrue(packetSz >= packetLen + 4);
+
+ payloadLen = ParsePayloadLen(packet, packetSz);
+ payload = packet + 5;
+
+ AssertTrue(payloadLen >= 1 + sizeof(word32));
+ AssertIntEQ(payload[0], MSGID_GLOBAL_REQUEST);
+
+ WMEMCPY(&strSz, payload + 1, sizeof(strSz));
+ strSz = ntohl(strSz);
+ AssertTrue(payloadLen >= 1 + sizeof(word32) + strSz);
+
+ *nameSz = strSz;
+ return payload + 1 + sizeof(word32);
+}
+
+static void AssertGlobalRequestReply(const ChannelOpenHarness* harness,
+ byte expectedMsgId)
+{
+ byte msgId;
+ word32 payloadLen;
+
+ AssertTrue(harness->io.outSz > 0);
+ msgId = ParseMsgId(harness->io.out, harness->io.outSz);
+ AssertIntEQ(msgId, expectedMsgId);
+
+ payloadLen = ParsePayloadLen(harness->io.out, harness->io.outSz);
+ if (expectedMsgId == MSGID_REQUEST_FAILURE) {
+ AssertIntEQ(payloadLen, 1);
+ }
+ else if (expectedMsgId == MSGID_REQUEST_SUCCESS) {
+ const byte* reqName;
+ word32 reqNameSz;
+
+ reqName = ParseGlobalRequestName(harness->io.in, harness->io.inSz,
+ &reqNameSz);
+
+ if (reqNameSz == sizeof("tcpip-forward") - 1 &&
+ WMEMCMP(reqName, "tcpip-forward",
+ sizeof("tcpip-forward") - 1) == 0) {
+ AssertIntEQ(payloadLen, 5);
+ }
+ else if (reqNameSz == sizeof("cancel-tcpip-forward") - 1 &&
+ WMEMCMP(reqName, "cancel-tcpip-forward",
+ sizeof("cancel-tcpip-forward") - 1) == 0) {
+ AssertIntEQ(payloadLen, 1);
+ }
+ else {
+ Fail(("unexpected global request name"),
+ ("%.*s", (int)reqNameSz, reqName));
+ }
+ }
+}
+#endif
+
static int RejectChannelOpenCb(WOLFSSH_CHANNEL* channel, void* ctx)
{
(void)channel;
@@ -978,6 +1081,17 @@ static int RejectDirectTcpipSetup(WS_FwdCbAction action, void* ctx,
return WS_SUCCESS;
}
+
+static int AcceptFwdCb(WS_FwdCbAction action, void* ctx,
+ const char* host, word32 port)
+{
+ (void)action;
+ (void)ctx;
+ (void)host;
+ (void)port;
+
+ return WS_SUCCESS;
+}
#endif
@@ -1242,6 +1356,101 @@ static void TestDirectTcpipNoFwdCbSendsOpenFail(void)
FreeChannelOpenHarness(&harness);
}
+
+static void TestGlobalRequestFwdNoCbSendsFailure(void)
+{
+ ChannelOpenHarness harness;
+ byte in[256];
+ word32 inSz;
+ int ret;
+
+ inSz = BuildGlobalRequestFwdPacket("0.0.0.0", 2222, 0, 1, in, sizeof(in));
+ InitChannelOpenHarness(&harness, in, inSz);
+ /* no fwdCb registered */
+
+ ret = DoReceive(harness.ssh);
+
+ AssertIntEQ(ret, WS_SUCCESS);
+ AssertGlobalRequestReply(&harness, MSGID_REQUEST_FAILURE);
+
+ FreeChannelOpenHarness(&harness);
+}
+
+static void TestGlobalRequestFwdNoCbNoReplyKeepsConnection(void)
+{
+ ChannelOpenHarness harness;
+ byte in[256];
+ word32 inSz;
+ int ret;
+
+ /* wantReply=0: no reply sent, connection must stay alive */
+ inSz = BuildGlobalRequestFwdPacket("0.0.0.0", 2222, 0, 0, in, sizeof(in));
+ InitChannelOpenHarness(&harness, in, inSz);
+ /* no fwdCb registered */
+
+ ret = DoReceive(harness.ssh);
+
+ AssertIntEQ(ret, WS_SUCCESS);
+ AssertIntEQ(harness.io.outSz, 0); /* no reply sent */
+
+ FreeChannelOpenHarness(&harness);
+}
+
+static void TestGlobalRequestFwdWithCbSendsSuccess(void)
+{
+ ChannelOpenHarness harness;
+ byte in[256];
+ word32 inSz;
+ int ret;
+
+ inSz = BuildGlobalRequestFwdPacket("0.0.0.0", 2222, 0, 1, in, sizeof(in));
+ InitChannelOpenHarness(&harness, in, inSz);
+ AssertIntEQ(wolfSSH_CTX_SetFwdCb(harness.ctx, AcceptFwdCb, NULL), WS_SUCCESS);
+
+ ret = DoReceive(harness.ssh);
+
+ AssertIntEQ(ret, WS_SUCCESS);
+ AssertGlobalRequestReply(&harness, MSGID_REQUEST_SUCCESS);
+
+ FreeChannelOpenHarness(&harness);
+}
+
+static void TestGlobalRequestFwdCancelNoCbSendsFailure(void)
+{
+ ChannelOpenHarness harness;
+ byte in[256];
+ word32 inSz;
+ int ret;
+
+ inSz = BuildGlobalRequestFwdPacket("0.0.0.0", 2222, 1, 1, in, sizeof(in));
+ InitChannelOpenHarness(&harness, in, inSz);
+
+ ret = DoReceive(harness.ssh);
+
+ AssertIntEQ(ret, WS_SUCCESS);
+ AssertGlobalRequestReply(&harness, MSGID_REQUEST_FAILURE);
+
+ FreeChannelOpenHarness(&harness);
+}
+
+static void TestGlobalRequestFwdCancelWithCbSendsSuccess(void)
+{
+ ChannelOpenHarness harness;
+ byte in[256];
+ word32 inSz;
+ int ret;
+
+ inSz = BuildGlobalRequestFwdPacket("0.0.0.0", 2222, 1, 1, in, sizeof(in));
+ InitChannelOpenHarness(&harness, in, inSz);
+ AssertIntEQ(wolfSSH_CTX_SetFwdCb(harness.ctx, AcceptFwdCb, NULL), WS_SUCCESS);
+
+ ret = DoReceive(harness.ssh);
+
+ AssertIntEQ(ret, WS_SUCCESS);
+ AssertGlobalRequestReply(&harness, MSGID_REQUEST_SUCCESS);
+
+ FreeChannelOpenHarness(&harness);
+}
#endif
#ifdef WOLFSSH_AGENT
@@ -1707,6 +1916,11 @@ int main(int argc, char** argv)
#ifdef WOLFSSH_FWD
TestDirectTcpipRejectSendsOpenFail();
TestDirectTcpipNoFwdCbSendsOpenFail();
+ TestGlobalRequestFwdNoCbSendsFailure();
+ TestGlobalRequestFwdNoCbNoReplyKeepsConnection();
+ TestGlobalRequestFwdWithCbSendsSuccess();
+ TestGlobalRequestFwdCancelNoCbSendsFailure();
+ TestGlobalRequestFwdCancelWithCbSendsSuccess();
#endif
#ifdef WOLFSSH_AGENT
TestAgentChannelNullAgentSendsOpenFail();