HVM: sanitize DOMCTL_gethvmcontext_partial handling
authorJan Beulich <jbeulich@suse.com>
Wed, 14 Jun 2017 09:38:32 +0000 (11:38 +0200)
committerJan Beulich <jbeulich@suse.com>
Wed, 14 Jun 2017 09:38:32 +0000 (11:38 +0200)
Have the caller indicate its buffer size, provide a means to query the
needed size, don't ignore the upper halves of type code and instance,
and don't copy partial data.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: Wei Liu <wei.liu2@citrix.com>
Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
tools/libxc/xc_domain.c
xen/arch/x86/domctl.c
xen/common/hvm/save.c
xen/include/public/domctl.h
xen/include/xen/hvm/save.h

index b1a286ecf4ce0813ba58e9e652d87783826b5ef5..5d192ea0e49ebc0b61023eeee4fb9a8833bba72a 100644 (file)
@@ -496,6 +496,7 @@ int xc_domain_hvm_getcontext_partial(xc_interface *xch,
     domctl.domain = (domid_t) domid;
     domctl.u.hvmcontext_partial.type = typecode;
     domctl.u.hvmcontext_partial.instance = instance;
+    domctl.u.hvmcontext_partial.bufsz = size;
     set_xen_guest_handle(domctl.u.hvmcontext_partial.buffer, ctxt_buf);
 
     ret = do_domctl(xch, &domctl);
index e104be213dc50bec118a7ad8034074cc56d58cd4..f40e989fd8140fc79e966de022f5e166390a445b 100644 (file)
@@ -590,8 +590,12 @@ long arch_do_domctl(
         domain_pause(d);
         ret = hvm_save_one(d, domctl->u.hvmcontext_partial.type,
                            domctl->u.hvmcontext_partial.instance,
-                           domctl->u.hvmcontext_partial.buffer);
+                           domctl->u.hvmcontext_partial.buffer,
+                           &domctl->u.hvmcontext_partial.bufsz);
         domain_unpause(d);
+
+        if ( !ret )
+            copyback = true;
         break;
 
     case XEN_DOMCTL_set_address_size:
index 579b2d4ebdca0332679835fd3a6eefc4e8230e82..045e5a388aeb5484516a20adfa207b959986e78e 100644 (file)
@@ -76,8 +76,8 @@ size_t hvm_save_size(struct domain *d)
 
 /* Extract a single instance of a save record, by marshalling all
  * records of that type and copying out the one we need. */
-int hvm_save_one(struct domain *d, uint16_t typecode, uint16_t instance, 
-                 XEN_GUEST_HANDLE_64(uint8) handle)
+int hvm_save_one(struct domain *d, unsigned int typecode, unsigned int instance,
+                 XEN_GUEST_HANDLE_64(uint8) handle, uint64_t *bufsz)
 {
     int rv = -ENOENT;
     size_t sz = 0;
@@ -117,16 +117,20 @@ int hvm_save_one(struct domain *d, uint16_t typecode, uint16_t instance,
             desc = (void *)(ctxt.data + off);
             /* Move past header */
             off += sizeof(*desc);
+            if ( ctxt.cur < desc->length ||
+                 off > ctxt.cur - desc->length )
+                break;
             if ( instance == desc->instance )
             {
-                uint32_t copy_length = desc->length;
-
-                if ( ctxt.cur < copy_length ||
-                     off > ctxt.cur - copy_length )
-                    copy_length = ctxt.cur - off;
                 rv = 0;
-                if ( copy_to_guest(handle, ctxt.data + off, copy_length) )
+                if ( guest_handle_is_null(handle) )
+                    *bufsz = desc->length;
+                else if ( *bufsz < desc->length )
+                    rv = -ENOBUFS;
+                else if ( copy_to_guest(handle, ctxt.data + off, desc->length) )
                     rv = -EFAULT;
+                else
+                    *bufsz = desc->length;
                 break;
             }
         }
index 3f3b3ebaee1962248e2a0ebb4e165e509a84d4cc..f7cbc0afcd659434567e183cfd446a5617a823a4 100644 (file)
@@ -746,6 +746,7 @@ DEFINE_XEN_GUEST_HANDLE(xen_domctl_debug_op_t);
 typedef struct xen_domctl_hvmcontext_partial {
     uint32_t type;                      /* IN: Type of record required */
     uint32_t instance;                  /* IN: Instance of that type */
+    uint64_aligned_t bufsz;             /* IN: size of buffer */
     XEN_GUEST_HANDLE_64(uint8) buffer;  /* OUT: buffer to write record into */
 } xen_domctl_hvmcontext_partial_t;
 DEFINE_XEN_GUEST_HANDLE(xen_domctl_hvmcontext_partial_t);
index a9a78f91339d795d98d41e83c0eb0df18438ed55..f889e8fe1dda32e67f6a2e2be040eef420651165 100644 (file)
@@ -132,8 +132,8 @@ __initcall(__hvm_register_##_x##_save_and_restore);
 /* Entry points for saving and restoring HVM domain state */
 size_t hvm_save_size(struct domain *d);
 int hvm_save(struct domain *d, hvm_domain_context_t *h);
-int hvm_save_one(struct domain *d,  uint16_t typecode, uint16_t instance, 
-                 XEN_GUEST_HANDLE_64(uint8) handle);
+int hvm_save_one(struct domain *d, unsigned int typecode, unsigned int instance,
+                 XEN_GUEST_HANDLE_64(uint8) handle, uint64_t *bufsz);
 int hvm_load(struct domain *d, hvm_domain_context_t *h);
 
 /* Arch-specific definitions. */