linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [PATCH v2] KVM: VMX: Fix rflags cache during vCPU reset
@ 2017-11-20 22:52 Wanpeng Li
  2017-11-20 23:09 ` Paolo Bonzini
  0 siblings, 1 reply; 7+ messages in thread
From: Wanpeng Li @ 2017-11-20 22:52 UTC (permalink / raw)
  To: linux-kernel, kvm
  Cc: Paolo Bonzini, Radim Krčmář,
	Wanpeng Li, Nadav Amit, Dmitry Vyukov

From: Wanpeng Li <wanpeng.li@hotmail.com>

Reported by syzkaller:

   *** Guest State ***
   CR0: actual=0x0000000080010031, shadow=0x0000000060000010, gh_mask=fffffffffffffff7
   CR4: actual=0x0000000000002061, shadow=0x0000000000000000, gh_mask=ffffffffffffe8f1
   CR3 = 0x000000002081e000
   RSP = 0x000000000000fffa  RIP = 0x0000000000000000
   RFLAGS=0x00023000         DR7 = 0x00000000000000
          ^^^^^^^^^^         
   ------------[ cut here ]------------
   WARNING: CPU: 6 PID: 24431 at /home/kernel/linux/arch/x86/kvm//x86.c:7302 kvm_arch_vcpu_ioctl_run+0x651/0x2ea0 [kvm]
   CPU: 6 PID: 24431 Comm: reprotest Tainted: G        W  OE   4.14.0+ #26
   RIP: 0010:kvm_arch_vcpu_ioctl_run+0x651/0x2ea0 [kvm]
   RSP: 0018:ffff880291d179e0 EFLAGS: 00010202
   Call Trace:
    kvm_vcpu_ioctl+0x479/0x880 [kvm]
    do_vfs_ioctl+0x142/0x9a0
    SyS_ioctl+0x74/0x80
    entry_SYSCALL_64_fastpath+0x23/0x9a

The BUG is triggered while doing:

*(uint32_t*)0x20afd000 = (uint32_t)0xf0403;
*(uint32_t*)0x20afd004 = (uint32_t)0x0;
*(uint64_t*)0x20afd008 = (uint64_t)0x65;
*(uint64_t*)0x20afd010 = (uint64_t)0x5;
*(uint64_t*)0x20afd018 = (uint64_t)0xfffffffffffffffe;
*(uint64_t*)0x20afd020 = (uint64_t)0xfff;
*(uint64_t*)0x20afd038 = (uint64_t)0x2;
*(uint64_t*)0x20afd040 = (uint64_t)0x2;
r[15] = syscall(__NR_ioctl, r[4], 0x4048ae9bul, 0x20afd000ul);

i.e. KVM_SET_GUEST_DEBUG ioctl with

struct kvm_guest_debug {
    .control = 0xf0403,
    .pad = 0,
    .arch = {
        .debugreg[0] = 0x65,
        .debugreg[1] = 0x5,
        .debugreg[2] = 0xfffffffffffffffe,
        .debugreg[3] = 0xfff,
        .debugreg[6] = 0x2,
        .debugreg[7] = 0x2 
    }

The syzkaller testcase tries to setup the processor specific debug registers 
and configure vCPU for handling guest debug events through KVM_SET_GUEST_DEBUG.
The KVM_SET_GUEST_DEBUG ioctl will get and set rflags in order to set TF bit 
if single step is needed. All regs' caches are reset to avail and GUEST_RFLAGS 
vmcs field is reset to 0x2 during vCPU reset. However, the cache of rflags is 
not reset during vCPU reset. The function vmx_get_rflags() returns an unreset 
rflags cache value since the cache is marked avail, it is 0 after boot. Vmentry 
fails if the rflags reserved bit 1 is 0.

This patch fixes it by resetting both the GUEST_RFLAGS vmcs field and its cache 
to 0x2 during vCPU reset.

Reported-by: Dmitry Vyukov <dvyukov@google.com>
Tested-by: Dmitry Vyukov <dvyukov@google.com>
Reviewed-by: David Hildenbrand <david@redhat.com>
Cc: Paolo Bonzini <pbonzini@redhat.com>
Cc: Radim Krčmář <rkrcmar@redhat.com>
Cc: Nadav Amit <nadav.amit@gmail.com>
Cc: Dmitry Vyukov <dvyukov@google.com>
Signed-off-by: Wanpeng Li <wanpeng.li@hotmail.com>
---
 arch/x86/kvm/vmx.c | 1 +
 1 file changed, 1 insertion(+)

diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
index b348920..131fa1c 100644
--- a/arch/x86/kvm/vmx.c
+++ b/arch/x86/kvm/vmx.c
@@ -5590,6 +5590,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
 		vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
 	}
 
+	kvm_set_rflags(vcpu, 2);
 	vmcs_writel(GUEST_RFLAGS, 0x02);
 	kvm_rip_write(vcpu, 0xfff0);
 
-- 
2.7.4

^ permalink raw reply related	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] KVM: VMX: Fix rflags cache during vCPU reset
  2017-11-20 22:52 [PATCH v2] KVM: VMX: Fix rflags cache during vCPU reset Wanpeng Li
@ 2017-11-20 23:09 ` Paolo Bonzini
  2017-11-21  0:34   ` Wanpeng Li
  0 siblings, 1 reply; 7+ messages in thread
From: Paolo Bonzini @ 2017-11-20 23:09 UTC (permalink / raw)
  To: Wanpeng Li, linux-kernel, kvm
  Cc: Radim Krčmář, Wanpeng Li, Nadav Amit, Dmitry Vyukov

On 20/11/2017 23:52, Wanpeng Li wrote:
> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
> index b348920..131fa1c 100644
> --- a/arch/x86/kvm/vmx.c
> +++ b/arch/x86/kvm/vmx.c
> @@ -5590,6 +5590,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
>  		vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
>  	}
>  
> +	kvm_set_rflags(vcpu, 2);
>  	vmcs_writel(GUEST_RFLAGS, 0x02);

I think the vmcs_writel can go, kvm_set_rflags ends up calling
vmx_set_rflags.

>  	kvm_rip_write(vcpu, 0xfff0);
>  
> 

Beautified testcase:

    #include <unistd.h>
    #include <sys/syscall.h>
    #include <string.h>
    #include <stdint.h>
    #include <linux/kvm.h>
    #include <fcntl.h>
    #include <sys/ioctl.h>

    long r[5];
    int main()
    {
        struct kvm_debugregs dr = { 0 };

        r[2] = open("/dev/kvm", O_RDONLY);
        r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
        r[4] = ioctl(r[3], KVM_CREATE_VCPU, 7);
        struct kvm_guest_debug debug = {
                .control = 0xf0403,
                .arch = {
                        .debugreg[6] = 0x2,
                        .debugreg[7] = 0x2
                }
        };
        ioctl(r[4], KVM_SET_GUEST_DEBUG, &debug);
        ioctl(r[4], KVM_RUN, 0);
    }

No need to do anything, I'll handle this patch after -rc1.

Paolo

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] KVM: VMX: Fix rflags cache during vCPU reset
  2017-11-20 23:09 ` Paolo Bonzini
