From 18a3fcf2fc2a89ebf2d7fda3264111029265bd79 Mon Sep 17 00:00:00 2001 From: Armin Novak Date: Mon, 4 Oct 2021 08:48:38 +0200 Subject: [PATCH] Updated wStream API and added torough checks * Do length/capacity checks in every read/write/seek function if WINPR_ASSERT is defined. * Ensure s->pointer is valid, e.g. within s->buffer + s->capacity (Stream_Rewind, Stream_Seek, ...) * Add return values to Stream_Set* functions so inalid arguments can be reported to the caller * Deprecated problematic stream manipulation functions (Stream_SetBuffer, Stream_SetPointer, Stream_SetCapacity) * Ensure length/capacity functions never return a value larger than the actual length/capacity --- channels/tsmf/client/tsmf_codec.c | 6 +- libfreerdp/codec/clear.c | 2 - libfreerdp/codec/dsp.c | 163 +++++++++++++++--------------- libfreerdp/core/connection.c | 14 +-- server/Sample/sfreerdp.c | 2 +- winpr/include/winpr/stream.h | 133 +++++++++++++++++------- winpr/libwinpr/utils/stream.c | 53 ++++++++++ 7 files changed, 243 insertions(+), 130 deletions(-) diff --git a/channels/tsmf/client/tsmf_codec.c b/channels/tsmf/client/tsmf_codec.c index 66723962d..e993d9356 100644 --- a/channels/tsmf/client/tsmf_codec.c +++ b/channels/tsmf/client/tsmf_codec.c @@ -569,7 +569,7 @@ BOOL tsmf_codec_parse_media_type(TS_AM_MEDIA_TYPE* mediatype, wStream* s) BOOL tsmf_codec_check_media_type(const char* decoder_name, wStream* s) { - BYTE* m; + size_t pos; BOOL ret = FALSE; TS_AM_MEDIA_TYPE mediatype; @@ -583,10 +583,10 @@ BOOL tsmf_codec_check_media_type(const char* decoder_name, wStream* s) decoderAvailable = TRUE; } - Stream_GetPointer(s, m); + pos = Stream_GetPosition(s); if (decoderAvailable) ret = tsmf_codec_parse_media_type(&mediatype, s); - Stream_SetPointer(s, m); + Stream_SetPosition(s, pos); if (ret) { diff --git a/libfreerdp/codec/clear.c b/libfreerdp/codec/clear.c index eba22a3c8..977a07c45 100644 --- a/libfreerdp/codec/clear.c +++ b/libfreerdp/codec/clear.c @@ -1045,8 +1045,6 @@ INT32 clear_decompress(CLEAR_CONTEXT* clear, const BYTE* pSrcData, UINT32 SrcSiz if (!s) return -2005; - Stream_SetLength(s, SrcSize); - if (Stream_GetRemainingLength(s) < 2) { WLog_ERR(TAG, "stream short %" PRIuz " [2 expected]", Stream_GetRemainingLength(s)); diff --git a/libfreerdp/codec/dsp.c b/libfreerdp/codec/dsp.c index 29f8ace79..e4126ea10 100644 --- a/libfreerdp/codec/dsp.c +++ b/libfreerdp/codec/dsp.c @@ -117,12 +117,6 @@ static INT16 read_int16(const BYTE* src) return (INT16)(src[0] | (src[1] << 8)); } -static void write_int16(BYTE* dst, INT32 val) -{ - dst[1] = (val >> 8) & 0xFF; - dst[0] = val & 0xFF; -} - static BOOL freerdp_dsp_channel_mix(FREERDP_DSP_CONTEXT* context, const BYTE* src, size_t size, const AUDIO_FORMAT* srcFormat, const BYTE** data, size_t* length) @@ -334,7 +328,7 @@ static UINT16 dsp_decode_ima_adpcm_sample(ADPCM* adpcm, unsigned int channel, BY static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE* src, size_t size, wStream* out) { - BYTE* dst; + size_t pos; BYTE sample; UINT16 decoded; size_t out_size = size * 4; @@ -346,7 +340,7 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT if (!Stream_EnsureCapacity(out, out_size)) return FALSE; - dst = Stream_Pointer(out); + pos = Stream_GetPosition(out); while (size > 0) { @@ -374,6 +368,8 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT { for (i = 0; i < 8; i++) { + BYTE* dst = Stream_Pointer(out); + channel = (i < 4 ? 0 : 1); sample = ((*src) & 0x0f); decoded = dsp_decode_ima_adpcm_sample(&context->adpcm, channel, sample); @@ -386,11 +382,16 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT src++; } - dst += 32; + if (!Stream_SafeSeek(out, 32)) + return FALSE; size -= 8; } else { + BYTE* dst = Stream_Pointer(out); + if (!Stream_SafeSeek(out, 4)) + return FALSE; + sample = ((*src) & 0x0f); decoded = dsp_decode_ima_adpcm_sample(&context->adpcm, 0, sample); *dst++ = (decoded & 0xFF); @@ -404,7 +405,6 @@ static BOOL freerdp_dsp_decode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT } } - Stream_SetPointer(out, dst); return TRUE; } @@ -712,8 +712,7 @@ static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT wStream* out) { int i; - BYTE* dst; - BYTE* start; + size_t start; INT16 sample; BYTE encoded; size_t out_size; @@ -723,30 +722,32 @@ static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT if (!Stream_EnsureRemainingCapacity(out, size)) return FALSE; - start = Stream_Buffer(context->buffer); - dst = Stream_Pointer(context->buffer); + start = Stream_GetPosition(context->buffer); + align = (context->format.nChannels > 1) ? 32 : 4; while (size >= align) { - if ((dst - start) % context->format.nBlockAlign == 0) + if ((Stream_GetPosition(context->buffer) - start) % context->format.nBlockAlign == 0) { - *dst++ = context->adpcm.ima.last_sample[0] & 0xFF; - *dst++ = (context->adpcm.ima.last_sample[0] >> 8) & 0xFF; - *dst++ = (BYTE)context->adpcm.ima.last_step[0]; - *dst++ = 0; + Stream_Write_UINT8(context->buffer, context->adpcm.ima.last_sample[0] & 0xFF); + Stream_Write_UINT8(context->buffer, (context->adpcm.ima.last_sample[0] >> 8) & 0xFF); + Stream_Write_UINT8(context->buffer, (BYTE)context->adpcm.ima.last_step[0]); + Stream_Write_UINT8(context->buffer, 0); if (context->format.nChannels > 1) { - *dst++ = context->adpcm.ima.last_sample[1] & 0xFF; - *dst++ = (context->adpcm.ima.last_sample[1] >> 8) & 0xFF; - *dst++ = (BYTE)context->adpcm.ima.last_step[1]; - *dst++ = 0; + Stream_Write_UINT8(context->buffer, context->adpcm.ima.last_sample[1] & 0xFF); + Stream_Write_UINT8(context->buffer, + (context->adpcm.ima.last_sample[1] >> 8) & 0xFF); + Stream_Write_UINT8(context->buffer, (BYTE)context->adpcm.ima.last_step[1]); + Stream_Write_UINT8(context->buffer, 0); } } if (context->format.nChannels > 1) { + BYTE* dst = Stream_Pointer(context->buffer); ZeroMemory(dst, 8); for (i = 0; i < 16; i++) @@ -758,7 +759,8 @@ static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT << ima_stereo_encode_map[i].byte_shift; } - dst += 8; + if (!Stream_SafeSeek(context->buffer, 8)) + return FALSE; size -= 32; } else @@ -769,18 +771,18 @@ static BOOL freerdp_dsp_encode_ima_adpcm(FREERDP_DSP_CONTEXT* context, const BYT sample = (INT16)(((UINT16)(*src)) | (((UINT16)(*(src + 1))) << 8)); src += 2; encoded |= dsp_encode_ima_adpcm_sample(&context->adpcm, 0, sample) << 4; - *dst++ = encoded; + Stream_Write_UINT8(context->buffer, encoded); size -= 4; } - if (dst - start == context->adpcm.ima.packet_size) + if (Stream_GetPosition(context->buffer) - start == context->adpcm.ima.packet_size) { - Stream_Write(out, start, context->adpcm.ima.packet_size); - dst = Stream_Buffer(context->buffer); + BYTE* bsrc = Stream_Buffer(context->buffer); + Stream_Write(out, bsrc, context->adpcm.ima.packet_size); + Stream_SetPosition(context->buffer, 0); } } - Stream_SetPointer(context->buffer, dst); return TRUE; } @@ -825,7 +827,6 @@ static INLINE INT16 freerdp_dsp_decode_ms_adpcm_sample(ADPCM* adpcm, BYTE sample static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE* src, size_t size, wStream* out) { - BYTE* dst; BYTE sample; const size_t out_size = size * 4; const UINT32 channels = context->format.nChannels; @@ -834,8 +835,6 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE if (!Stream_EnsureCapacity(out, out_size)) return FALSE; - dst = Stream_Pointer(out); - while (size > 0) { if (size % block_size == 0) @@ -857,14 +856,10 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE context->adpcm.ms.sample2[1] = read_int16(src); src += 2; size -= 14; - write_int16(dst, context->adpcm.ms.sample2[0]); - dst += 2; - write_int16(dst, context->adpcm.ms.sample2[1]); - dst += 2; - write_int16(dst, context->adpcm.ms.sample1[0]); - dst += 2; - write_int16(dst, context->adpcm.ms.sample1[1]); - dst += 2; + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample2[0]); + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample2[1]); + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample1[0]); + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample1[1]); } else { @@ -876,10 +871,8 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE context->adpcm.ms.sample2[0] = read_int16(src); src += 2; size -= 7; - write_int16(dst, context->adpcm.ms.sample2[0]); - dst += 2; - write_int16(dst, context->adpcm.ms.sample1[0]); - dst += 2; + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample2[0]); + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample1[0]); } } @@ -887,29 +880,28 @@ static BOOL freerdp_dsp_decode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE { sample = *src++; size--; - write_int16(dst, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0)); - dst += 2; - write_int16(dst, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 1)); - dst += 2; + Stream_Write_INT16(out, + freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0)); + Stream_Write_INT16( + out, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 1)); sample = *src++; size--; - write_int16(dst, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0)); - dst += 2; - write_int16(dst, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 1)); - dst += 2; + Stream_Write_INT16(out, + freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0)); + Stream_Write_INT16( + out, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 1)); } else { sample = *src++; size--; - write_int16(dst, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0)); - dst += 2; - write_int16(dst, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 0)); - dst += 2; + Stream_Write_INT16(out, + freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample >> 4, 0)); + Stream_Write_INT16( + out, freerdp_dsp_decode_ms_adpcm_sample(&context->adpcm, sample & 0x0F, 0)); } } - Stream_SetPointer(out, dst); return TRUE; } @@ -951,8 +943,7 @@ static BYTE freerdp_dsp_encode_ms_adpcm_sample(ADPCM* adpcm, INT32 sample, int c static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE* src, size_t size, wStream* out) { - BYTE* dst; - BYTE* start; + size_t start; INT32 sample; size_t out_size; const size_t step = 8 + ((context->format.nChannels > 1) ? 4 : 0); @@ -961,7 +952,7 @@ static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE if (!Stream_EnsureRemainingCapacity(out, size)) return FALSE; - start = dst = Stream_Pointer(out); + start = Stream_GetPosition(out); if (context->adpcm.ms.delta[0] < 16) context->adpcm.ms.delta[0] = 16; @@ -971,38 +962,42 @@ static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE while (size >= step) { - if ((dst - start) % context->format.nBlockAlign == 0) + BYTE val; + if ((Stream_GetPosition(out) - start) % context->format.nBlockAlign == 0) { if (context->format.nChannels > 1) { - *dst++ = context->adpcm.ms.predictor[0]; - *dst++ = context->adpcm.ms.predictor[1]; - *dst++ = (BYTE)(context->adpcm.ms.delta[0] & 0xFF); - *dst++ = (BYTE)((context->adpcm.ms.delta[0] >> 8) & 0xFF); - *dst++ = (BYTE)(context->adpcm.ms.delta[1] & 0xFF); - *dst++ = (BYTE)((context->adpcm.ms.delta[1] >> 8) & 0xFF); + Stream_Write_UINT8(out, context->adpcm.ms.predictor[0]); + Stream_Write_UINT8(out, context->adpcm.ms.predictor[1]); + Stream_Write_UINT8(out, (context->adpcm.ms.delta[0] & 0xFF)); + Stream_Write_UINT8(out, ((context->adpcm.ms.delta[0] >> 8) & 0xFF)); + Stream_Write_UINT8(out, (context->adpcm.ms.delta[1] & 0xFF)); + Stream_Write_UINT8(out, ((context->adpcm.ms.delta[1] >> 8) & 0xFF)); + context->adpcm.ms.sample1[0] = read_int16(src + 4); context->adpcm.ms.sample1[1] = read_int16(src + 6); context->adpcm.ms.sample2[0] = read_int16(src + 0); context->adpcm.ms.sample2[1] = read_int16(src + 2); - write_int16(dst + 0, context->adpcm.ms.sample1[0]); - write_int16(dst + 2, context->adpcm.ms.sample1[1]); - write_int16(dst + 4, context->adpcm.ms.sample2[0]); - write_int16(dst + 6, context->adpcm.ms.sample2[1]); - dst += 8; + + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample1[0]); + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample1[1]); + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample2[0]); + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample2[1]); + src += 8; size -= 8; } else { - *dst++ = context->adpcm.ms.predictor[0]; - *dst++ = (BYTE)(context->adpcm.ms.delta[0] & 0xFF); - *dst++ = (BYTE)((context->adpcm.ms.delta[0] >> 8) & 0xFF); + Stream_Write_UINT8(out, context->adpcm.ms.predictor[0]); + Stream_Write_UINT8(out, (BYTE)(context->adpcm.ms.delta[0] & 0xFF)); + Stream_Write_UINT8(out, (BYTE)((context->adpcm.ms.delta[0] >> 8) & 0xFF)); + context->adpcm.ms.sample1[0] = read_int16(src + 2); context->adpcm.ms.sample2[0] = read_int16(src + 0); - write_int16(dst + 0, context->adpcm.ms.sample1[0]); - write_int16(dst + 2, context->adpcm.ms.sample2[0]); - dst += 4; + + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample1[0]); + Stream_Write_INT16(out, (INT16)context->adpcm.ms.sample2[0]); src += 4; size -= 4; } @@ -1010,16 +1005,18 @@ static BOOL freerdp_dsp_encode_ms_adpcm(FREERDP_DSP_CONTEXT* context, const BYTE sample = read_int16(src); src += 2; - *dst = (freerdp_dsp_encode_ms_adpcm_sample(&context->adpcm, sample, 0) << 4) & 0xFF; + Stream_Write_UINT8( + out, (freerdp_dsp_encode_ms_adpcm_sample(&context->adpcm, sample, 0) << 4) & 0xFF); sample = read_int16(src); src += 2; - *dst += freerdp_dsp_encode_ms_adpcm_sample(&context->adpcm, sample, - context->format.nChannels > 1 ? 1 : 0); - dst++; + + Stream_Read_UINT8(out, val); + val += freerdp_dsp_encode_ms_adpcm_sample(&context->adpcm, sample, + context->format.nChannels > 1 ? 1 : 0); + Stream_Write_UINT8(out, val); size -= 4; } - Stream_SetPointer(out, dst); return TRUE; } diff --git a/libfreerdp/core/connection.c b/libfreerdp/core/connection.c index 035d0cca8..60b7ddc8f 100644 --- a/libfreerdp/core/connection.c +++ b/libfreerdp/core/connection.c @@ -995,7 +995,7 @@ BOOL rdp_client_connect_mcs_channel_join_confirm(rdpRdp* rdp, wStream* s) BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s) { - BYTE* mark; + size_t pos; UINT16 length; UINT16 channelId; @@ -1003,7 +1003,7 @@ BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s) if (rdp->mcs->messageChannelId != 0) { /* Process any MCS message channel PDUs. */ - Stream_GetPointer(s, mark); + pos = Stream_GetPosition(s); if (rdp_read_header(rdp, s, &length, &channelId)) { @@ -1028,7 +1028,7 @@ BOOL rdp_client_connect_auto_detect(rdpRdp* rdp, wStream* s) } } - Stream_SetPointer(s, mark); + Stream_SetPosition(s, pos); } return FALSE; @@ -1058,19 +1058,21 @@ int rdp_client_connect_license(rdpRdp* rdp, wStream* s) int rdp_client_connect_demand_active(rdpRdp* rdp, wStream* s) { - BYTE* mark; + size_t pos; UINT16 width; UINT16 height; UINT16 length; width = rdp->settings->DesktopWidth; height = rdp->settings->DesktopHeight; - Stream_GetPointer(s, mark); + + pos = Stream_GetPosition(s); if (!rdp_recv_demand_active(rdp, s)) { int rc; UINT16 channelId; - Stream_SetPointer(s, mark); + + Stream_SetPosition(s, pos); if (!rdp_recv_get_active_header(rdp, s, &channelId, &length)) return -1; /* Was Stream_Seek(s, RDP_PACKET_HEADER_MAX_LENGTH); diff --git a/server/Sample/sfreerdp.c b/server/Sample/sfreerdp.c index c68b338e6..730eec9b3 100644 --- a/server/Sample/sfreerdp.c +++ b/server/Sample/sfreerdp.c @@ -528,7 +528,7 @@ static BOOL tf_peer_dump_rfx(freerdp_peer* client) record.data = Stream_Buffer(s); pcap_get_next_record_content(pcap_rfx, &record); - Stream_SetPointer(s, Stream_Buffer(s) + Stream_Capacity(s)); + Stream_SetPosition(s, Stream_Capacity(s)); if (info->test_dump_rfx_realtime && test_sleep_tsdiff(&prev_seconds, &prev_useconds, record.header.ts_sec, diff --git a/winpr/include/winpr/stream.h b/winpr/include/winpr/stream.h index 5d38c3987..1ce348178 100644 --- a/winpr/include/winpr/stream.h +++ b/winpr/include/winpr/stream.h @@ -50,6 +50,10 @@ extern "C" }; typedef struct _wStream wStream; + static INLINE size_t Stream_Capacity(wStream* _s); + static INLINE size_t Stream_GetRemainingCapacity(wStream* _s); + static INLINE size_t Stream_GetRemainingLength(wStream* _s); + WINPR_API BOOL Stream_EnsureCapacity(wStream* s, size_t size); WINPR_API BOOL Stream_EnsureRemainingCapacity(wStream* s, size_t size); @@ -60,26 +64,38 @@ extern "C" static INLINE void Stream_Seek(wStream* s, size_t _offset) { WINPR_ASSERT(s); + WINPR_ASSERT(Stream_GetRemainingCapacity(s) >= _offset); s->pointer += (_offset); } static INLINE void Stream_Rewind(wStream* s, size_t _offset) { + size_t cur; WINPR_ASSERT(s); - s->pointer -= (_offset); + WINPR_ASSERT(s->buffer <= s->pointer); + cur = (size_t)(s->pointer - s->buffer); + WINPR_ASSERT(cur >= _offset); + if (cur >= _offset) + s->pointer -= (_offset); + else + s->pointer = s->buffer; } -#define _stream_read_n8(_t, _s, _v, _p) \ - do \ - { \ - (_v) = (_t)(*(_s)->pointer); \ - if (_p) \ - Stream_Seek(_s, sizeof(_t)); \ +#define _stream_read_n8(_t, _s, _v, _p) \ + do \ + { \ + WINPR_ASSERT(_s); \ + WINPR_ASSERT(Stream_GetRemainingLength(_s) >= 1); \ + (_v) = (_t)(*(_s)->pointer); \ + if (_p) \ + Stream_Seek(_s, sizeof(_t)); \ } while (0) #define _stream_read_n16_le(_t, _s, _v, _p) \ do \ { \ + WINPR_ASSERT(_s); \ + WINPR_ASSERT(Stream_GetRemainingLength(_s) >= 2); \ (_v) = (_t)((*(_s)->pointer) + (((UINT16)(*((_s)->pointer + 1))) << 8)); \ if (_p) \ Stream_Seek(_s, sizeof(_t)); \ @@ -88,6 +104,8 @@ extern "C" #define _stream_read_n16_be(_t, _s, _v, _p) \ do \ { \ + WINPR_ASSERT(_s); \ + WINPR_ASSERT(Stream_GetRemainingLength(_s) >= 2); \ (_v) = (_t)((((UINT16)(*(_s)->pointer)) << 8) + (UINT16)(*((_s)->pointer + 1))); \ if (_p) \ Stream_Seek(_s, sizeof(_t)); \ @@ -96,6 +114,8 @@ extern "C" #define _stream_read_n32_le(_t, _s, _v, _p) \ do \ { \ + WINPR_ASSERT(_s); \ + WINPR_ASSERT(Stream_GetRemainingLength(_s) >= 4); \ (_v) = (_t)((UINT32)(*(_s)->pointer) + (((UINT32)(*((_s)->pointer + 1))) << 8) + \ (((UINT32)(*((_s)->pointer + 2))) << 16) + \ ((((UINT32) * ((_s)->pointer + 3))) << 24)); \ @@ -106,6 +126,8 @@ extern "C" #define _stream_read_n32_be(_t, _s, _v, _p) \ do \ { \ + WINPR_ASSERT(_s); \ + WINPR_ASSERT(Stream_GetRemainingLength(_s) >= 4); \ (_v) = (_t)(((((UINT32) * ((_s)->pointer))) << 24) + \ (((UINT32)(*((_s)->pointer + 1))) << 16) + \ (((UINT32)(*((_s)->pointer + 2))) << 8) + (((UINT32)(*((_s)->pointer + 3))))); \ @@ -116,6 +138,8 @@ extern "C" #define _stream_read_n64_le(_t, _s, _v, _p) \ do \ { \ + WINPR_ASSERT(_s); \ + WINPR_ASSERT(Stream_GetRemainingLength(_s) >= 8); \ (_v) = (_t)( \ (UINT64)(*(_s)->pointer) + (((UINT64)(*((_s)->pointer + 1))) << 8) + \ (((UINT64)(*((_s)->pointer + 2))) << 16) + (((UINT64)(*((_s)->pointer + 3))) << 24) + \ @@ -128,6 +152,8 @@ extern "C" #define _stream_read_n64_be(_t, _s, _v, _p) \ do \ { \ + WINPR_ASSERT(_s); \ + WINPR_ASSERT(Stream_GetRemainingLength(_s) >= 8); \ (_v) = (_t)( \ (((UINT64)(*((_s)->pointer))) << 56) + (((UINT64)(*((_s)->pointer + 1))) << 48) + \ (((UINT64)(*((_s)->pointer + 2))) << 40) + (((UINT64)(*((_s)->pointer + 3))) << 32) + \ @@ -162,6 +188,7 @@ extern "C" { WINPR_ASSERT(_s); WINPR_ASSERT(_b || (_n == 0)); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= _n); memcpy(_b, (_s->pointer), (_n)); Stream_Seek(_s, _n); } @@ -191,18 +218,21 @@ extern "C" { WINPR_ASSERT(_s); WINPR_ASSERT(_b || (_n == 0)); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= _n); memcpy(_b, (_s->pointer), (_n)); } static INLINE void Stream_Write_UINT8(wStream* _s, UINT8 _v) { WINPR_ASSERT(_s); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 1); *_s->pointer++ = (UINT8)(_v); } static INLINE void Stream_Write_INT16(wStream* _s, INT16 _v) { WINPR_ASSERT(_s); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 2); *_s->pointer++ = (_v)&0xFF; *_s->pointer++ = ((_v) >> 8) & 0xFF; } @@ -210,6 +240,7 @@ extern "C" static INLINE void Stream_Write_UINT16(wStream* _s, UINT16 _v) { WINPR_ASSERT(_s); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 2); *_s->pointer++ = (_v)&0xFF; *_s->pointer++ = ((_v) >> 8) & 0xFF; } @@ -217,6 +248,7 @@ extern "C" static INLINE void Stream_Write_UINT16_BE(wStream* _s, UINT16 _v) { WINPR_ASSERT(_s); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 2); *_s->pointer++ = ((_v) >> 8) & 0xFF; *_s->pointer++ = (_v)&0xFF; } @@ -224,6 +256,7 @@ extern "C" static INLINE void Stream_Write_INT32(wStream* _s, INT32 _v) { WINPR_ASSERT(_s); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 4); *_s->pointer++ = (_v)&0xFF; *_s->pointer++ = ((_v) >> 8) & 0xFF; *_s->pointer++ = ((_v) >> 16) & 0xFF; @@ -233,6 +266,7 @@ extern "C" static INLINE void Stream_Write_UINT32(wStream* _s, UINT32 _v) { WINPR_ASSERT(_s); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 4); *_s->pointer++ = (_v)&0xFF; *_s->pointer++ = ((_v) >> 8) & 0xFF; *_s->pointer++ = ((_v) >> 16) & 0xFF; @@ -248,6 +282,7 @@ extern "C" static INLINE void Stream_Write_UINT64(wStream* _s, UINT64 _v) { WINPR_ASSERT(_s); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= 8); *_s->pointer++ = (UINT64)(_v)&0xFF; *_s->pointer++ = ((UINT64)(_v) >> 8) & 0xFF; *_s->pointer++ = ((UINT64)(_v) >> 16) & 0xFF; @@ -263,6 +298,7 @@ extern "C" { WINPR_ASSERT(_s); WINPR_ASSERT(_b); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= _n); memcpy(_s->pointer, (_b), (_n)); Stream_Seek(_s, _n); } @@ -281,6 +317,7 @@ extern "C" static INLINE void Stream_Zero(wStream* _s, size_t _n) { WINPR_ASSERT(_s); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= (_n)); memset(_s->pointer, '\0', (_n)); Stream_Seek(_s, _n); } @@ -288,6 +325,7 @@ extern "C" static INLINE void Stream_Fill(wStream* _s, int _v, size_t _n) { WINPR_ASSERT(_s); + WINPR_ASSERT(Stream_GetRemainingCapacity(_s) >= (_n)); memset(_s->pointer, _v, (_n)); Stream_Seek(_s, _n); } @@ -296,6 +334,9 @@ extern "C" { WINPR_ASSERT(_src); WINPR_ASSERT(_dst); + WINPR_ASSERT(Stream_GetRemainingCapacity(_src) >= (_n)); + WINPR_ASSERT(Stream_GetRemainingCapacity(_dst) >= (_n)); + memcpy(_dst->pointer, _src->pointer, _n); Stream_Seek(_dst, _n); Stream_Seek(_src, _n); @@ -308,11 +349,6 @@ extern "C" } #define Stream_GetBuffer(_s, _b) _b = Stream_Buffer(_s) - static INLINE void Stream_SetBuffer(wStream* _s, BYTE* _b) - { - WINPR_ASSERT(_s); - _s->buffer = _b; - } static INLINE BYTE* Stream_Pointer(wStream* _s) { @@ -321,11 +357,15 @@ extern "C" } #define Stream_GetPointer(_s, _p) _p = Stream_Pointer(_s) - static INLINE void Stream_SetPointer(wStream* _s, BYTE* _p) - { - WINPR_ASSERT(_s); - _s->pointer = _p; - } + +#if defined(WITH_WINPR_DEPRECATED) + WINPR_API WINPR_DEPRECATED_VAR("Use Stream_SetPosition instead", + BOOL Stream_SetPointer(wStream* _s, BYTE* _p)); + WINPR_API WINPR_DEPRECATED_VAR("Use Stream_New(buffer, capacity) instead", + BOOL Stream_SetBuffer(wStream* _s, BYTE* _b)); + WINPR_API WINPR_DEPRECATED_VAR("Use Stream_New(buffer, capacity) instead", + void Stream_SetCapacity(wStream* _s, size_t capacity)); +#endif static INLINE size_t Stream_Length(wStream* _s) { @@ -334,11 +374,7 @@ extern "C" } #define Stream_GetLength(_s, _l) _l = Stream_Length(_s) - static INLINE void Stream_SetLength(wStream* _s, size_t _l) - { - WINPR_ASSERT(_s); - _s->length = _l; - } + WINPR_API BOOL Stream_SetLength(wStream* _s, size_t _l); static INLINE size_t Stream_Capacity(wStream* _s) { @@ -347,40 +383,67 @@ extern "C" } #define Stream_GetCapacity(_s, _c) _c = Stream_Capacity(_s); - static INLINE void Stream_SetCapacity(wStream* _s, size_t _c) - { - WINPR_ASSERT(_s); - _s->capacity = _c; - } static INLINE size_t Stream_GetPosition(wStream* _s) { WINPR_ASSERT(_s); + WINPR_ASSERT(_s->buffer <= _s->pointer); return (size_t)(_s->pointer - _s->buffer); } - static INLINE void Stream_SetPosition(wStream* _s, size_t _p) - { - WINPR_ASSERT(_s); - _s->pointer = _s->buffer + (_p); - } + WINPR_API BOOL Stream_SetPosition(wStream* _s, size_t _p); static INLINE void Stream_SealLength(wStream* _s) { + size_t cur; WINPR_ASSERT(_s); - _s->length = (size_t)(_s->pointer - _s->buffer); + WINPR_ASSERT(_s->buffer <= _s->pointer); + cur = (size_t)(_s->pointer - _s->buffer); + WINPR_ASSERT(cur <= _s->capacity); + if (cur <= _s->capacity) + _s->length = cur; + else + { + const char* wTAG = "com.freerdp.winpr.wStream"; + WLog_FATAL(wTAG, "wStream API misuse: stream was written out of bounds"); + winpr_log_backtrace(wTAG, WLOG_FATAL, 20); + _s->length = 0; + } } static INLINE size_t Stream_GetRemainingCapacity(wStream* _s) { + size_t cur; WINPR_ASSERT(_s); - return (_s->capacity - (size_t)(_s->pointer - _s->buffer)); + WINPR_ASSERT(_s->buffer <= _s->pointer); + cur = (size_t)(_s->pointer - _s->buffer); + WINPR_ASSERT(cur <= _s->capacity); + if (cur > _s->capacity) + { + const char* wTAG = "com.freerdp.winpr.wStream"; + WLog_FATAL(wTAG, "wStream API misuse: stream was written out of bounds"); + winpr_log_backtrace(wTAG, WLOG_FATAL, 20); + return 0; + } + return (_s->capacity - cur); } static INLINE size_t Stream_GetRemainingLength(wStream* _s) { + size_t cur; WINPR_ASSERT(_s); - return (_s->length - (size_t)(_s->pointer - _s->buffer)); + WINPR_ASSERT(_s->buffer <= _s->pointer); + WINPR_ASSERT(_s->length <= _s->capacity); + cur = (size_t)(_s->pointer - _s->buffer); + WINPR_ASSERT(cur <= _s->length); + if (cur > _s->length) + { + const char* wTAG = "com.freerdp.winpr.wStream"; + WLog_FATAL(wTAG, "wStream API misuse: stream was read out of bounds"); + winpr_log_backtrace(wTAG, WLOG_FATAL, 20); + return 0; + } + return (_s->length - cur); } static INLINE void Stream_Clear(wStream* _s) diff --git a/winpr/libwinpr/utils/stream.c b/winpr/libwinpr/utils/stream.c index d09fd40b0..cd50f88ce 100644 --- a/winpr/libwinpr/utils/stream.c +++ b/winpr/libwinpr/utils/stream.c @@ -133,3 +133,56 @@ void Stream_Free(wStream* s, BOOL bFreeBuffer) free(s); } } + +BOOL Stream_SetLength(wStream* _s, size_t _l) +{ + if ((_l) > Stream_Capacity(_s)) + { + _s->length = 0; + return FALSE; + } + _s->length = _l; + return TRUE; +} + +BOOL Stream_SetPosition(wStream* _s, size_t _p) +{ + if ((_p) > Stream_Capacity(_s)) + { + _s->pointer = _s->buffer; + return FALSE; + } + _s->pointer = _s->buffer + (_p); + return TRUE; +} + +#if defined(WITH_WINPR_DEPRECATED) +BOOL Stream_SetPointer(wStream* _s, BYTE* _p) +{ + WINPR_ASSERT(_s); + if (!_p || (_s->buffer > _p) || (_s->buffer + _s->capacity < _p)) + { + _s->pointer = _s->buffer; + return FALSE; + } + _s->pointer = _p; + return TRUE; +} + +BOOL Stream_SetBuffer(wStream* _s, BYTE* _b) +{ + WINPR_ASSERT(_s); + WINPR_ASSERT(_b); + + _s->buffer = _b; + _s->pointer = _b; + return _s->buffer != NULL; +} + +void Stream_SetCapacity(wStream* _s, size_t _c) +{ + WINPR_ASSERT(_s); + _s->capacity = _c; +} + +#endif