hvm_save_one: return correct data
authorDon Slutz <dslutz@verizon.com>
Wed, 8 Jan 2014 08:15:03 +0000 (09:15 +0100)
committerJan Beulich <jbeulich@suse.com>
Wed, 8 Jan 2014 08:15:03 +0000 (09:15 +0100)
It is possible that hvm_sr_handlers[typecode].save does not use all
the provided room.  Also it can use variable sized records.  In both
cases, using:

   instance * hvm_sr_handlers[typecode].size

does not select the correct instance.  Add code to search for the
correct instance.

Signed-off-by: Don Slutz <dslutz@verizon.com>
Release-acked-by: George Dunlap <george.dunlap@eu.citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Keir Fraser <keir@xen.org>
xen/common/hvm/save.c

index de76adac4f33ed8852abf586d73d748232ae81a5..6c163999648627d199ad070535b915aee6e6370e 100644 (file)
@@ -98,9 +98,6 @@ int hvm_save_one(struct domain *d, uint16_t typecode, uint16_t instance,
     else 
         sz = hvm_sr_handlers[typecode].size;
     
-    if ( (instance + 1) * hvm_sr_handlers[typecode].size > sz )
-        return -EINVAL;
-
     ctxt.size = sz;
     ctxt.data = xmalloc_bytes(sz);
     if ( !ctxt.data )
@@ -112,13 +109,30 @@ int hvm_save_one(struct domain *d, uint16_t typecode, uint16_t instance,
                d->domain_id, typecode);
         rv = -EFAULT;
     }
-    else if ( copy_to_guest(handle,
-                            ctxt.data 
-                            + (instance * hvm_sr_handlers[typecode].size) 
-                            + sizeof (struct hvm_save_descriptor), 
-                            hvm_sr_handlers[typecode].size
-                            - sizeof (struct hvm_save_descriptor)) )
-        rv = -EFAULT;
+    else
+    {
+        uint32_t off;
+        const struct hvm_save_descriptor *desc;
+
+        rv = -EBADSLT;
+        for ( off = 0; off < (ctxt.cur - sizeof(*desc)); off += desc->length )
+        {
+            desc = (void *)(ctxt.data + off);
+            /* Move past header */
+            off += sizeof(*desc);
+            if ( instance == desc->instance )
+            {
+                uint32_t copy_length = desc->length;
+
+                if ( off + copy_length > ctxt.cur )
+                    copy_length = ctxt.cur - off;
+                rv = 0;
+                if ( copy_to_guest(handle, ctxt.data + off, copy_length) )
+                    rv = -EFAULT;
+                break;
+            }
+        }
+    }
 
     xfree(ctxt.data);
     return rv;