@ 2017-11-21  0:34   ` Wanpeng Li
  2017-12-05  0:28     ` Jim Mattson
  0 siblings, 1 reply; 7+ messages in thread
From: Wanpeng Li @ 2017-11-21  0:34 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: linux-kernel, kvm, Radim Krčmář,
	Wanpeng Li, Nadav Amit, Dmitry Vyukov

2017-11-21 7:09 GMT+08:00 Paolo Bonzini <pbonzini@redhat.com>:
> On 20/11/2017 23:52, Wanpeng Li wrote:
>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>> index b348920..131fa1c 100644
>> --- a/arch/x86/kvm/vmx.c
>> +++ b/arch/x86/kvm/vmx.c
>> @@ -5590,6 +5590,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
>>               vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
>>       }
>>
>> +     kvm_set_rflags(vcpu, 2);
>>       vmcs_writel(GUEST_RFLAGS, 0x02);
>
> I think the vmcs_writel can go, kvm_set_rflags ends up calling
> vmx_set_rflags.

Agreed.

>
>>       kvm_rip_write(vcpu, 0xfff0);
>>
>>
>
> Beautified testcase:
>
>     #include <unistd.h>
>     #include <sys/syscall.h>
>     #include <string.h>
>     #include <stdint.h>
>     #include <linux/kvm.h>
>     #include <fcntl.h>
>     #include <sys/ioctl.h>
>
>     long r[5];
>     int main()
>     {
>         struct kvm_debugregs dr = { 0 };
>
>         r[2] = open("/dev/kvm", O_RDONLY);
>         r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
>         r[4] = ioctl(r[3], KVM_CREATE_VCPU, 7);
>         struct kvm_guest_debug debug = {
>                 .control = 0xf0403,
>                 .arch = {
>                         .debugreg[6] = 0x2,
>                         .debugreg[7] = 0x2
>                 }
>         };
>         ioctl(r[4], KVM_SET_GUEST_DEBUG, &debug);
>         ioctl(r[4], KVM_RUN, 0);
>     }
>
> No need to do anything, I'll handle this patch after -rc1.

