summaryrefslogtreecommitdiffstats
path: root/server
diff options
context:
space:
mode:
authorFrediano Ziglio <fziglio@redhat.com>2015-09-08 12:12:19 +0100
committerFrediano Ziglio <fziglio@redhat.com>2015-10-06 11:11:11 +0100
commit3738478ed7065fe05f3ee4848f8a7fcdf40aa920 (patch)
tree80671229df4d94277f72829fb8d120d0ff206bab /server
parentcaec52dc77af6ebdac3219a1b10fe2293af21208 (diff)
downloadspice-3738478ed7065fe05f3ee4848f8a7fcdf40aa920.tar.gz
spice-3738478ed7065fe05f3ee4848f8a7fcdf40aa920.tar.xz
spice-3738478ed7065fe05f3ee4848f8a7fcdf40aa920.zip
Fix race condition in red_get_data_chunks_ptr
Do not read multiple times data from guest as this can be changed by other guest vcpus. This causes races and security problems if these data are used for buffer allocation or checks. Actually, the 'data' member can't change during read as it is just a pointer to a fixed array contained in qxl. However, this change will make it clear that there can be no race condition. Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
Diffstat (limited to 'server')
-rw-r--r--server/red_parse_qxl.c17
1 files changed, 10 insertions, 7 deletions
diff --git a/server/red_parse_qxl.c b/server/red_parse_qxl.c
index cfa21f95..2863ae26 100644
--- a/server/red_parse_qxl.c
+++ b/server/red_parse_qxl.c
@@ -102,30 +102,33 @@ static size_t red_get_data_chunks_ptr(RedMemSlotInfo *slots, int group_id,
RedDataChunk *red_prev;
size_t data_size = 0;
int error;
+ QXLPHYSICAL next_chunk;
red->data_size = qxl->data_size;
data_size += red->data_size;
- if (!validate_virt(slots, (intptr_t)qxl->data, memslot_id, red->data_size, group_id)) {
+ red->data = qxl->data;
+ if (!validate_virt(slots, (intptr_t)red->data, memslot_id, red->data_size, group_id)) {
+ red->data = NULL;
return 0;
}
- red->data = qxl->data;
red->prev_chunk = NULL;
- while (qxl->next_chunk) {
+ while ((next_chunk = qxl->next_chunk) != 0) {
red_prev = red;
red = spice_new(RedDataChunk, 1);
- memslot_id = get_memslot_id(slots, qxl->next_chunk);
- qxl = (QXLDataChunk *)get_virt(slots, qxl->next_chunk, sizeof(*qxl), group_id,
+ memslot_id = get_memslot_id(slots, next_chunk);
+ qxl = (QXLDataChunk *)get_virt(slots, next_chunk, sizeof(*qxl), group_id,
&error);
if (error) {
return 0;
}
red->data_size = qxl->data_size;
data_size += red->data_size;
- if (!validate_virt(slots, (intptr_t)qxl->data, memslot_id, red->data_size, group_id)) {
+ red->data = qxl->data;
+ if (!validate_virt(slots, (intptr_t)red->data, memslot_id, red->data_size, group_id)) {
+ red->data = NULL;
return 0;
}
- red->data = qxl->data;
red->prev_chunk = red_prev;
red_prev->next_chunk = red;
}