x86/domctl: two functional fixes to XEN_DOMCTL_[gs]etvcpuextstate

Interacting with the vcpu itself should be protected by vcpu_pause().
Buggy/naive toolstacks might encounter adverse interaction with a vcpu context
switch, or increase of xcr0_accum.  There are no much problems with current
in-tree code.

Explicitly permit a NULL guest handle as being a request for size.  It is the
prevailing Xen style, and without it, valgrind's ioctl handler is unable to
determine whether evc->buffer actually got written to.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>

x86/domctl: further fix to XEN_DOMCTL_[gs]etvcpuextstate

Do not clobber errors from certain codepaths.  Clobbering of -EINVAL from
failing "evc->size <= PV_XSAVE_SIZE(_xcr0_accum)" was a pre-existing bug.

However, clobbering -EINVAL/-EFAULT from the get codepath was a bug
unintentionally introduced by 090ca8c1 "x86/domctl: two functional fixes to
XEN_DOMCTL_[gs]etvcpuextstate".

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: 090ca8c155
master date: 2014-06-05 17:52:57 +0200
master commit: 895661ae98
master date: 2014-06-10 12:03:16 +0200
This commit is contained in:
Andrew Cooper authored and Jan Beulich committed 2014-06-24 09:51:19 +02:00
1 parent 29cdbd115d
commit 5cd10bbcf2
1 file changed
+29 -26
+29 -26
View File
@@ -1075,45 +1075,48 @@ long arch_do_domctl(
((v = d->vcpu[evc->vcpu]) == NULL) )
goto vcpuextstate_out;
ret = -EINVAL;
if ( v == current ) /* no vcpu_pause() */
goto vcpuextstate_out;
if ( domctl->cmd == XEN_DOMCTL_getvcpuextstate )
{
unsigned int size = PV_XSAVE_SIZE(v->arch.xcr0_accum);
unsigned int size;
if ( !evc->size && !evc->xfeature_mask )
ret = 0;
vcpu_pause(v);
size = PV_XSAVE_SIZE(v->arch.xcr0_accum);
if ( (!evc->size && !evc->xfeature_mask) ||
guest_handle_is_null(evc->buffer) )
{
evc->xfeature_mask = xfeature_mask;
evc->size = size;
ret = 0;
vcpu_unpause(v);
goto vcpuextstate_out;
}
if ( evc->size != size || evc->xfeature_mask != xfeature_mask )
{
ret = -EINVAL;
goto vcpuextstate_out;
}
if ( copy_to_guest_offset(domctl->u.vcpuextstate.buffer,
offset, (void *)&v->arch.xcr0,
sizeof(v->arch.xcr0)) )
{
if ( !ret && copy_to_guest_offset(evc->buffer, offset,
(void *)&v->arch.xcr0,
sizeof(v->arch.xcr0)) )
ret = -EFAULT;
goto vcpuextstate_out;
}
offset += sizeof(v->arch.xcr0);
if ( copy_to_guest_offset(domctl->u.vcpuextstate.buffer,
offset, (void *)&v->arch.xcr0_accum,
sizeof(v->arch.xcr0_accum)) )
{
if ( !ret && copy_to_guest_offset(evc->buffer, offset,
(void *)&v->arch.xcr0_accum,
sizeof(v->arch.xcr0_accum)) )
ret = -EFAULT;
goto vcpuextstate_out;
}
offset += sizeof(v->arch.xcr0_accum);
if ( copy_to_guest_offset(domctl->u.vcpuextstate.buffer,
offset, (void *)v->arch.xsave_area,
size - 2 * sizeof(uint64_t)) )
{
if ( !ret && copy_to_guest_offset(evc->buffer, offset,
(void *)v->arch.xsave_area,
size - 2 * sizeof(uint64_t)) )
ret = -EFAULT;
goto vcpuextstate_out;
}
vcpu_unpause(v);
}
else
{
@@ -1162,12 +1165,14 @@ long arch_do_domctl(
if ( evc->size <= PV_XSAVE_SIZE(_xcr0_accum) )
{
vcpu_pause(v);
v->arch.xcr0 = _xcr0;
v->arch.xcr0_accum = _xcr0_accum;
if ( _xcr0_accum & XSTATE_NONLAZY )
v->arch.nonlazy_xstate_used = 1;
memcpy(v->arch.xsave_area, _xsave_area,
evc->size - 2 * sizeof(uint64_t));
vcpu_unpause(v);
}
else
ret = -EINVAL;
@@ -1175,8 +1180,6 @@ long arch_do_domctl(
xfree(receive_buf);
}
ret = 0;
vcpuextstate_out:
if ( domctl->cmd == XEN_DOMCTL_getvcpuextstate )
copyback = 1;
Reference in new issue
Block a user
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.