Thanks for that. :)

Regards,
Wanpeng Li

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] KVM: VMX: Fix rflags cache during vCPU reset
  2017-11-21  0:34   ` Wanpeng Li
@ 2017-12-05  0:28     ` Jim Mattson
  2017-12-05  0:53       ` Wanpeng Li
  0 siblings, 1 reply; 7+ messages in thread
From: Jim Mattson @ 2017-12-05  0:28 UTC (permalink / raw)
  To: Wanpeng Li
  Cc: Paolo Bonzini, linux-kernel, kvm, Radim Krčmář,
	Wanpeng Li, Nadav Amit, Dmitry Vyukov

That seems like a convoluted path to produce an illegal RFLAGS value.
What's to prevent syzkaller from simply clearing bit 1 of RFLAGS with
the KVM_SET_REGS ioctl?

On Mon, Nov 20, 2017 at 4:34 PM, Wanpeng Li <kernellwp@gmail.com> wrote:
> 2017-11-21 7:09 GMT+08:00 Paolo Bonzini <pbonzini@redhat.com>:
>> On 20/11/2017 23:52, Wanpeng Li wrote:
>>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>>> index b348920..131fa1c 100644
>>> --- a/arch/x86/kvm/vmx.c
>>> +++ b/arch/x86/kvm/vmx.c
>>> @@ -5590,6 +5590,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
>>>               vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
>>>       }
>>>
>>> +     kvm_set_rflags(vcpu, 2);
>>>       vmcs_writel(GUEST_RFLAGS, 0x02);
>>
>> I think the vmcs_writel can go, kvm_set_rflags ends up calling
>> vmx_set_rflags.
>
> Agreed.
>
>>
>>>       kvm_rip_write(vcpu, 0xfff0);
>>>
>>>
>>
>> Beautified testcase:
>>
>>     #include <unistd.h>
>>     #include <sys/syscall.h>
>>     #include <string.h>
>>     #include <stdint.h>
>>     #include <linux/kvm.h>
>>     #include <fcntl.h>
>>     #include <sys/ioctl.h>
>>
>>     long r[5];
>>     int main()
>>     {
>>         struct kvm_debugregs dr = { 0 };
>>
>>         r[2] = open("/dev/kvm", O_RDONLY);
>>         r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
>>         r[4] = ioctl(r[3], KVM_CREATE_VCPU, 7);
>>         struct kvm_guest_debug debug = {
>>                 .control = 0xf0403,
>>                 .arch = {
>>                         .debugreg[6] = 0x2,
>>                         .debugreg[7] = 0x2
>>                 }
>>         };
>>         ioctl(r[4], KVM_SET_GUEST_DEBUG, &debug);
>>         ioctl(r[4], KVM_RUN, 0);
>>     }
>>
>> No need to do anything, I'll handle this patch after -rc1.
>
> Thanks for that. :)
>
> Regards,
> Wanpeng Li

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] KVM: VMX: Fix rflags cache during vCPU reset
  2017-12-05  0:28     ` Jim Mattson
