aboutsummaryrefslogtreecommitdiffstats
path: root/main/spice/CVE-2017-7506.patch
blob: 0a6e1563665d13ae4800b0f22b75681489eb8f50 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
Matthias Maier <tamiko@gentoo.org>

 - Ported to 0.13.3


From 111ab38611cef5012f1565a65fa2d8a8a05cce37 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Mon, 15 May 2017 15:57:28 +0100
Subject: [PATCH 1/3] 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>
---

diff --git a/server/reds.c b/server/reds.c
index 92feea1..286993b 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1077,19 +1077,35 @@ static void reds_client_monitors_config_cleanup(RedsState *reds)
 static void reds_on_main_agent_monitors_config(RedsState *reds,
         MainChannelClient *mcc, 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;
     RedsClientMonitorsConfig *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->buffer_size < size) {
+        goto overflow;
+    }
+
     cmc->buffer_size += size;
     cmc->buffer = realloc(cmc->buffer, cmc->buffer_size);
     spice_assert(cmc->buffer);
     cmc->mcc = mcc;
     memcpy(cmc->buffer + cmc->buffer_pos, message, size);
     cmc->buffer_pos += size;
+    if (sizeof(VDAgentMessage) > cmc->buffer_size) {
+        spice_debug("not enough data yet. %d", cmc->buffer_size);
+        return;
+    }
     msg_header = (VDAgentMessage *)cmc->buffer;
-    if (sizeof(VDAgentMessage) > cmc->buffer_size ||
-            msg_header->size > cmc->buffer_size - sizeof(VDAgentMessage)) {
+    if (msg_header->size > MAX_MONITOR_CONFIG_SIZE) {
+        goto overflow;
+    }
+    if (msg_header->size > cmc->buffer_size - sizeof(VDAgentMessage)) {
         spice_debug("not enough data yet. %d", cmc->buffer_size);
         return;
     }
@@ -1097,6 +1113,12 @@ static void reds_on_main_agent_monitors_config(RedsState *reds,
     spice_debug("%s: %d", __func__, monitors_config->num_of_monitors);
     reds_client_monitors_config(reds, monitors_config);
     reds_client_monitors_config_cleanup(reds);
+    return;
+
+overflow:
+    spice_warning("received invalid MonitorsConfig request from client, disconnecting");
+    red_channel_client_disconnect(RED_CHANNEL_CLIENT(mcc));
+    reds_client_monitors_config_cleanup(reds);
 }
 
 void reds_on_main_agent_data(RedsState *reds, MainChannelClient *mcc, void *message, size_t size)

From 571cec91e71c2aae0d5f439ea2d8439d0c3d75eb Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Mon, 15 May 2017 15:57:28 +0100
Subject: [PATCH 2/3] reds: Avoid integer overflows handling monitor
 configuration

Avoid VDAgentMessage::size integer overflows.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
---
 server/reds.c | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/server/reds.c b/server/reds.c
index ec2b6f47..656f518f 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1131,6 +1131,9 @@ static void reds_on_main_agent_monitors_config(RedsState *reds,
         spice_debug("not enough data yet. %zd", cmc->offset);
         return;
     }
+    if (msg_header->size < sizeof(VDAgentMonitorsConfig)) {
+        goto overflow;
+    }
     monitors_config = (VDAgentMonitorsConfig *)(cmc->buffer + sizeof(*msg_header));
     spice_debug("monitors_config->num_of_monitors: %d", monitors_config->num_of_monitors);
     reds_client_monitors_config(reds, monitors_config);
-- 
2.13.0

Matthias Maier <tamiko@gentoo.org>

 - Ported to 0.13.3


From fbbcdad773e2791cfb988f4748faa41943551ca6 Mon Sep 17 00:00:00 2001
From: Frediano Ziglio <fziglio@redhat.com>
Date: Mon, 15 May 2017 15:57:28 +0100
Subject: [PATCH 3/3] reds: Avoid buffer overflows handling monitor
 configuration

It was also possible for a malicious client to set
VDAgentMonitorsConfig::num_of_monitors to a number larger
than the actual size of VDAgentMOnitorsConfig::monitors.
This would lead to buffer overflows, which could allow the guest to
read part of the host memory. This might cause write overflows in the
host as well, but controlling the content of such buffers seems
complicated.

Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
---

diff --git a/server/reds.c b/server/reds.c
index ec89105..fd1457f 100644
--- a/server/reds.c
+++ b/server/reds.c
@@ -1084,6 +1084,7 @@ static void reds_on_main_agent_monitors_config(RedsState *reds,
     VDAgentMessage *msg_header;
     VDAgentMonitorsConfig *monitors_config;
     RedsClientMonitorsConfig *cmc = &reds->client_monitors_config;
+    uint32_t max_monitors;
 
     // limit size of message sent by the client as this can cause a DoS through
     // memory exhaustion, or potentially some integer overflows
@@ -1113,6 +1114,12 @@ static void reds_on_main_agent_monitors_config(RedsState *reds,
         goto overflow;
     }
     monitors_config = (VDAgentMonitorsConfig *)(cmc->buffer + sizeof(*msg_header));
+    // limit the monitor number to avoid buffer overflows
+    max_monitors = (msg_header->size - sizeof(VDAgentMonitorsConfig)) /
+                   sizeof(VDAgentMonConfig);
+    if (monitors_config->num_of_monitors > max_monitors) {
+        goto overflow;
+    }
     spice_debug("%s: %d", __func__, monitors_config->num_of_monitors);
     reds_client_monitors_config(reds, monitors_config);
     reds_client_monitors_config_cleanup(reds);
M