summaryrefslogtreecommitdiffstats
path: root/server/red_memslots.c
diff options
context:
space:
mode:
authorAlon Levy <alevy@redhat.com>2012-04-04 20:40:59 +0300
committerAlon Levy <alevy@redhat.com>2012-04-05 18:28:49 +0300
commit2ec2dbc78a660ee4e3315f50c881d9e31a8e4fe2 (patch)
tree5b5bd52f9df547bcbbbdf9c492b54848b8aca23e /server/red_memslots.c
parent2439c0dc90bcfd83d3e0eb4f08f19ef2face2118 (diff)
downloadspice-2ec2dbc78a660ee4e3315f50c881d9e31a8e4fe2.tar.gz
spice-2ec2dbc78a660ee4e3315f50c881d9e31a8e4fe2.tar.xz
spice-2ec2dbc78a660ee4e3315f50c881d9e31a8e4fe2.zip
server: allow failure in getvirt
This patch changed getvirt to continue working even if spice_critical doesn't abort (i.e. SPICE_ABORT_LEVEL != -1). This is in preparation to make getvirt not abort at all. The reason is that getvirt is run on guest provided memory, so a bad driver can crash the vm.
Diffstat (limited to 'server/red_memslots.c')
-rw-r--r--server/red_memslots.c42
1 files changed, 34 insertions, 8 deletions
diff --git a/server/red_memslots.c b/server/red_memslots.c
index ae2c6e46..523890d6 100644
--- a/server/red_memslots.c
+++ b/server/red_memslots.c
@@ -73,14 +73,16 @@ unsigned long get_virt_delta(RedMemSlotInfo *info, QXLPHYSICAL addr, int group_i
return (slot->address_delta - (addr - __get_clean_virt(info, addr)));
}
-void validate_virt(RedMemSlotInfo *info, unsigned long virt, int slot_id,
- uint32_t add_size, uint32_t group_id)
+/* return 1 if validation successfull, 0 otherwise */
+int validate_virt(RedMemSlotInfo *info, unsigned long virt, int slot_id,
+ uint32_t add_size, uint32_t group_id)
{
MemSlot *slot;
slot = &info->mem_slots[group_id][slot_id];
if ((virt + add_size) < virt) {
spice_critical("virtual address overlap");
+ return 0;
}
if (virt < slot->virt_start_addr || (virt + add_size) > slot->virt_end_addr) {
@@ -90,11 +92,17 @@ void validate_virt(RedMemSlotInfo *info, unsigned long virt, int slot_id,
" slot=0x%lx-0x%lx delta=0x%lx",
virt, add_size, slot_id, group_id,
slot->virt_start_addr, slot->virt_end_addr, slot->address_delta);
+ return 0;
}
+ return 1;
}
+/*
+ * return virtual address if successful, which may be 0.
+ * returns 0 and sets error to 1 if an error condition occurs.
+ */
unsigned long get_virt(RedMemSlotInfo *info, QXLPHYSICAL addr, uint32_t add_size,
- int group_id)
+ int group_id, int *error)
{
int slot_id;
int generation;
@@ -102,14 +110,19 @@ unsigned long get_virt(RedMemSlotInfo *info, QXLPHYSICAL addr, uint32_t add_size
MemSlot *slot;
+ *error = 0;
if (group_id > info->num_memslots_groups) {
spice_critical("group_id too big");
+ *error = 1;
+ return 0;
}
slot_id = get_memslot_id(info, addr);
if (slot_id > info->num_memslots) {
print_memslots(info);
spice_critical("slot_id too big, addr=%" PRIx64, addr);
+ *error = 1;
+ return 0;
}
slot = &info->mem_slots[group_id][slot_id];
@@ -119,25 +132,38 @@ unsigned long get_virt(RedMemSlotInfo *info, QXLPHYSICAL addr, uint32_t add_size
print_memslots(info);
spice_critical("address generation is not valid, group_id %d, slot_id %d, gen %d, slot_gen %d\n",
group_id, slot_id, generation, slot->generation);
+ *error = 1;
+ return 0;
}
h_virt = __get_clean_virt(info, addr);
h_virt += slot->address_delta;
- validate_virt(info, h_virt, slot_id, add_size, group_id);
+ if (!validate_virt(info, h_virt, slot_id, add_size, group_id)) {
+ *error = 1;
+ return 0;
+ }
return h_virt;
}
-void *validate_chunk (RedMemSlotInfo *info, QXLPHYSICAL data, uint32_t group_id, uint32_t *data_size_out, QXLPHYSICAL *next_out)
+void *validate_chunk(RedMemSlotInfo *info, QXLPHYSICAL data, uint32_t group_id,
+ uint32_t *data_size_out, QXLPHYSICAL *next_out, int *error)
{
QXLDataChunk *chunk;
uint32_t data_size;
- chunk = (QXLDataChunk *)get_virt(info, data, sizeof(QXLDataChunk), group_id);
+ chunk = (QXLDataChunk *)get_virt(info, data, sizeof(QXLDataChunk), group_id,
+ error);
+ if (*error) {
+ return NULL;
+ }
data_size = chunk->data_size;
- validate_virt(info, (unsigned long)chunk->data, get_memslot_id(info, data),
- data_size, group_id);
+ if (!validate_virt(info, (unsigned long)chunk->data, get_memslot_id(info, data),
+ data_size, group_id)) {
+ *error = 1;
+ return NULL;
+ }
*next_out = chunk->next_chunk;
*data_size_out = data_size;