diff mbox

[v1,1/2] x86/vvmx: check vmcs address in vmread/vmwrite

Message ID 20170301091355.24742-2-sergey.dyasli@citrix.com (mailing list archive)
State New, archived
Headers show

Commit Message

Sergey Dyasli March 1, 2017, 9:13 a.m. UTC
If nested vmcs's address is invalid, virtual_vmcs_enter() will fail
during vmread/vmwrite:

(XEN) Xen BUG at .../git/upstream/xen/xen/include/asm/hvm/vmx/vmx.h:333
(XEN) ----[ Xen-4.9-unstable  x86_64  debug=y   Tainted:    H ]----
(XEN) Xen call trace:
(XEN)    [<ffff82d0801f925e>] vmcs.c#arch/x86/hvm/vmx/vmcs.o.unlikely+0x28/0x19a
(XEN)    [<ffff82d0801f60e3>] virtual_vmcs_vmwrite_safe+0x16/0x52
(XEN)    [<ffff82d080202cb2>] nvmx_handle_vmwrite+0x70/0xfe
(XEN)    [<ffff82d0801fe98a>] vmx_vmexit_handler+0x1379/0x1c49
(XEN)    [<ffff82d08020427c>] vmx_asm_vmexit_handler+0x3c/0x120

Fix this by emulating VMfailInvalid if the address is invalid.

Signed-off-by: Sergey Dyasli <sergey.dyasli@citrix.com>
---
 xen/arch/x86/hvm/vmx/vvmx.c | 12 ++++++++++++
 1 file changed, 12 insertions(+)

Comments

Andrew Cooper March 1, 2017, 10:58 a.m. UTC | #1
On 01/03/17 09:13, Sergey Dyasli wrote:
> If nested vmcs's address is invalid, virtual_vmcs_enter() will fail
> during vmread/vmwrite:
>
> (XEN) Xen BUG at .../git/upstream/xen/xen/include/asm/hvm/vmx/vmx.h:333
> (XEN) ----[ Xen-4.9-unstable  x86_64  debug=y   Tainted:    H ]----
> (XEN) Xen call trace:
> (XEN)    [<ffff82d0801f925e>] vmcs.c#arch/x86/hvm/vmx/vmcs.o.unlikely+0x28/0x19a
> (XEN)    [<ffff82d0801f60e3>] virtual_vmcs_vmwrite_safe+0x16/0x52
> (XEN)    [<ffff82d080202cb2>] nvmx_handle_vmwrite+0x70/0xfe
> (XEN)    [<ffff82d0801fe98a>] vmx_vmexit_handler+0x1379/0x1c49
> (XEN)    [<ffff82d08020427c>] vmx_asm_vmexit_handler+0x3c/0x120
>
> Fix this by emulating VMfailInvalid if the address is invalid.
>
> Signed-off-by: Sergey Dyasli <sergey.dyasli@citrix.com>

Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
Jan Beulich March 1, 2017, 12:55 p.m. UTC | #2
>>> On 01.03.17 at 10:13, <sergey.dyasli@citrix.com> wrote:
> If nested vmcs's address is invalid, virtual_vmcs_enter() will fail
> during vmread/vmwrite:
> 
> (XEN) Xen BUG at .../git/upstream/xen/xen/include/asm/hvm/vmx/vmx.h:333
> (XEN) ----[ Xen-4.9-unstable  x86_64  debug=y   Tainted:    H ]----
> (XEN) Xen call trace:
> (XEN)    [<ffff82d0801f925e>] vmcs.c#arch/x86/hvm/vmx/vmcs.o.unlikely+0x28/0x19a
> (XEN)    [<ffff82d0801f60e3>] virtual_vmcs_vmwrite_safe+0x16/0x52
> (XEN)    [<ffff82d080202cb2>] nvmx_handle_vmwrite+0x70/0xfe
> (XEN)    [<ffff82d0801fe98a>] vmx_vmexit_handler+0x1379/0x1c49
> (XEN)    [<ffff82d08020427c>] vmx_asm_vmexit_handler+0x3c/0x120
> 
> Fix this by emulating VMfailInvalid if the address is invalid.

So just like in patch 2 this is __vmptrld() not properly dealing with
errors. Instead of doing checks in software which hardware does
anyway, wouldn't it be better to introduce (and use here and
there) vmptrld_safe()?

