From 69e9571d9edc58193d49afd4ce9f9fd0c5757075 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Wed, 27 Feb 2019 17:15:43 +0100 Subject: [PATCH] Fixed EGFX capability parsing, respect length fields. Disable RDPGFX_CAPVERSION_106 as we currently do not support scaled outputs. --- channels/rdpgfx/client/rdpgfx_main.c | 23 ++++++++++++++++------- channels/rdpgfx/server/rdpgfx_main.c | 29 ++++++++++++++++------------- include/freerdp/channels/rdpgfx.h | 2 +- 3 files changed, 33 insertions(+), 21 deletions(-) diff --git a/channels/rdpgfx/client/rdpgfx_main.c b/channels/rdpgfx/client/rdpgfx_main.c index 8abe21c..1a8645d 100644 --- a/channels/rdpgfx/client/rdpgfx_main.c +++ b/channels/rdpgfx/client/rdpgfx_main.c @@ -55,6 +55,7 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) { UINT error; + UINT32 x; wStream* s; UINT16 index; RDPGFX_PLUGIN* gfx; @@ -118,12 +119,10 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) caps10Flags |= RDPGFX_CAPS_FLAG_AVC_DISABLED; #endif capsSet->flags = caps10Flags; - /* - capsSet = &capsSets[pdu.capsSetCount++]; - capsSet->version = RDPGFX_CAPVERSION_101; - capsSet->length = 0x10; - capsSet->flags = 0; - */ + capsSet = &capsSets[pdu.capsSetCount++]; + capsSet->version = RDPGFX_CAPVERSION_101; + capsSet->length = 0x10; + capsSet->flags = 0; capsSet = &capsSets[pdu.capsSetCount++]; capsSet->version = RDPGFX_CAPVERSION_102; capsSet->length = 0x4; @@ -145,12 +144,21 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) capsSet->length = 0x4; capsSet->flags = caps10Flags; capsSet = &capsSets[pdu.capsSetCount++]; + /* TODO: Until RDPGFX_MAP_SURFACE_TO_SCALED_OUTPUT_PDU and + * RDPGFX_MAP_SURFACE_TO_SCALED_WINDOW_PDU are not implemented do not + * announce the following version */ +#if 0 capsSet->version = RDPGFX_CAPVERSION_106; capsSet->length = 0x4; capsSet->flags = caps10Flags; +#endif } - header.pduLength = RDPGFX_HEADER_SIZE + 2 + (pdu.capsSetCount * RDPGFX_CAPSET_SIZE); + header.pduLength = RDPGFX_HEADER_SIZE + 2; + + for (x = 0; x < pdu.capsSetCount; x++) + header.pduLength += RDPGFX_CAPSET_BASE_SIZE + capsSets[x].length; + WLog_Print(gfx->log, WLOG_DEBUG, "SendCapsAdvertisePdu %"PRIu16"", pdu.capsSetCount); s = Stream_New(NULL, header.pduLength); @@ -172,6 +180,7 @@ static UINT rdpgfx_send_caps_advertise_pdu(RDPGFX_CHANNEL_CALLBACK* callback) Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */ Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ + Stream_Zero(s, capsSet->length - 4); } Stream_SealLength(s); diff --git a/channels/rdpgfx/server/rdpgfx_main.c b/channels/rdpgfx/server/rdpgfx_main.c index 6397fd4..7542522 100644 --- a/channels/rdpgfx/server/rdpgfx_main.c +++ b/channels/rdpgfx/server/rdpgfx_main.c @@ -204,7 +204,7 @@ static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, { RDPGFX_CAPSET* capsSet = capsConfirm->capsSet; wStream* s = rdpgfx_server_single_packet_new( - RDPGFX_CMDID_CAPSCONFIRM, RDPGFX_CAPSET_SIZE); + RDPGFX_CMDID_CAPSCONFIRM, RDPGFX_CAPSET_BASE_SIZE + capsSet->length); if (!s) { @@ -213,8 +213,16 @@ static UINT rdpgfx_send_caps_confirm_pdu(RdpgfxServerContext* context, } Stream_Write_UINT32(s, capsSet->version); /* version (4 bytes) */ - Stream_Write_UINT32(s, 4); /* capsDataLength (4 bytes) */ - Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ + Stream_Write_UINT32(s, capsSet->length); /* capsDataLength (4 bytes) */ + + if (capsSet->length >= 4) + { + Stream_Write_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ + Stream_Zero(s, capsSet->length - 4); + } + else + Stream_Zero(s, capsSet->length); + return rdpgfx_server_single_packet_send(context, s); } @@ -1196,13 +1204,13 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, Stream_Read_UINT16(s, pdu.capsSetCount); /* capsSetCount (2 bytes) */ - if (Stream_GetRemainingLength(s) < (pdu.capsSetCount * RDPGFX_CAPSET_SIZE)) + if (Stream_GetRemainingLength(s) < (pdu.capsSetCount * (RDPGFX_CAPSET_BASE_SIZE + 4))) { WLog_ERR(TAG, "not enough data!"); return ERROR_INVALID_DATA; } - capsSets = calloc(pdu.capsSetCount, RDPGFX_CAPSET_SIZE); + capsSets = calloc(pdu.capsSetCount, (RDPGFX_CAPSET_BASE_SIZE + 4)); if (!capsSets) return ERROR_OUTOFMEMORY; @@ -1215,15 +1223,10 @@ static UINT rdpgfx_recv_caps_advertise_pdu(RdpgfxServerContext* context, Stream_Read_UINT32(s, capsSet->version); /* version (4 bytes) */ Stream_Read_UINT32(s, capsDataLength); /* capsDataLength (4 bytes) */ - if (capsDataLength != 4) - { - WLog_ERR(TAG, "capsDataLength does not equal to 4: %"PRIu32"", - capsDataLength); - free(capsSets); - return ERROR_INVALID_DATA; - } + if (capsDataLength >= 4) + Stream_Peek_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ - Stream_Read_UINT32(s, capsSet->flags); /* capsData (4 bytes) */ + Stream_Seek(s, capsSet->length); } if (context) diff --git a/include/freerdp/channels/rdpgfx.h b/include/freerdp/channels/rdpgfx.h index c0b4506..11ca7fa 100644 --- a/include/freerdp/channels/rdpgfx.h +++ b/include/freerdp/channels/rdpgfx.h @@ -102,7 +102,7 @@ typedef struct _RDPGFX_HEADER RDPGFX_HEADER; #define RDPGFX_CAPVERSION_106 0x000A0601 /** [MS-RDPEGFX] 2.2.3.9 */ #define RDPGFX_NUMBER_CAPSETS 9 -#define RDPGFX_CAPSET_SIZE 12 +#define RDPGFX_CAPSET_BASE_SIZE 8 struct _RDPGFX_CAPSET { -- 2.7.4