[PATCH v2 8/8] migration: Harden vmstate_size

Fabiano Rosas <[email protected]>
Newsgroups gmane.comp.emulators.qemu
Message-ID <[email protected]>
Protect vmstate_size against overflow of the on-stack 64bit integer
during multiplication. The data at size_indirect.offset comes from the
migration stream.

Signed-off-by: Fabiano Rosas <[email protected]>
---
 migration/vmstate.c | 28 ++++++++++++++++++++++------
 1 file changed, 22 insertions(+), 6 deletions(-)

diff --git a/migration/vmstate.c b/migration/vmstate.c
index 1d028bfe009..08548ae7a1f 100644
--- a/migration/vmstate.c
+++ b/migration/vmstate.c
@@ -113,14 +113,20 @@ static uint64_t vmstate_n_elems(void *opaque, const VMStateField *field)
     return n_elems;
 }
 
-static uint64_t vmstate_size(void *opaque, const VMStateField *field)
+static bool vmstate_size(void *opaque, const VMStateField *field,
+                         uint64_t *sz, Error **errp)
 {
     uint64_t size;
 
+    *sz = 0;
+
     if (field->flags & VMS_VBUFFER) {
         size = vmstate_read_from_offset(&field->size_indirect, opaque);
-        if (field->flags & VMS_MULTIPLY) {
-            size *= field->size;
+        if ((field->flags & VMS_MULTIPLY) &&
+            umul64_overflow(size, field->size, &size)) {
+            error_setg(errp, "%s: VMState field '%s' multiply overflow",
+                       __func__, field->name);
+            return false;
         }
     } else if (field->flags & VMS_ARRAY_OF_POINTER) {
         /*
@@ -132,7 +138,8 @@ static uint64_t vmstate_size(void *opaque, const VMStateField *field)
         size = field->size;
     }
 
-    return size;
+    *sz = size;
+    return true;
 }
 
 static bool vmstate_handle_alloc(void *ptr, const VMStateField *field,
@@ -364,7 +371,11 @@ bool vmstate_load_vmsd(QEMUFile *f, const VMStateDescription *vmsd,
             void *first_elem = opaque + field->offset;
             int i;
             uint64_t n_elems = vmstate_n_elems(opaque, field);
-            uint64_t size = vmstate_size(opaque, field);
+            uint64_t size;
+
+            if (!vmstate_size(opaque, field, &size, errp)) {
+                return false;
+            }
 
             if (!vmstate_handle_alloc(first_elem, field, n_elems, size, errp)) {
                 return false;
@@ -682,9 +693,10 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd,
             void *first_elem = opaque + field->offset;
             int i;
             uint64_t n_elems = vmstate_n_elems(opaque, field);
-            uint64_t size = vmstate_size(opaque, field);
+            uint64_t size;
             JSONWriter *vmdesc_loop = vmdesc;
             bool is_prev_null = false;
+
             /*
              * When this is enabled, it means we will always push a ptr
              * marker first for each element saying if it's populated.
@@ -692,6 +704,10 @@ static bool vmstate_save_vmsd_v(QEMUFile *f, const VMStateDescription *vmsd,
             bool use_dynamic_array =
                 field->flags & VMS_ARRAY_OF_POINTER_AUTO_ALLOC;
 
+            if (!vmstate_size(opaque, field, &size, errp)) {
+                return false;
+            }
+
             trace_vmstate_save_state_loop(vmsd->name, field->name, n_elems);
             if (field->flags & VMS_POINTER) {
                 first_elem = *(void **)first_elem;
-- 
2.53.0
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.