Jan
Andrew Cooper March 1, 2017, 1:22 p.m. UTC | #3
On 01/03/17 12:55, Jan Beulich wrote:
>>>> On 01.03.17 at 10:13, <sergey.dyasli@citrix.com> wrote:
>> If nested vmcs's address is invalid, virtual_vmcs_enter() will fail
>> during vmread/vmwrite:
>>
>> (XEN) Xen BUG at .../git/upstream/xen/xen/include/asm/hvm/vmx/vmx.h:333
>> (XEN) ----[ Xen-4.9-unstable  x86_64  debug=y   Tainted:    H ]----
>> (XEN) Xen call trace:
>> (XEN)    [<ffff82d0801f925e>] vmcs.c#arch/x86/hvm/vmx/vmcs.o.unlikely+0x28/0x19a
>> (XEN)    [<ffff82d0801f60e3>] virtual_vmcs_vmwrite_safe+0x16/0x52
>> (XEN)    [<ffff82d080202cb2>] nvmx_handle_vmwrite+0x70/0xfe
>> (XEN)    [<ffff82d0801fe98a>] vmx_vmexit_handler+0x1379/0x1c49
>> (XEN)    [<ffff82d08020427c>] vmx_asm_vmexit_handler+0x3c/0x120
>>
>> Fix this by emulating VMfailInvalid if the address is invalid.
> So just like in patch 2 this is __vmptrld() not properly dealing with
> errors. Instead of doing checks in software which hardware does
> anyway, wouldn't it be better to introduce (and use here and
> there) vmptrld_safe()?

Lonterm, I'd like to see us move to a model where the base version is
safe, and error handling is along the lines of:

if ( on_behalf_of_nested )
    propagate_to_guest();
else
{
    dump_relevent_info();
    domain_crash(current->domain);
}


This is far more useful for error isolation (not taking the host down
even if it is Xen's fault the failure occured), and diagnosing what
actually went wrong, than simply having hit a BUG().

~Andrew
Jan Beulich March 1, 2017, 1:40 p.m. UTC | #4
>>> On 01.03.17 at 14:22, <andrew.cooper3@citrix.com> wrote:
> On 01/03/17 12:55, Jan Beulich wrote:
>>>>> On 01.03.17 at 10:13, <sergey.dyasli@citrix.com> wrote:
>>> If nested vmcs's address is invalid, virtual_vmcs_enter() will fail
>>> during vmread/vmwrite:
>>>
>>> (XEN) Xen BUG at .../git/upstream/xen/xen/include/asm/hvm/vmx/vmx.h:333
>>> (XEN) ----[ Xen-4.9-unstable  x86_64  debug=y   Tainted:    H ]----
>>> (XEN) Xen call trace:
>>> (XEN)    [<ffff82d0801f925e>] 
> vmcs.c#arch/x86/hvm/vmx/vmcs.o.unlikely+0x28/0x19a
>>> (XEN)    [<ffff82d0801f60e3>] virtual_vmcs_vmwrite_safe+0x16/0x52
>>> (XEN)    [<ffff82d080202cb2>] nvmx_handle_vmwrite+0x70/0xfe
>>> (XEN)    [<ffff82d0801fe98a>] vmx_vmexit_handler+0x1379/0x1c49
>>> (XEN)    [<ffff82d08020427c>] vmx_asm_vmexit_handler+0x3c/0x120
>>>
>>> Fix this by emulating VMfailInvalid if the address is invalid.
>> So just like in patch 2 this is __vmptrld() not properly dealing with
>> errors. Instead of doing checks in software which hardware does
>> anyway, wouldn't it be better to introduce (and use here and
>> there) vmptrld_safe()?
> 
> Lonterm, I'd like to see us move to a model where the base version is
> safe, and error handling is along the lines of:
> 
> if ( on_behalf_of_nested )
>     propagate_to_guest();
> else
> {
>     dump_relevent_info();
>     domain_crash(current->domain);
> }
> 
> 
> This is far more useful for error isolation (not taking the host down
> even if it is Xen's fault the failure occured), and diagnosing what
> actually went wrong, than simply having hit a BUG().

I completely agree, but I don't think you or I mean to ask Sergey to
do the full conversion right away. I.e. I think your reply is somewhat
orthogonal to (or is going way beyond) my request.

Jan
Sergey Dyasli March 1, 2017, 1:44 p.m. UTC | #5
On Wed, 2017-03-01 at 05:55 -0700, Jan Beulich wrote:
> > > > On 01.03.17 at 10:13, <sergey.dyasli@citrix.com> wrote:

> > 

> > If nested vmcs's address is invalid, virtual_vmcs_enter() will fail

> > during vmread/vmwrite:

> > 

> > (XEN) Xen BUG at .../git/upstream/xen/xen/include/asm/hvm/vmx/vmx.h:333

> > (XEN) ----[ Xen-4.9-unstable  x86_64  debug=y   Tainted:    H ]----

> > (XEN) Xen call trace:

> > (XEN)    [<ffff82d0801f925e>] vmcs.c#arch/x86/hvm/vmx/vmcs.o.unlikely+0x28/0x19a

> > (XEN)    [<ffff82d0801f60e3>] virtual_vmcs_vmwrite_safe+0x16/0x52

> > (XEN)    [<ffff82d080202cb2>] nvmx_handle_vmwrite+0x70/0xfe

> > (XEN)    [<ffff82d0801fe98a>] vmx_vmexit_handler+0x1379/0x1c49

> > (XEN)    [<ffff82d08020427c>] vmx_asm_vmexit_handler+0x3c/0x120

> > 

> > Fix this by emulating VMfailInvalid if the address is invalid.

> 

> So just like in patch 2 this is __vmptrld() not properly dealing with

> errors. Instead of doing checks in software which hardware does

> anyway, wouldn't it be better to introduce (and use here and

> there) vmptrld_safe()?


