summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorFrediano Ziglio <fziglio@redhat.com>2017-05-15 15:57:28 +0100
committerChristophe Fergeau <cfergeau@redhat.com>2017-07-11 10:40:27 +0200
commit111ab38611cef5012f1565a65fa2d8a8a05cce37 (patch)
tree8fe8f13e19e6e2b8249bd906b4085648cfab5958
parentfa85fbf880fb01f42bf5d8c009151e92824096e6 (diff)
reds: Disconnect when receiving overly big ClientMonitorsConfig
Total message size received from the client was unlimited. There is a 2kiB size check on individual agent messages, but the MonitorsConfig message can be split in multiple chunks, and the size of the non-chunked MonitorsConfig message was never checked. This could easily lead to memory exhaustion on the host. Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
-rw-r--r--server/reds.c25
1 files changed, 23 insertions, 2 deletions
diff --git a/server/reds.c b/server/reds.c
index 4aeac9a5..ec2b6f47 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1105,14 +1105,29 @@ void reds_release_agent_data_buffer(RedsState *reds, uint8_t *buf)
static void reds_on_main_agent_monitors_config(RedsState *reds,
MainChannelClient *mcc, const void *message, size_t size)
{
+ const unsigned int MAX_MONITORS = 256;
+ const unsigned int MAX_MONITOR_CONFIG_SIZE =
+ sizeof(VDAgentMonitorsConfig) + MAX_MONITORS * sizeof(VDAgentMonConfig);
+
VDAgentMessage *msg_header;
VDAgentMonitorsConfig *monitors_config;
SpiceBuffer *cmc = &reds->client_monitors_config;
+ // limit size of message sent by the client as this can cause a DoS through
+ // memory exhaustion, or potentially some integer overflows
+ if (sizeof(VDAgentMessage) + MAX_MONITOR_CONFIG_SIZE - cmc->offset < size) {
+ goto overflow;
+ }
spice_buffer_append(cmc, message, size);
+ if (sizeof(VDAgentMessage) > cmc->offset) {
+ spice_debug("not enough data yet. %zd", cmc->offset);
+ return;
+ }
msg_header = (VDAgentMessage *)cmc->buffer;
- if (sizeof(VDAgentMessage) > cmc->offset ||
- msg_header->size > cmc->offset - sizeof(VDAgentMessage)) {
+ if (msg_header->size > MAX_MONITOR_CONFIG_SIZE) {
+ goto overflow;
+ }
+ if (msg_header->size > cmc->offset - sizeof(VDAgentMessage)) {
spice_debug("not enough data yet. %zd", cmc->offset);
return;
}
@@ -1120,6 +1135,12 @@ static void reds_on_main_agent_monitors_config(RedsState *reds,
spice_debug("monitors_config->num_of_monitors: %d", monitors_config->num_of_monitors);
reds_client_monitors_config(reds, monitors_config);
spice_buffer_free(cmc);
+ return;
+
+overflow:
+ spice_warning("received invalid MonitorsConfig request from client, disconnecting");
+ red_channel_client_disconnect(RED_CHANNEL_CLIENT(mcc));
+ spice_buffer_free(cmc);
}
void reds_on_main_agent_data(RedsState *reds, MainChannelClient *mcc, const void *message,