[core,gateway] try to parse remaining RPC PDU

if not all bytes have been parsed, try parsing again
This commit is contained in:
Armin Novak 2023-10-24 16:51:31 +02:00 committed by akallabeth
parent 230563b337
commit 135c4cc78c
2 changed files with 42 additions and 32 deletions

View File

@ -180,22 +180,18 @@ static int rpc_client_transition_to_state(rdpRpc* rpc, RPC_CLIENT_STATE state)
static int rpc_client_recv_pdu_int(rdpRpc* rpc, RPC_PDU* pdu)
{
int status = -1;
rdpTsg* tsg;
RtsPduSignature found = { 0 };
WINPR_ASSERT(rpc);
WINPR_ASSERT(pdu);
Stream_SealLength(pdu->s);
Stream_SetPosition(pdu->s, 0);
tsg = transport_get_tsg(rpc->transport);
if (rts_match_pdu_signature(&RTS_PDU_PING_SIGNATURE, pdu->s, NULL))
return 1;
rdpTsg* tsg = transport_get_tsg(rpc->transport);
if (rpc->VirtualConnection->State < VIRTUAL_CONNECTION_STATE_OPENED)
{
RtsPduSignature found = { 0 };
if (rts_match_pdu_signature_ex(&RTS_PDU_PING_SIGNATURE, pdu->s, NULL, &found))
return 1;
switch (rpc->VirtualConnection->State)
{
case VIRTUAL_CONNECTION_STATE_INITIAL:
@ -205,7 +201,7 @@ static int rpc_client_recv_pdu_int(rdpRpc* rpc, RPC_PDU* pdu)
break;
case VIRTUAL_CONNECTION_STATE_WAIT_A3W:
if (!rts_match_pdu_signature_ex(&RTS_PDU_CONN_A3_SIGNATURE, pdu->s, NULL, &found))
if (memcmp(&found, &RTS_PDU_CONN_A3_SIGNATURE, sizeof(found)) != 0)
{
wLog* log = WLog_Get(TAG);
WLog_Print(log, WLOG_ERROR, "unexpected RTS PDU: Expected CONN/A3");
@ -225,7 +221,7 @@ static int rpc_client_recv_pdu_int(rdpRpc* rpc, RPC_PDU* pdu)
break;
case VIRTUAL_CONNECTION_STATE_WAIT_C2:
if (!rts_match_pdu_signature_ex(&RTS_PDU_CONN_C2_SIGNATURE, pdu->s, NULL, &found))
if (memcmp(&found, &RTS_PDU_CONN_C2_SIGNATURE, sizeof(found)) != 0)
{
wLog* log = WLog_Get(TAG);
WLog_Print(log, WLOG_ERROR, "unexpected RTS PDU: Expected CONN/C2");
@ -328,13 +324,24 @@ static int rpc_client_recv_pdu_int(rdpRpc* rpc, RPC_PDU* pdu)
static int rpc_client_recv_pdu(rdpRpc* rpc, RPC_PDU* pdu)
{
WINPR_ASSERT(rpc);
WINPR_ASSERT(pdu);
Stream_SealLength(pdu->s);
Stream_SetPosition(pdu->s, 0);
const size_t before = Stream_GetRemainingLength(pdu->s);
WLog_VRB(TAG, "RPC PDU parsing %" PRIuz " bytes", before);
const int rc = rpc_client_recv_pdu_int(rpc, pdu);
const size_t size = Stream_GetRemainingLength(pdu->s);
if (size > 0)
if (rc < 0)
return rc;
const size_t after = Stream_GetRemainingLength(pdu->s);
if (after > 0)
{
WLog_WARN(TAG, "unused bytes in PDU: %" PRIuz, size);
WLog_ERR(TAG, "incompletely parsed RPC PDU, %" PRIuz " byte remain", before);
return -1;
}
return rc;
}
@ -483,10 +490,11 @@ static int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment)
pdu->Type = header.common.ptype;
pdu->CallId = header.common.call_id;
if (!Stream_EnsureCapacity(pdu->s, Stream_Length(fragment)))
const size_t len = Stream_Length(fragment);
if (!Stream_EnsureCapacity(pdu->s, len))
goto fail;
Stream_Write(pdu->s, Stream_Buffer(fragment), Stream_Length(fragment));
Stream_Write(pdu->s, Stream_Buffer(fragment), len);
if (rpc_client_recv_pdu(rpc, pdu) < 0)
goto fail;
@ -508,10 +516,11 @@ static int rpc_client_recv_fragment(rdpRpc* rpc, wStream* fragment)
pdu->Type = header.common.ptype;
pdu->CallId = header.common.call_id;
if (!Stream_EnsureCapacity(pdu->s, Stream_Length(fragment)))
const size_t len = Stream_Length(fragment);
if (!Stream_EnsureCapacity(pdu->s, len))
goto fail;
Stream_Write(pdu->s, Stream_Buffer(fragment), Stream_Length(fragment));
Stream_Write(pdu->s, Stream_Buffer(fragment), len);
if (rpc_client_recv_pdu(rpc, pdu) < 0)
goto fail;

View File

@ -1197,18 +1197,18 @@ static BOOL rts_write_pdu_header(wStream* s, const rpcconn_rts_hdr_t* header)
}
static BOOL rts_receive_window_size_command_read(rdpRpc* rpc, wStream* buffer,
UINT32* ReceiveWindowSize)
UINT64* ReceiveWindowSize)
{
UINT32 val;
WINPR_ASSERT(rpc);
WINPR_ASSERT(buffer);
if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 4))
if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 8))
return FALSE;
Stream_Read_UINT32(buffer, val);
Stream_Read_UINT64(buffer, val);
if (ReceiveWindowSize)
*ReceiveWindowSize = val; /* ReceiveWindowSize (4 bytes) */
*ReceiveWindowSize = val; /* ReceiveWindowSize (8 bytes) */
return TRUE;
}
@ -1269,18 +1269,18 @@ static BOOL rts_flow_control_ack_command_write(wStream* s, UINT32 BytesReceived,
}
static BOOL rts_connection_timeout_command_read(rdpRpc* rpc, wStream* buffer,
UINT32* ConnectionTimeout)
UINT64* ConnectionTimeout)
{
UINT32 val;
WINPR_ASSERT(rpc);
WINPR_ASSERT(buffer);
if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 4))
if (!Stream_CheckAndLogRequiredLength(TAG, buffer, 8))
return FALSE;
Stream_Read_UINT32(buffer, val);
Stream_Read_UINT64(buffer, val);
if (ConnectionTimeout)
*ConnectionTimeout = val; /* ConnectionTimeout (4 bytes) */
*ConnectionTimeout = val; /* ConnectionTimeout (8 bytes) */
return TRUE;
}
@ -1333,9 +1333,10 @@ static BOOL rts_version_command_read(rdpRpc* rpc, wStream* buffer)
WINPR_ASSERT(rpc);
WINPR_ASSERT(buffer);
if (!Stream_SafeSeek(buffer, 4))
if (!Stream_SafeSeek(buffer, 8))
return FALSE;
/* command (4 bytes) */
/* Version (4 bytes) */
return TRUE;
}
@ -1534,9 +1535,9 @@ fail:
BOOL rts_recv_CONN_A3_pdu(rdpRpc* rpc, wStream* buffer)
{
BOOL rc;
UINT32 ConnectionTimeout;
UINT64 ConnectionTimeout;
if (!Stream_SafeSeek(buffer, 24))
if (!Stream_SafeSeek(buffer, 20))
return FALSE;
rc = rts_connection_timeout_command_read(rpc, buffer, &ConnectionTimeout);
@ -1616,13 +1617,13 @@ fail:
BOOL rts_recv_CONN_C2_pdu(rdpRpc* rpc, wStream* buffer)
{
BOOL rc = FALSE;
UINT32 ReceiveWindowSize = 0;
UINT32 ConnectionTimeout = 0;
UINT64 ReceiveWindowSize = 0;
UINT64 ConnectionTimeout = 0;
WINPR_ASSERT(rpc);
WINPR_ASSERT(buffer);
if (!Stream_SafeSeek(buffer, 24))
if (!Stream_SafeSeek(buffer, 20))
return FALSE;
rc = rts_version_command_read(rpc, buffer);