Currently it's assumed that virtual_vmcs_enter/exit() never fail.
It's easy to maintain that assumption with one simple check:

    nv_vvmcxaddr != INVALID_PADDR

as long as nvmx_handle_vmptrld() correctly checks the validity of
provided pointer.

Additionally, it would be painful to return the correct error value
all the way back to nvmx_handle_vmptrld().

-- 
Thanks,
Sergey
Jan Beulich March 1, 2017, 2:04 p.m. UTC | #6
>>> On 01.03.17 at 14:44, <sergey.dyasli@citrix.com> wrote:
> On Wed, 2017-03-01 at 05:55 -0700, Jan Beulich wrote:
>> > > > On 01.03.17 at 10:13, <sergey.dyasli@citrix.com> wrote:
>> > 
>> > If nested vmcs's address is invalid, virtual_vmcs_enter() will fail
>> > during vmread/vmwrite:
>> > 
>> > (XEN) Xen BUG at .../git/upstream/xen/xen/include/asm/hvm/vmx/vmx.h:333
>> > (XEN) ----[ Xen-4.9-unstable  x86_64  debug=y   Tainted:    H ]----
>> > (XEN) Xen call trace:
>> > (XEN)    [<ffff82d0801f925e>] vmcs.c#arch/x86/hvm/vmx/vmcs.o.unlikely+0x28/0x19a
>> > (XEN)    [<ffff82d0801f60e3>] virtual_vmcs_vmwrite_safe+0x16/0x52
>> > (XEN)    [<ffff82d080202cb2>] nvmx_handle_vmwrite+0x70/0xfe
>> > (XEN)    [<ffff82d0801fe98a>] vmx_vmexit_handler+0x1379/0x1c49
>> > (XEN)    [<ffff82d08020427c>] vmx_asm_vmexit_handler+0x3c/0x120
>> > 
>> > Fix this by emulating VMfailInvalid if the address is invalid.
>> 
>> So just like in patch 2 this is __vmptrld() not properly dealing with
>> errors. Instead of doing checks in software which hardware does
>> anyway, wouldn't it be better to introduce (and use here and
>> there) vmptrld_safe()?
> 
> Currently it's assumed that virtual_vmcs_enter/exit() never fail.
> It's easy to maintain that assumption with one simple check:
> 
>     nv_vvmcxaddr != INVALID_PADDR
> 
> as long as nvmx_handle_vmptrld() correctly checks the validity of
> provided pointer.

Yet even more safe would be to avoid the check here and simply
properly check and convey the instruction results.

