GUACAMOLE-1059: Use FreeRDP function for verifying Stream length before reading.
diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c
index 0f45303..52201a2 100644
--- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c
+++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages-file-info.c
@@ -135,6 +135,10 @@
wStream* output_stream;
char destination_path[GUAC_RDP_FS_MAX_PATH];
+ /* Check stream size prior to reading. */
+ if (Stream_GetRemainingLength(input_stream) < 6)
+ return;
+
/* Read structure */
Stream_Seek_UINT8(input_stream); /* ReplaceIfExists */
Stream_Seek_UINT8(input_stream); /* RootDirectory */
diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c
index 529eea5..0e9581c 100644
--- a/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c
+++ b/src/protocols/rdp/channels/rdpdr/rdpdr-fs-messages.c
@@ -48,6 +48,10 @@
int create_disposition, create_options, path_length;
char path[GUAC_RDP_FS_MAX_PATH];
+ /* Check remaining stream data prior to reading. */
+ if (Stream_GetRemainingLength(input_stream) < 32)
+ return;
+
/* Read "create" information */
Stream_Read_UINT32(input_stream, desired_access);
Stream_Seek_UINT64(input_stream); /* allocation size */
@@ -123,6 +127,10 @@
wStream* output_stream;
+ /* Check remaining bytes before reading stream. */
+ if (Stream_GetRemainingLength(input_stream) < 12)
+ return;
+
/* Read packet */
Stream_Read_UINT32(input_stream, length);
Stream_Read_UINT64(input_stream, offset);
@@ -172,6 +180,10 @@
wStream* output_stream;
+ /* Check remaining length. */
+ if (Stream_GetRemainingLength(input_stream) < 32)
+ return;
+
/* Read packet */
Stream_Read_UINT32(input_stream, length);
Stream_Read_UINT64(input_stream, offset);
@@ -244,6 +256,10 @@
int fs_information_class;
+ /* Check remaining length */
+ if (Stream_GetRemainingLength(input_stream) < 4)
+ return;
+
Stream_Read_UINT32(input_stream, fs_information_class);
/* Dispatch to appropriate class-specific handler */
@@ -282,6 +298,10 @@
int fs_information_class;
+ /* Check remaining length */
+ if (Stream_GetRemainingLength(input_stream) < 4)
+ return;
+
Stream_Read_UINT32(input_stream, fs_information_class);
/* Dispatch to appropriate class-specific handler */
@@ -328,6 +348,10 @@
int fs_information_class;
int length;
+ /* Check remaining length */
+ if (Stream_GetRemainingLength(input_stream) < 32)
+ return;
+
Stream_Read_UINT32(input_stream, fs_information_class);
Stream_Read_UINT32(input_stream, length); /* Length */
Stream_Seek(input_stream, 24); /* Padding */
@@ -406,6 +430,9 @@
if (file == NULL)
return;
+ if (Stream_GetRemainingLength(input_stream) < 9)
+ return;
+
/* Read main header */
Stream_Read_UINT32(input_stream, fs_information_class);
Stream_Read_UINT8(input_stream, initial_query);
@@ -414,6 +441,9 @@
/* If this is the first query, the path is included after padding */
if (initial_query) {
+ if (Stream_GetRemainingLength(input_stream) < 23)
+ return;
+
Stream_Seek(input_stream, 23); /* Padding */
/* Convert path to UTF-8 */
diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c b/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c
index 28a27e6..76808fa 100644
--- a/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c
+++ b/src/protocols/rdp/channels/rdpdr/rdpdr-messages.c
@@ -212,6 +212,9 @@
unsigned int major, minor, client_id;
+ if (Stream_GetRemainingLength(input_stream) < 8)
+ return;
+
Stream_Read_UINT16(input_stream, major);
Stream_Read_UINT16(input_stream, minor);
Stream_Read_UINT32(input_stream, client_id);
@@ -243,6 +246,9 @@
unsigned int device_id, ntstatus;
int severity, c, n, facility, code;
+ if (Stream_GetRemainingLength(input_stream) < 8)
+ return;
+
Stream_Read_UINT32(input_stream, device_id);
Stream_Read_UINT32(input_stream, ntstatus);
@@ -278,6 +284,9 @@
guac_rdpdr* rdpdr = (guac_rdpdr*) svc->data;
guac_rdpdr_iorequest iorequest;
+ if (Stream_GetRemainingLength(input_stream) < 20)
+ return;
+
/* Read header */
Stream_Read_UINT32(input_stream, iorequest.device_id);
Stream_Read_UINT32(input_stream, iorequest.file_id);
@@ -306,6 +315,9 @@
int count;
int i;
+ if (Stream_GetRemainingLength(input_stream) < 4)
+ return;
+
/* Read header */
Stream_Read_UINT16(input_stream, count);
Stream_Seek(input_stream, 2);
@@ -316,9 +328,15 @@
int type;
int length;
+ if (Stream_GetRemainingLength(input_stream) < 4)
+ break;
+
Stream_Read_UINT16(input_stream, type);
Stream_Read_UINT16(input_stream, length);
+ if (Stream_GetRemainingLength(input_stream) < (length - 4))
+ break;
+
/* Ignore all for now */
guac_client_log(svc->client, GUAC_LOG_DEBUG, "Ignoring server capability set type=0x%04x, length=%i", type, length);
Stream_Seek(input_stream, length - 4);
diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c b/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c
index d90116f..fb0b1c9 100644
--- a/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c
+++ b/src/protocols/rdp/channels/rdpdr/rdpdr-printer.c
@@ -67,6 +67,9 @@
int length;
int status;
+ if (Stream_GetRemainingLength(input_stream) < 32)
+ return;
+
/* Read buffer of print data */
Stream_Read_UINT32(input_stream, length);
Stream_Seek(input_stream, 8); /* Offset */
diff --git a/src/protocols/rdp/channels/rdpdr/rdpdr.c b/src/protocols/rdp/channels/rdpdr/rdpdr.c
index e04bc9d..5499e71 100644
--- a/src/protocols/rdp/channels/rdpdr/rdpdr.c
+++ b/src/protocols/rdp/channels/rdpdr/rdpdr.c
@@ -38,6 +38,9 @@
int component;
int packet_id;
+ if (Stream_GetRemainingLength(input_stream) < 4)
+ return;
+
/* Read header */
Stream_Read_UINT16(input_stream, component);
Stream_Read_UINT16(input_stream, packet_id);
diff --git a/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c b/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c
index 1d69e06..9e33c0e 100644
--- a/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c
+++ b/src/protocols/rdp/channels/rdpsnd/rdpsnd-messages.c
@@ -50,6 +50,9 @@
/* Reset own format count */
rdpsnd->format_count = 0;
+ if (Stream_GetRemainingLength(input_stream) < 20)
+ return;
+
/* Format header */
Stream_Seek(input_stream, 14);
Stream_Read_UINT16(input_stream, server_format_count);
@@ -96,6 +99,9 @@
/* Remember position in stream */
Stream_GetPointer(input_stream, format_start);
+ if (Stream_GetRemainingLength(input_stream) < 18)
+ return;
+
/* Read format */
Stream_Read_UINT16(input_stream, format_tag);
Stream_Read_UINT16(input_stream, channels);
@@ -106,6 +112,10 @@
/* Skip past extra data */
Stream_Read_UINT16(input_stream, body_size);
+
+ if (Stream_GetRemainingLength(input_stream) < body_size)
+ return;
+
Stream_Seek(input_stream, body_size);
/* If PCM, accept */
@@ -205,6 +215,9 @@
guac_rdpsnd* rdpsnd = (guac_rdpsnd*) svc->data;
+ if (Stream_GetRemainingLength(input_stream) < 4)
+ return;
+
/* Read timestamp and data size */
Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
Stream_Read_UINT16(input_stream, data_size);
@@ -232,6 +245,9 @@
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
guac_audio_stream* audio = rdp_client->audio;
+ if (Stream_GetRemainingLength(input_stream) < 12)
+ return;
+
/* Read wave information */
Stream_Read_UINT16(input_stream, rdpsnd->server_timestamp);
Stream_Read_UINT16(input_stream, format);
diff --git a/src/protocols/rdp/channels/rdpsnd/rdpsnd.c b/src/protocols/rdp/channels/rdpsnd/rdpsnd.c
index be6034d..0873a94 100644
--- a/src/protocols/rdp/channels/rdpsnd/rdpsnd.c
+++ b/src/protocols/rdp/channels/rdpsnd/rdpsnd.c
@@ -35,11 +35,23 @@
guac_rdpsnd* rdpsnd = (guac_rdpsnd*) svc->data;
guac_rdpsnd_pdu_header header;
+ /* Check that we at least have a header. */
+ if (Stream_GetRemainingLength(input_stream) < 4)
+ return;
+
/* Read RDPSND PDU header */
Stream_Read_UINT8(input_stream, header.message_type);
Stream_Seek_UINT8(input_stream);
Stream_Read_UINT16(input_stream, header.body_size);
-
+
+ if (Stream_GetRemainingLength(input_stream) < header.body_size) {
+ guac_client_log(svc->client, GUAC_LOG_DEBUG, "Not enough bytes in stream."
+ " Remaining: %d, Body size: %d",
+ Stream_GetRemainingLength(input_stream),
+ header.body_size);
+ return;
+ }
+
/*
* If next PDU is SNDWAVE (due to receiving WaveInfo PDU previously),
* ignore the header and parse as a Wave PDU.
diff --git a/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c b/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c
index 535cb45..91dee29 100644
--- a/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c
+++ b/src/protocols/rdp/plugins/guac-common-svc/guac-common-svc.c
@@ -116,6 +116,10 @@
svc->_input_stream = Stream_New(NULL, total_length);
}
+ /* leave if we don't have a stream. */
+ if (svc->_input_stream == NULL)
+ return;
+
/* Add chunk to buffer only if sufficient space remains */
if (Stream_EnsureRemainingCapacity(svc->_input_stream, data_length))
Stream_Write(svc->_input_stream, data, data_length);
@@ -137,6 +141,7 @@
svc->_receive_handler(svc, svc->_input_stream);
Stream_Free(svc->_input_stream, TRUE);
+ svc->_input_stream = NULL;
}
diff --git a/src/protocols/rdp/plugins/guacai/guacai-messages.c b/src/protocols/rdp/plugins/guacai/guacai-messages.c
index 38f7a7c..8641002 100644
--- a/src/protocols/rdp/plugins/guacai/guacai-messages.c
+++ b/src/protocols/rdp/plugins/guacai/guacai-messages.c
@@ -39,6 +39,9 @@
static void guac_rdp_ai_read_format(wStream* stream,
guac_rdp_ai_format* format) {
+ if (Stream_GetRemainingLength(stream) < 18)
+ return;
+
/* Read audio format into structure */
Stream_Read_UINT16(stream, format->tag); /* wFormatTag */
Stream_Read_UINT16(stream, format->channels); /* nChannels */
@@ -49,7 +52,8 @@
Stream_Read_UINT16(stream, format->data_size); /* cbSize */
/* Read arbitrary data block (if applicable) */
- if (format->data_size != 0) {
+ if (format->data_size != 0
+ && Stream_GetRemainingLength(stream) >= format->data_size) {
format->data = Stream_Pointer(stream); /* data */
Stream_Seek(stream, format->data_size);
}
@@ -232,6 +236,12 @@
void guac_rdp_ai_process_version(guac_client* client,
IWTSVirtualChannel* channel, wStream* stream) {
+ if (Stream_GetRemainingLength(stream) < 4) {
+ guac_client_log(client, GUAC_LOG_WARNING,
+ "Invalid value provided for AUDIO_INPUT version.");
+ return;
+ }
+
UINT32 version;
Stream_Read_UINT32(stream, version);
@@ -258,10 +268,13 @@
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
guac_rdp_audio_buffer* audio_buffer = rdp_client->audio_input;
+ if (Stream_GetRemainingLength(stream) < 8)
+ return;
+
UINT32 num_formats;
Stream_Read_UINT32(stream, num_formats); /* NumFormats */
Stream_Seek_UINT32(stream); /* cbSizeFormatsPacket (MUST BE IGNORED) */
-
+
UINT32 index;
for (index = 0; index < num_formats; index++) {
@@ -306,6 +319,9 @@
guac_rdp_client* rdp_client = (guac_rdp_client*) client->data;
guac_rdp_audio_buffer* audio_buffer = rdp_client->audio_input;
+ if (Stream_GetRemainingLength(stream) < 8)
+ return;
+
UINT32 packet_frames;
UINT32 initial_format;
diff --git a/src/protocols/rdp/plugins/guacai/guacai.c b/src/protocols/rdp/plugins/guacai/guacai.c
index 15de865..5f2319d 100644
--- a/src/protocols/rdp/plugins/guacai/guacai.c
+++ b/src/protocols/rdp/plugins/guacai/guacai.c
@@ -52,10 +52,13 @@
static void guac_rdp_ai_handle_data(guac_client* client,
IWTSVirtualChannel* channel, wStream* stream) {
+ if (Stream_GetRemainingLength(stream) < 1)
+ return;
+
/* Read message ID from received PDU */
BYTE message_id;
Stream_Read_UINT8(stream, message_id);
-
+
/* Invoke appropriate message processor based on ID */
switch (message_id) {