summaryrefslogtreecommitdiffstats
path: root/server/red_parse_qxl.c
diff options
context:
space:
mode:
Diffstat (limited to 'server/red_parse_qxl.c')
-rw-r--r--server/red_parse_qxl.c43
1 files changed, 37 insertions, 6 deletions
diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c
index de5501b5..6fb439e5 100644
--- a/server/red_parse_qxl.c
+++ b/server/red_parse_qxl.c
@@ -153,8 +153,10 @@ static SpicePath *red_get_path(RedMemSlotInfo *slots, int group_id,
bool free_data;
QXLPath *qxl;
SpicePath *red;
- size_t size;
+ size_t size, mem_size, mem_size2, dsize;
+ int n_segments;
int i;
+ uint32_t count;
qxl = (QXLPath *)get_virt(slots, addr, sizeof(*qxl), group_id);
size = red_get_data_chunks_ptr(slots, group_id,
@@ -163,17 +165,44 @@ static SpicePath *red_get_path(RedMemSlotInfo *slots, int group_id,
data = red_linearize_chunk(&chunks, size, &free_data);
red_put_data_chunks(&chunks);
- ASSERT(qxl->data_size == size);
- ASSERT(sizeof(QXLPathSeg) == sizeof(SpicePathSeg)); /* FIXME */
- red = spice_malloc(sizeof(*red) + size);
- red->size = qxl->data_size;
+ n_segments = 0;
+ mem_size = sizeof(*red);
+
+ start = (QXLPathSeg*)data;
+ end = (QXLPathSeg*)(data + size);
+ while (start < end) {
+ n_segments++;
+ count = start->count;
+ mem_size += sizeof(SpicePathSeg) + count * sizeof(SpicePointFix);
+ start = (QXLPathSeg*)(&start->points[count]);
+ }
+
+ red = spice_malloc(mem_size);
+ red->num_segments = n_segments;
start = (QXLPathSeg*)data;
end = (QXLPathSeg*)(data + size);
seg = red->segments;
+ n_segments = 0;
+ mem_size2 = sizeof(*red);
while (start < end) {
+ n_segments++;
+ count = start->count;
+
+ /* Protect against overflow in size calculations before
+ writing to memory */
+ ASSERT(mem_size2 + sizeof(SpicePathSeg) > mem_size2);
+ mem_size2 += sizeof(SpicePathSeg);
+ ASSERT(count < UINT32_MAX / sizeof(SpicePointFix));
+ dsize = count * sizeof(SpicePointFix);
+ ASSERT(mem_size2 + dsize > mem_size2);
+ mem_size2 += dsize;
+
+ /* Verify that we didn't overflow due to guest changing data */
+ ASSERT(mem_size2 <= mem_size);
+
seg->flags = start->flags;
- seg->count = start->count;
+ seg->count = count;
for (i = 0; i < seg->count; i++) {
seg->points[i].x = start->points[i].x;
seg->points[i].y = start->points[i].y;
@@ -181,6 +210,8 @@ static SpicePath *red_get_path(RedMemSlotInfo *slots, int group_id,
start = (QXLPathSeg*)(&start->points[i]);
seg = (SpicePathSeg*)(&seg->points[i]);
}
+ /* Ensure guest didn't tamper with segment count */
+ ASSERT(n_segments == red->num_segments);
if (free_data) {
free(data);