> Additionally, it would be painful to return the correct error value
> all the way back to nvmx_handle_vmptrld().

Surely that's at best relevant in the other patch. Here you're in
virtual_vmcs_vmwrite_safe(), which already knows how to
communicate back an error indicator.

Jan
Sergey Dyasli March 1, 2017, 2:22 p.m. UTC | #7
On Wed, 2017-03-01 at 07:04 -0700, Jan Beulich wrote:
> > > > On 01.03.17 at 14:44, <sergey.dyasli@citrix.com> wrote:

> > 

> > On Wed, 2017-03-01 at 05:55 -0700, Jan Beulich wrote:

> > > > > > On 01.03.17 at 10:13, <sergey.dyasli@citrix.com> wrote:

> > > > 

> > > > If nested vmcs's address is invalid, virtual_vmcs_enter() will fail

> > > > during vmread/vmwrite:

> > > > 

> > > > (XEN) Xen BUG at .../git/upstream/xen/xen/include/asm/hvm/vmx/vmx.h:333

> > > > (XEN) ----[ Xen-4.9-unstable  x86_64  debug=y   Tainted:    H ]----

> > > > (XEN) Xen call trace:

> > > > (XEN)    [<ffff82d0801f925e>] vmcs.c#arch/x86/hvm/vmx/vmcs.o.unlikely+0x28/0x19a

> > > > (XEN)    [<ffff82d0801f60e3>] virtual_vmcs_vmwrite_safe+0x16/0x52

> > > > (XEN)    [<ffff82d080202cb2>] nvmx_handle_vmwrite+0x70/0xfe

> > > > (XEN)    [<ffff82d0801fe98a>] vmx_vmexit_handler+0x1379/0x1c49

> > > > (XEN)    [<ffff82d08020427c>] vmx_asm_vmexit_handler+0x3c/0x120

> > > > 

> > > > Fix this by emulating VMfailInvalid if the address is invalid.

> > > 

> > > So just like in patch 2 this is __vmptrld() not properly dealing with

> > > errors. Instead of doing checks in software which hardware does

> > > anyway, wouldn't it be better to introduce (and use here and

> > > there) vmptrld_safe()?

> > 

> > Currently it's assumed that virtual_vmcs_enter/exit() never fail.

> > It's easy to maintain that assumption with one simple check:

> > 

> >     nv_vvmcxaddr != INVALID_PADDR

> > 

> > as long as nvmx_handle_vmptrld() correctly checks the validity of

> > provided pointer.

> 

> Yet even more safe would be to avoid the check here and simply

> properly check and convey the instruction results.


In the future it should be possible to limit (level) the set of VMX
features provided to the guest.  One example would be VMCS shadowing.
In such cases checks mustn't be done by H/W since it can be different.

> > Additionally, it would be painful to return the correct error value

> > all the way back to nvmx_handle_vmptrld().

> 

> Surely that's at best relevant in the other patch. Here you're in

> virtual_vmcs_vmwrite_safe(), which already knows how to

> communicate back an error indicator.


How checking the return value of virtual_vmcs_enter() is different
from checking nv_vvmcxaddr?

-- 
Thanks,
Sergey
Jan Beulich March 1, 2017, 2:28 p.m. UTC | #8
>>> On 01.03.17 at 15:22, <sergey.dyasli@citrix.com> wrote:
> On Wed, 2017-03-01 at 07:04 -0700, Jan Beulich wrote:
>> > > > On 01.03.17 at 14:44, <sergey.dyasli@citrix.com> wrote:
>> > Additionally, it would be painful to return the correct error value
>> > all the way back to nvmx_handle_vmptrld().
>> 
>> Surely that's at best relevant in the other patch. Here you're in
>> virtual_vmcs_vmwrite_safe(), which already knows how to
>> communicate back an error indicator.
> 
> How checking the return value of virtual_vmcs_enter() is different
> from checking nv_vvmcxaddr?

Checking the address is just one step. As the other patch shows,
checking the ID is necessary too. Over time more such checks may
be found necessary. Checking what hardware hands us is a single
check, and is always going to be sufficient no matter what new
features get added to hardware.

