[core,capabilities] fix RFX capability parsing

* Require SURFCMDS_STREAM_SURFACE_BITS
* Improve error logging
* Improve content length checks
This commit is contained in:
Armin Novak 2024-07-24 13:16:41 +02:00 committed by akallabeth
parent 268bf25f02
commit e888769bf6
No known key found for this signature in database
GPG Key ID: A49454A3FC909FD5

View File

@ -2894,7 +2894,7 @@ static BOOL rdp_read_surface_commands_capability_set(wStream* s, rdpSettings* se
Stream_Read_UINT32(s, cmdFlags); /* cmdFlags (4 bytes) */
Stream_Seek_UINT32(s); /* reserved (4 bytes) */
settings->SurfaceCommandsEnabled = TRUE;
settings->SurfaceCommandsEnabled = (cmdFlags & SURFCMDS_STREAM_SURFACE_BITS) ? TRUE : FALSE;
settings->SurfaceFrameMarkerEnabled = (cmdFlags & SURFCMDS_FRAME_MARKER) ? TRUE : FALSE;
return TRUE;
}
@ -3044,6 +3044,279 @@ static BOOL rdp_apply_bitmap_codecs_capability_set(rdpSettings* settings, const
return TRUE;
}
static BOOL rdp_read_codec_ts_rfx_icap(wStream* sub, rdpSettings* settings, UINT16 icapLen)
{
UINT16 version = 0;
UINT16 tileSize = 0;
BYTE codecFlags = 0;
BYTE colConvBits = 0;
BYTE transformBits = 0;
BYTE entropyBits = 0;
/* TS_RFX_ICAP */
if (icapLen != 8)
{
WLog_ERR(TAG,
"[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP size %" PRIu16
" unsupported, expecting size %" PRIu16 " not supported",
icapLen, 8);
return FALSE;
}
if (!Stream_CheckAndLogRequiredLength(TAG, sub, 8))
return FALSE;
Stream_Read_UINT16(sub, version); /* version (2 bytes) */
Stream_Read_UINT16(sub, tileSize); /* tileSize (2 bytes) */
Stream_Read_UINT8(sub, codecFlags); /* flags (1 byte) */
Stream_Read_UINT8(sub, colConvBits); /* colConvBits (1 byte) */
Stream_Read_UINT8(sub, transformBits); /* transformBits (1 byte) */
Stream_Read_UINT8(sub, entropyBits); /* entropyBits (1 byte) */
if (version == 0x0009)
{
/* Version 0.9 */
if (tileSize != 0x0080)
{
WLog_ERR(TAG,
"[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " tile size %" PRIu16
" not supported",
version, tileSize);
return FALSE;
}
}
else if (version == 0x0100)
{
/* Version 1.0 */
if (tileSize != 0x0040)
{
WLog_ERR(TAG,
"[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " tile size %" PRIu16
" not supported",
version, tileSize);
return FALSE;
}
}
else
{
WLog_ERR(TAG, "[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::version %" PRIu16 " not supported",
version);
return FALSE;
}
/* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_COL_CONV_ICT (0x1) */
if (colConvBits != 1)
{
WLog_ERR(TAG,
"[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::colConvBits %" PRIu8
" not supported, must be CLW_COL_CONV_ICT (0x1)",
colConvBits);
return FALSE;
}
/* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP CLW_XFORM_DWT_53_A (0x1) */
if (transformBits != 1)
{
WLog_ERR(TAG,
"[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::transformBits %" PRIu8
" not supported, must be CLW_XFORM_DWT_53_A (0x1)",
colConvBits);
return FALSE;
}
const UINT8 CODEC_MODE = 0x02; /* [MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP */
if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x00))
return FALSE;
if ((codecFlags & CODEC_MODE) != 0)
{
if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxCodecMode, 0x02))
return FALSE;
}
else if ((codecFlags & ~CODEC_MODE) != 0)
WLog_WARN(TAG,
"[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::flags unknown value "
"0x%02" PRIx8,
(codecFlags & ~CODEC_MODE));
switch (entropyBits)
{
case CLW_ENTROPY_RLGR1:
if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR1))
return FALSE;
break;
case CLW_ENTROPY_RLGR3:
if (!freerdp_settings_set_uint32(settings, FreeRDP_RemoteFxRlgrMode, RLGR3))
return FALSE;
break;
default:
WLog_ERR(TAG,
"[MS-RDPRFX] 2.2.1.1.1.1.1 TS_RFX_ICAP::entropyBits "
"unsupported value 0x%02" PRIx8
", must be CLW_ENTROPY_RLGR1 (0x01) or CLW_ENTROPY_RLGR3 "
"(0x04)",
entropyBits);
return FALSE;
}
return TRUE;
}
static BOOL rdp_read_codec_ts_rfx_capset(wStream* s, rdpSettings* settings)
{
UINT16 blockType = 0;
UINT32 blockLen = 0;
BYTE rfxCodecId = 0;
UINT16 capsetType = 0;
UINT16 numIcaps = 0;
UINT16 icapLen = 0;
if (!Stream_CheckAndLogRequiredLength(TAG, s, 6))
return FALSE;
/* TS_RFX_CAPSET */
Stream_Read_UINT16(s, blockType); /* blockType (2 bytes) */
Stream_Read_UINT32(s, blockLen); /* blockLen (4 bytes) */
if (blockType != 0xCBC1)
{
WLog_ERR(TAG,
"[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockType[0x%04" PRIx16
"] != CBY_CAPSET (0xCBC1)",
blockType);
return FALSE;
}
if (blockLen < 6ull)
{
WLog_ERR(TAG, "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::blockLen[%" PRIu16 "] < 6", blockLen);
return FALSE;
}
if (!Stream_CheckAndLogRequiredLength(TAG, s, blockLen - 6ull))
return FALSE;
wStream sbuffer = { 0 };
wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), blockLen - 6ull);
WINPR_ASSERT(sub);
if (!Stream_CheckAndLogRequiredLength(TAG, sub, 7))
return FALSE;
Stream_Read_UINT8(sub, rfxCodecId); /* codecId (1 byte) */
Stream_Read_UINT16(sub, capsetType); /* capsetType (2 bytes) */
Stream_Read_UINT16(sub, numIcaps); /* numIcaps (2 bytes) */
Stream_Read_UINT16(sub, icapLen); /* icapLen (2 bytes) */
if (rfxCodecId != 1)
{
WLog_ERR(TAG, "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::codecId[%" PRIu16 "] != 1",
rfxCodecId);
return FALSE;
}
if (capsetType != 0xCFC0)
{
WLog_ERR(TAG,
"[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::capsetType[0x%04" PRIx16
"] != CLY_CAPSET (0xCFC0)",
capsetType);
return FALSE;
}
while (numIcaps--)
{
if (!rdp_read_codec_ts_rfx_icap(sub, settings, icapLen))
return FALSE;
}
return TRUE;
}
static BOOL rdp_read_codec_ts_rfx_caps(wStream* sub, rdpSettings* settings)
{
if (Stream_GetRemainingLength(sub) == 0)
return TRUE;
UINT16 blockType = 0;
UINT32 blockLen = 0;
UINT16 numCapsets = 0;
/* TS_RFX_CAPS */
if (!Stream_CheckAndLogRequiredLength(TAG, sub, 8))
return FALSE;
Stream_Read_UINT16(sub, blockType); /* blockType (2 bytes) */
Stream_Read_UINT32(sub, blockLen); /* blockLen (4 bytes) */
Stream_Read_UINT16(sub, numCapsets); /* numCapsets (2 bytes) */
if (blockType != 0xCBC0)
{
WLog_ERR(TAG,
"[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockType[0x%04" PRIx16
"] != CBY_CAPS (0xCBC0)",
blockType);
return FALSE;
}
if (blockLen != 8)
{
WLog_ERR(TAG, "[MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS::blockLen[%" PRIu16 "] != 8", blockLen);
return FALSE;
}
if (numCapsets != 1)
{
WLog_ERR(TAG, "[MS_RDPRFX] 2.2.1.1.1.1 TS_RFX_CAPSET::numIcaps[" PRIu16 "] != 1",
numCapsets);
return FALSE;
}
for (UINT16 x = 0; x < numCapsets; x++)
{
if (!rdp_read_codec_ts_rfx_capset(sub, settings))
return FALSE;
}
return TRUE;
}
static BOOL rdp_read_codec_ts_rfx_clnt_caps_container(wStream* s, rdpSettings* settings)
{
UINT32 rfxCapsLength = 0;
UINT32 rfxPropsLength = 0;
UINT32 captureFlags = 0;
/* [MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER */
if (!Stream_CheckAndLogRequiredLength(TAG, s, 4))
return FALSE;
Stream_Read_UINT32(s, rfxPropsLength); /* length (4 bytes) */
if (rfxPropsLength < 4)
{
WLog_ERR(TAG,
"[MS_RDPRFX] 2.2.1.1 TS_RFX_CLNT_CAPS_CONTAINER::length %" PRIu32
" too short, require at least 4 bytes",
rfxPropsLength);
return FALSE;
}
if (!Stream_CheckAndLogRequiredLength(TAG, s, rfxPropsLength - 4ull))
return FALSE;
wStream sbuffer = { 0 };
wStream* sub = Stream_StaticConstInit(&sbuffer, Stream_Pointer(s), rfxPropsLength - 4ull);
WINPR_ASSERT(sub);
if (!Stream_CheckAndLogRequiredLength(TAG, s, 8))
return FALSE;
Stream_Read_UINT32(sub, captureFlags); /* captureFlags (4 bytes) */
Stream_Read_UINT32(sub, rfxCapsLength); /* capsLength (4 bytes) */
if (!Stream_CheckAndLogRequiredLength(TAG, sub, rfxCapsLength))
return FALSE;
settings->RemoteFxCaptureFlags = captureFlags;
settings->RemoteFxOnly = (captureFlags & CARDP_CAPS_CAPTURE_NON_CAC) ? FALSE : TRUE;
/* [MS_RDPRFX] 2.2.1.1.1 TS_RFX_CAPS */
wStream tsbuffer = { 0 };
wStream* ts_sub = Stream_StaticConstInit(&tsbuffer, Stream_Pointer(sub), rfxCapsLength);
WINPR_ASSERT(ts_sub);
return rdp_read_codec_ts_rfx_caps(ts_sub, settings);
}
/*
* Read bitmap codecs capability set.
* msdn{dd891377}
@ -3086,101 +3359,10 @@ static BOOL rdp_read_bitmap_codecs_capability_set(wStream* s, rdpSettings* setti
{
if (UuidEqual(&codecGuid, &CODEC_GUID_REMOTEFX, &rpc_status))
{
UINT32 rfxCapsLength = 0;
UINT32 rfxPropsLength = 0;
UINT32 captureFlags = 0;
guidRemoteFx = TRUE;
settings->RemoteFxCodecId = codecId;
if (!Stream_CheckAndLogRequiredLength(TAG, sub, 12))
if (!rdp_read_codec_ts_rfx_clnt_caps_container(sub, settings))
return FALSE;
Stream_Read_UINT32(sub, rfxPropsLength); /* length (4 bytes) */
Stream_Read_UINT32(sub, captureFlags); /* captureFlags (4 bytes) */
Stream_Read_UINT32(sub, rfxCapsLength); /* capsLength (4 bytes) */
settings->RemoteFxCaptureFlags = captureFlags;
settings->RemoteFxOnly = (captureFlags & CARDP_CAPS_CAPTURE_NON_CAC) ? FALSE : TRUE;
if (rfxCapsLength)
{
UINT16 blockType = 0;
UINT32 blockLen = 0;
UINT16 numCapsets = 0;
BYTE rfxCodecId = 0;
UINT16 capsetType = 0;
UINT16 numIcaps = 0;
UINT16 icapLen = 0;
/* TS_RFX_CAPS */
if (!Stream_CheckAndLogRequiredLength(TAG, sub, 21))
return FALSE;
Stream_Read_UINT16(sub, blockType); /* blockType (2 bytes) */
Stream_Read_UINT32(sub, blockLen); /* blockLen (4 bytes) */
Stream_Read_UINT16(sub, numCapsets); /* numCapsets (2 bytes) */
if (blockType != 0xCBC0)
return FALSE;
if (blockLen != 8)
return FALSE;
if (numCapsets != 1)
return FALSE;
/* TS_RFX_CAPSET */
Stream_Read_UINT16(sub, blockType); /* blockType (2 bytes) */
Stream_Read_UINT32(sub, blockLen); /* blockLen (4 bytes) */
Stream_Read_UINT8(sub, rfxCodecId); /* codecId (1 byte) */
Stream_Read_UINT16(sub, capsetType); /* capsetType (2 bytes) */
Stream_Read_UINT16(sub, numIcaps); /* numIcaps (2 bytes) */
Stream_Read_UINT16(sub, icapLen); /* icapLen (2 bytes) */
if (blockType != 0xCBC1)
return FALSE;
if (rfxCodecId != 1)
return FALSE;
if (capsetType != 0xCFC0)
return FALSE;
while (numIcaps--)
{
UINT16 version = 0;
UINT16 tileSize = 0;
BYTE codecFlags = 0;
BYTE colConvBits = 0;
BYTE transformBits = 0;
BYTE entropyBits = 0;
/* TS_RFX_ICAP */
if (!Stream_CheckAndLogRequiredLength(TAG, sub, 8))
return FALSE;
Stream_Read_UINT16(sub, version); /* version (2 bytes) */
Stream_Read_UINT16(sub, tileSize); /* tileSize (2 bytes) */
Stream_Read_UINT8(sub, codecFlags); /* flags (1 byte) */
Stream_Read_UINT8(sub, colConvBits); /* colConvBits (1 byte) */
Stream_Read_UINT8(sub, transformBits); /* transformBits (1 byte) */
Stream_Read_UINT8(sub, entropyBits); /* entropyBits (1 byte) */
if (version == 0x0009)
{
/* Version 0.9 */
if (tileSize != 0x0080)
return FALSE;
}
else if (version == 0x0100)
{
/* Version 1.0 */
if (tileSize != 0x0040)
return FALSE;
}
else
return FALSE;
if (colConvBits != 1)
return FALSE;
if (transformBits != 1)
return FALSE;
}
}
}
else if (UuidEqual(&codecGuid, &CODEC_GUID_IMAGE_REMOTEFX, &rpc_status))
{