@ 2017-12-05  0:53       ` Wanpeng Li
  2017-12-05 13:54         ` Paolo Bonzini
  0 siblings, 1 reply; 7+ messages in thread
From: Wanpeng Li @ 2017-12-05  0:53 UTC (permalink / raw)
  To: Jim Mattson
  Cc: Paolo Bonzini, linux-kernel, kvm, Radim Krčmář,
	Wanpeng Li, Nadav Amit, Dmitry Vyukov

2017-12-05 8:28 GMT+08:00 Jim Mattson <jmattson@google.com>:
> That seems like a convoluted path to produce an illegal RFLAGS value.
> What's to prevent syzkaller from simply clearing bit 1 of RFLAGS with
> the KVM_SET_REGS ioctl?

Yeah, it can happen. Which do you prefer, ioctl fails or |
X86_EFLAGS_FIXED unconditionally in the ioctl handler in kvm?

Regards,
Wanpeng Li

>
> On Mon, Nov 20, 2017 at 4:34 PM, Wanpeng Li <kernellwp@gmail.com> wrote:
>> 2017-11-21 7:09 GMT+08:00 Paolo Bonzini <pbonzini@redhat.com>:
>>> On 20/11/2017 23:52, Wanpeng Li wrote:
>>>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>>>> index b348920..131fa1c 100644
>>>> --- a/arch/x86/kvm/vmx.c
>>>> +++ b/arch/x86/kvm/vmx.c
>>>> @@ -5590,6 +5590,7 @@ static void vmx_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
>>>>               vmcs_write64(GUEST_IA32_DEBUGCTL, 0);
>>>>       }
>>>>
>>>> +     kvm_set_rflags(vcpu, 2);
>>>>       vmcs_writel(GUEST_RFLAGS, 0x02);
>>>
>>> I think the vmcs_writel can go, kvm_set_rflags ends up calling
>>> vmx_set_rflags.
>>
>> Agreed.
>>
>>>
>>>>       kvm_rip_write(vcpu, 0xfff0);
>>>>
>>>>
>>>
>>> Beautified testcase:
>>>
>>>     #include <unistd.h>
>>>     #include <sys/syscall.h>
>>>     #include <string.h>
>>>     #include <stdint.h>
>>>     #include <linux/kvm.h>
>>>     #include <fcntl.h>
>>>     #include <sys/ioctl.h>
>>>
>>>     long r[5];
>>>     int main()
>>>     {
>>>         struct kvm_debugregs dr = { 0 };
>>>
>>>         r[2] = open("/dev/kvm", O_RDONLY);
>>>         r[3] = ioctl(r[2], KVM_CREATE_VM, 0);
>>>         r[4] = ioctl(r[3], KVM_CREATE_VCPU, 7);
>>>         struct kvm_guest_debug debug = {
>>>                 .control = 0xf0403,
>>>                 .arch = {
>>>                         .debugreg[6] = 0x2,
>>>                         .debugreg[7] = 0x2
>>>                 }
>>>         };
>>>         ioctl(r[4], KVM_SET_GUEST_DEBUG, &debug);
>>>         ioctl(r[4], KVM_RUN, 0);
>>>     }
>>>
>>> No need to do anything, I'll handle this patch after -rc1.
>>
>> Thanks for that. :)
>>
>> Regards,
>> Wanpeng Li

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] KVM: VMX: Fix rflags cache during vCPU reset
  2017-12-05  0:53       ` Wanpeng Li
@ 2017-12-05 13:54         ` Paolo Bonzini
  2017-12-05 17:53           ` Jim Mattson
  0 siblings, 1 reply; 7+ messages in thread
From: Paolo Bonzini @ 2017-12-05 13:54 UTC (permalink / raw)
  To: Wanpeng Li, Jim Mattson
  Cc: linux-kernel, kvm, Radim Krčmář,
	Wanpeng Li, Nadav Amit, Dmitry Vyukov

On 05/12/2017 01:53, Wanpeng Li wrote:
>> That seems like a convoluted path to produce an illegal RFLAGS value.
>> What's to prevent syzkaller from simply clearing bit 1 of RFLAGS with
>> the KVM_SET_REGS ioctl?
> Yeah, it can happen. Which do you prefer, ioctl fails or |
> X86_EFLAGS_FIXED unconditionally in the ioctl handler in kvm?

I suspect somebody might be passing an all-zero regs struct to
KVM_SET_REGS, so ORing X86_EFLAGS_FIXED is better.

Thanks,

Paolo

^ permalink raw reply	[flat|nested] 7+ messages in thread

* Re: [PATCH v2] KVM: VMX: Fix rflags cache during vCPU reset
  2017-12-05 13:54         ` Paolo Bonzini