Jan
Sergey Dyasli March 1, 2017, 3:23 p.m. UTC | #9
On Wed, 2017-03-01 at 07:28 -0700, Jan Beulich wrote:
> > > > On 01.03.17 at 15:22, <sergey.dyasli@citrix.com> wrote:

> > 

> > On Wed, 2017-03-01 at 07:04 -0700, Jan Beulich wrote:

> > > > > > On 01.03.17 at 14:44, <sergey.dyasli@citrix.com> wrote:

> > > > 

> > > > Additionally, it would be painful to return the correct error value

> > > > all the way back to nvmx_handle_vmptrld().

> > > 

> > > Surely that's at best relevant in the other patch. Here you're in

> > > virtual_vmcs_vmwrite_safe(), which already knows how to

> > > communicate back an error indicator.

> > 

> > How checking the return value of virtual_vmcs_enter() is different

> > from checking nv_vvmcxaddr?

> 

> Checking the address is just one step. As the other patch shows,

> checking the ID is necessary too. Over time more such checks may

> be found necessary. Checking what hardware hands us is a single

> check, and is always going to be sufficient no matter what new

> features get added to hardware.


Conceptually, the result of __vmptrld() is irrelevant to a guest
during nested vmread/vmwrite emulation.  The fact that Xen is doing
__vmptrld() is a side effect of nested VMX.

All necessary checks may be found in Intel SDM.  And it states that
there can be only 1 VMfail if VMCS pointer is not valid: VMfailInvalid.
vmptrld can end up in 3 different VMfails and returning them to the
guest as a result of vmread/vmwrite emulation is wrong.

(Even though each of them will end up being VMfailInvalid in current
implementation)

I think that Xen's goal in nested VMX is emulating H/W as close as
possible.

-- 
Thanks,
Sergey
Jan Beulich March 1, 2017, 3:39 p.m. UTC | #10
>>> On 01.03.17 at 16:23, <sergey.dyasli@citrix.com> wrote:
> On Wed, 2017-03-01 at 07:28 -0700, Jan Beulich wrote:
>> > > > On 01.03.17 at 15:22, <sergey.dyasli@citrix.com> wrote:
>> > 
>> > On Wed, 2017-03-01 at 07:04 -0700, Jan Beulich wrote:
>> > > > > > On 01.03.17 at 14:44, <sergey.dyasli@citrix.com> wrote:
>> > > > 
>> > > > Additionally, it would be painful to return the correct error value
>> > > > all the way back to nvmx_handle_vmptrld().
>> > > 
>> > > Surely that's at best relevant in the other patch. Here you're in
>> > > virtual_vmcs_vmwrite_safe(), which already knows how to
>> > > communicate back an error indicator.
>> > 
>> > How checking the return value of virtual_vmcs_enter() is different
>> > from checking nv_vvmcxaddr?
>> 
>> Checking the address is just one step. As the other patch shows,
>> checking the ID is necessary too. Over time more such checks may
>> be found necessary. Checking what hardware hands us is a single
>> check, and is always going to be sufficient no matter what new
>> features get added to hardware.
> 
> Conceptually, the result of __vmptrld() is irrelevant to a guest
> during nested vmread/vmwrite emulation.  The fact that Xen is doing
> __vmptrld() is a side effect of nested VMX.

True.

> All necessary checks may be found in Intel SDM.

All _currently_ necessary checks. It is precisely possible new ones
getting added which I'd like to see covered by other than adding
further checks to our software when hardware already does them.

>  And it states that
> there can be only 1 VMfail if VMCS pointer is not valid: VMfailInvalid.
> vmptrld can end up in 3 different VMfails and returning them to the
> guest as a result of vmread/vmwrite emulation is wrong.

As is crashing Xen because of such.

The implication of course would be that the insn-error may need
adjustment in such a case.

> (Even though each of them will end up being VMfailInvalid in current
> implementation)
> 
> I think that Xen's goal in nested VMX is emulating H/W as close as
> possible.

Correct. Preferably by leveraging hardware instead of re-doing the
same thing in software.

Anyway - we'll see what the VMX maintainers think.

