summary refs log tree commit diff stats
path: root/hw/misc/ivshmem.c
diff options
context:
space:
mode:
authorSebastian Krahmer <krahmer@suse.de>2014-09-15 18:40:07 +0200
committerPaolo Bonzini <pbonzini@redhat.com>2014-10-31 17:02:07 +0100
commit34bc07c5282a631c2663ae1ded0a186f46f64612 (patch)
treed1f353ba01de082bd983f54206f449ae7c657271 /hw/misc/ivshmem.c
parent363ba1c72fed4425e7917afc36722584aaeaad8a (diff)
downloadfocaccia-qemu-34bc07c5282a631c2663ae1ded0a186f46f64612.tar.gz
focaccia-qemu-34bc07c5282a631c2663ae1ded0a186f46f64612.zip
ivshmem: Fix potential OOB r/w access
Fix OOB access via malformed incoming_posn parameters
and check that requested memory is actually alloc'ed.

Signed-off-by: Sebastian Krahmer <krahmer@suse.de>
[AF: Rebased, cleanups, avoid fd leak]
Cc: qemu-stable@nongnu.org
Signed-off-by: Andreas Färber <afaerber@suse.de>
Reviewed-by: Michael S. Tsirkin <mst@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
Diffstat (limited to 'hw/misc/ivshmem.c')
-rw-r--r--hw/misc/ivshmem.c27
1 files changed, 23 insertions, 4 deletions
diff --git a/hw/misc/ivshmem.c b/hw/misc/ivshmem.c
index 24f74f6f58..ecef82a423 100644
--- a/hw/misc/ivshmem.c
+++ b/hw/misc/ivshmem.c
@@ -29,6 +29,7 @@
 
 #include <sys/mman.h>
 #include <sys/types.h>
+#include <limits.h>
 
 #define PCI_VENDOR_ID_IVSHMEM   PCI_VENDOR_ID_REDHAT_QUMRANET
 #define PCI_DEVICE_ID_IVSHMEM   0x1110
@@ -410,14 +411,24 @@ static void close_guest_eventfds(IVShmemState *s, int posn)
 
 /* this function increase the dynamic storage need to store data about other
  * guests */
-static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
+static int increase_dynamic_storage(IVShmemState *s, int new_min_size)
+{
 
     int j, old_nb_alloc;
 
+    /* check for integer overflow */
+    if (new_min_size >= INT_MAX / sizeof(Peer) - 1 || new_min_size <= 0) {
+        return -1;
+    }
+
     old_nb_alloc = s->nb_peers;
 
-    while (new_min_size >= s->nb_peers)
-        s->nb_peers = s->nb_peers * 2;
+    if (new_min_size >= s->nb_peers) {
+        /* +1 because #new_min_size is used as last array index */
+        s->nb_peers = new_min_size + 1;
+    } else {
+        return 0;
+    }
 
     IVSHMEM_DPRINTF("bumping storage to %d guests\n", s->nb_peers);
     s->peers = g_realloc(s->peers, s->nb_peers * sizeof(Peer));
@@ -427,6 +438,8 @@ static void increase_dynamic_storage(IVShmemState *s, int new_min_size) {
         s->peers[j].eventfds = NULL;
         s->peers[j].nb_eventfds = 0;
     }
+
+    return 0;
 }
 
 static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
@@ -469,7 +482,13 @@ static void ivshmem_read(void *opaque, const uint8_t *buf, int size)
 
     /* make sure we have enough space for this guest */
     if (incoming_posn >= s->nb_peers) {
-        increase_dynamic_storage(s, incoming_posn);
+        if (increase_dynamic_storage(s, incoming_posn) < 0) {
+            error_report("increase_dynamic_storage() failed");
+            if (tmp_fd != -1) {
+                close(tmp_fd);
+            }
+            return;
+        }
     }
 
     if (tmp_fd == -1) {