@ 2017-12-05 17:53           ` Jim Mattson
  0 siblings, 0 replies; 7+ messages in thread
From: Jim Mattson @ 2017-12-05 17:53 UTC (permalink / raw)
  To: Paolo Bonzini
  Cc: Wanpeng Li, linux-kernel, kvm, Radim Krčmář,
	Wanpeng Li, Nadav Amit, Dmitry Vyukov

Sorry; I didn't mean to derail this patch thread. Setting bit 1 of
RFLAGS on CPU reset is clearly correct.

I was just noting that if syzkaller is complaining about illegal
RFLAGS, it's trivial for userspace to set RFLAGS to an illegal value.
User space can set all kinds of illegal RFLAGS state...bits 63:22, 15,
5, or 3 can be set; bit 1 can be cleared; RFLAGS.VM can be set in long
mode or real-address mode; RFLAGS.IF can be set while injecting an
interrupt via KVM_SET_VCPU_EVENTS. Let's not get hung up too much on
the one case of bit 1 being clear.

I don't think KVM_SET_REGS, KVM_SET_SREGS, KVM_SET_VCPU_EVENTS, and
friends should necessarily be in the validation business. There are
too many context-dependent validation checks that might pass or fail
depending on the order in which these ioctls are called. In a way,
these ioctls are comparable to the VMWRITE instruction, which does no
validity checking.

Better, perhaps, would be to defer the validity checks to KVM_VMRUN
(and let the hardware take care of them). Unfortunately, this doesn't
interact very well with emulate_invalid_guest_state = true and
enable_unrestricted_guest = false, in which case invalid guest state
is passed to the kernel emulator to see how well it deals with the
illegal state. (By the way, that's a really fun configuration for
syzkaller, because it opens the door to a myriad of kvm warnings that
are difficult to exercise otherwise).

So, how should illegal RFLAGS bits be handled by KVM_SET_REGS? Sure,
we could set bit 1, and we could clear bits 63:22, 15, 5, and 3. But
what about RFLAGS.VM and RFLAGS.IF?

On Tue, Dec 5, 2017 at 5:54 AM, Paolo Bonzini <pbonzini@redhat.com> wrote:
> On 05/12/2017 01:53, Wanpeng Li wrote:
>>> That seems like a convoluted path to produce an illegal RFLAGS value.
>>> What's to prevent syzkaller from simply clearing bit 1 of RFLAGS with
>>> the KVM_SET_REGS ioctl?
>> Yeah, it can happen. Which do you prefer, ioctl fails or |
>> X86_EFLAGS_FIXED unconditionally in the ioctl handler in kvm?
>
> I suspect somebody might be passing an all-zero regs struct to
> KVM_SET_REGS, so ORing X86_EFLAGS_FIXED is better.
>
> Thanks,
>
> Paolo

^ permalink raw reply	[flat|nested] 7+ messages in thread

end of thread, other threads:[~2017-12-05 17:53 UTC | newest]

Thread overview: 7+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2017-11-20 22:52 [PATCH v2] KVM: VMX: Fix rflags cache during vCPU reset Wanpeng Li
2017-11-20 23:09 ` Paolo Bonzini
2017-11-21  0:34   ` Wanpeng Li
2017-12-05  0:28     ` Jim Mattson
2017-12-05  0:53       ` Wanpeng Li
2017-12-05 13:54         ` Paolo Bonzini
2017-12-05 17:53           ` Jim Mattson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).