Jan
Tian, Kevin March 3, 2017, 8:21 a.m. UTC | #11
> From: Jan Beulich [mailto:JBeulich@suse.com]
> Sent: Wednesday, March 01, 2017 11:40 PM
> 
> >>> On 01.03.17 at 16:23, <sergey.dyasli@citrix.com> wrote:
> > On Wed, 2017-03-01 at 07:28 -0700, Jan Beulich wrote:
> >> > > > On 01.03.17 at 15:22, <sergey.dyasli@citrix.com> wrote:
> >> >
> >> > On Wed, 2017-03-01 at 07:04 -0700, Jan Beulich wrote:
> >> > > > > > On 01.03.17 at 14:44, <sergey.dyasli@citrix.com> wrote:
> >> > > >
> >> > > > Additionally, it would be painful to return the correct error value
> >> > > > all the way back to nvmx_handle_vmptrld().
> >> > >
> >> > > Surely that's at best relevant in the other patch. Here you're in
> >> > > virtual_vmcs_vmwrite_safe(), which already knows how to
> >> > > communicate back an error indicator.
> >> >
> >> > How checking the return value of virtual_vmcs_enter() is different
> >> > from checking nv_vvmcxaddr?
> >>
> >> Checking the address is just one step. As the other patch shows,
> >> checking the ID is necessary too. Over time more such checks may
> >> be found necessary. Checking what hardware hands us is a single
> >> check, and is always going to be sufficient no matter what new
> >> features get added to hardware.
> >
> > Conceptually, the result of __vmptrld() is irrelevant to a guest
> > during nested vmread/vmwrite emulation.  The fact that Xen is doing
> > __vmptrld() is a side effect of nested VMX.
> 
> True.
> 
> > All necessary checks may be found in Intel SDM.
> 
> All _currently_ necessary checks. It is precisely possible new ones
> getting added which I'd like to see covered by other than adding
> further checks to our software when hardware already does them.
> 
> >  And it states that
> > there can be only 1 VMfail if VMCS pointer is not valid: VMfailInvalid.
> > vmptrld can end up in 3 different VMfails and returning them to the
> > guest as a result of vmread/vmwrite emulation is wrong.
> 
> As is crashing Xen because of such.
> 
> The implication of course would be that the insn-error may need
> adjustment in such a case.
> 
> > (Even though each of them will end up being VMfailInvalid in current
> > implementation)
> >
> > I think that Xen's goal in nested VMX is emulating H/W as close as
> > possible.
> 
> Correct. Preferably by leveraging hardware instead of re-doing the
> same thing in software.
> 
> Anyway - we'll see what the VMX maintainers think.
> 

Although leveraging HW check is a generally good idea, I buy-in 
Sergey's comment that we may emulate different VMX feature set 
to guest in the future then in such case we'll need both SW/HW 
checks and then may still need to track latest SDM change.

So:

Acked-by: Kevin Tian <kevin.tian@intel.com>

Thanks
Kevin
diff mbox

Patch

diff --git a/xen/arch/x86/hvm/vmx/vvmx.c b/xen/arch/x86/hvm/vmx/vvmx.c
index f6a25a6..4f5ee5a 100644
--- a/xen/arch/x86/hvm/vmx/vvmx.c
+++ b/xen/arch/x86/hvm/vmx/vvmx.c
@@ -1751,6 +1751,12 @@  int nvmx_handle_vmread(struct cpu_user_regs *regs)
     if ( rc != X86EMUL_OKAY )
         return rc;
 
+    if ( vcpu_nestedhvm(v).nv_vvmcxaddr == INVALID_PADDR )
+    {
+        vmfail_invalid(regs);
+        return X86EMUL_OKAY;
+    }
+
     rc = get_vvmcs_safe(v, reg_read(regs, decode.reg2), &value);
     if ( rc != VMX_INSN_SUCCEED )
     {
@@ -1788,6 +1794,12 @@  int nvmx_handle_vmwrite(struct cpu_user_regs *regs)
              != X86EMUL_OKAY )
         return X86EMUL_EXCEPTION;
 
+    if ( vcpu_nestedhvm(v).nv_vvmcxaddr == INVALID_PADDR )
+    {
+        vmfail_invalid(regs);
+        return X86EMUL_OKAY;
+    }
+
     vmcs_encoding = reg_read(regs, decode.reg2);
     err = set_vvmcs_safe(v, vmcs_encoding, operand);
     if ( err != VMX_INSN_SUCCEED )