diff mbox

WARNING in x86_emulate_insn

Message ID CAOLK0pwczbQrno_vc2Uj6czyELyiEHeCAoi2SgDvvKcRNiijiw@mail.gmail.com (mailing list archive)
State New, archived
Headers show

Commit Message

Tianyu Lan Dec. 8, 2017, 8:28 a.m. UTC
Hi Jim&Wanpeng:
         Thanks for your help.

2017-12-08 5:25 GMT+08:00 Jim Mattson <jmattson@google.com>:
> Try disabling the module parameter, "unrestricted_guest." Make sure
> that the module parameter, "emulate_invalid_guest_state" is enabled.
> This combination allows userspace to feed invalid guest state into the
> in-kernel emulator.

Yes, you are right. I need to disable unrestricted_guest to reproduce the issue.

I find this is pop instruction emulation issue. According "SDM VOL2,
chapter INSTRUCTION
SET REFERENCE. POP—Pop a Value from the Stack"

Protected Mode Exceptions
#GP(0) If attempt is made to load SS register with NULL segment selector.

This test case hits it but current code doesn't check such case.
The following patch can fix the issue.

Comments

Ingo Molnar Dec. 8, 2017, 8:44 a.m. UTC | #1
* Tianyu Lan <lantianyu1986@gmail.com> wrote:

> Hi Jim&Wanpeng:
>          Thanks for your help.
> 
> 2017-12-08 5:25 GMT+08:00 Jim Mattson <jmattson@google.com>:
> > Try disabling the module parameter, "unrestricted_guest." Make sure
> > that the module parameter, "emulate_invalid_guest_state" is enabled.
> > This combination allows userspace to feed invalid guest state into the
> > in-kernel emulator.
> 
> Yes, you are right. I need to disable unrestricted_guest to reproduce the issue.
> 
> I find this is pop instruction emulation issue. According "SDM VOL2,
> chapter INSTRUCTION
> SET REFERENCE. POP—Pop a Value from the Stack"
> 
> Protected Mode Exceptions
> #GP(0) If attempt is made to load SS register with NULL segment selector.
> 
> This test case hits it but current code doesn't check such case.
> The following patch can fix the issue.
> 
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index abe74f7..e2ac5cc 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -1844,6 +1844,9 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
>         int rc;
>         struct segmented_address addr;
> 
> +       if ( !get_segment_selector(ctxt, VCPU_SREG_SS))
> +               return emulate_gp(ctxt, 0);
> +
>         addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt);
>         addr.seg = VCPU_SREG_SS;
>         rc = segmented_read(ctxt, addr, dest, len);

s/if ( !get_segment_selector
 /if (!get_segment_selector

I think it would also be nice to convert the syzkaller testcase to a new KVM unit 
test:

  git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git

There's a test_pop() function in kvm-unit-tests/x86/emulator.c.

Thanks,

	Ingo
Tianyu Lan Dec. 8, 2017, 8:48 a.m. UTC | #2
2017-12-08 16:44 GMT+08:00 Ingo Molnar <mingo@kernel.org>:
>
> * Tianyu Lan <lantianyu1986@gmail.com> wrote:
>
>> Hi Jim&Wanpeng:
>>          Thanks for your help.
>>
>> 2017-12-08 5:25 GMT+08:00 Jim Mattson <jmattson@google.com>:
>> > Try disabling the module parameter, "unrestricted_guest." Make sure
>> > that the module parameter, "emulate_invalid_guest_state" is enabled.
>> > This combination allows userspace to feed invalid guest state into the
>> > in-kernel emulator.
>>
>> Yes, you are right. I need to disable unrestricted_guest to reproduce the issue.
>>
>> I find this is pop instruction emulation issue. According "SDM VOL2,
>> chapter INSTRUCTION
>> SET REFERENCE. POP—Pop a Value from the Stack"
>>
>> Protected Mode Exceptions
>> #GP(0) If attempt is made to load SS register with NULL segment selector.
>>
>> This test case hits it but current code doesn't check such case.
>> The following patch can fix the issue.
>>
>> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
>> index abe74f7..e2ac5cc 100644
>> --- a/arch/x86/kvm/emulate.c
>> +++ b/arch/x86/kvm/emulate.c
>> @@ -1844,6 +1844,9 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
>>         int rc;
>>         struct segmented_address addr;
>>
>> +       if ( !get_segment_selector(ctxt, VCPU_SREG_SS))
>> +               return emulate_gp(ctxt, 0);
>> +
>>         addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt);
>>         addr.seg = VCPU_SREG_SS;
>>         rc = segmented_read(ctxt, addr, dest, len);
>
> s/if ( !get_segment_selector
>  /if (!get_segment_selector

Sorry. I mixed xen and kernel code style...

>
> I think it would also be nice to convert the syzkaller testcase to a new KVM unit
> test:

Sure. I will add it.

>
>   git://git.kernel.org/pub/scm/virt/kvm/kvm-unit-tests.git
>
> There's a test_pop() function in kvm-unit-tests/x86/emulator.c.
>
> Thanks,
>
>         Ingo
Wanpeng Li Dec. 8, 2017, 9:27 a.m. UTC | #3
2017-12-08 16:28 GMT+08:00 Tianyu Lan <lantianyu1986@gmail.com>:
> Hi Jim&Wanpeng:
>          Thanks for your help.
>
> 2017-12-08 5:25 GMT+08:00 Jim Mattson <jmattson@google.com>:
>> Try disabling the module parameter, "unrestricted_guest." Make sure
>> that the module parameter, "emulate_invalid_guest_state" is enabled.
>> This combination allows userspace to feed invalid guest state into the
>> in-kernel emulator.
>
> Yes, you are right. I need to disable unrestricted_guest to reproduce the issue.

I can observe ctxt->exception.vector == 0xff which triggers Dmitry's
report. Do you figure out the reason?

Regards,
Wanpeng Li

>
> I find this is pop instruction emulation issue. According "SDM VOL2,
> chapter INSTRUCTION
> SET REFERENCE. POP—Pop a Value from the Stack"
>
> Protected Mode Exceptions
> #GP(0) If attempt is made to load SS register with NULL segment selector.
>
> This test case hits it but current code doesn't check such case.
> The following patch can fix the issue.
>
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index abe74f7..e2ac5cc 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -1844,6 +1844,9 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
>         int rc;
>         struct segmented_address addr;
>
> +       if ( !get_segment_selector(ctxt, VCPU_SREG_SS))
> +               return emulate_gp(ctxt, 0);
> +
>         addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt);
>         addr.seg = VCPU_SREG_SS;
>         rc = segmented_read(ctxt, addr, dest, len);
lan,Tianyu Dec. 9, 2017, 5:44 a.m. UTC | #4
On 12/8/2017 5:27 PM, Wanpeng Li wrote:
> 2017-12-08 16:28 GMT+08:00 Tianyu Lan <lantianyu1986@gmail.com>:
>> Hi Jim&Wanpeng:
>>           Thanks for your help.
>>
>> 2017-12-08 5:25 GMT+08:00 Jim Mattson <jmattson@google.com>:
>>> Try disabling the module parameter, "unrestricted_guest." Make sure
>>> that the module parameter, "emulate_invalid_guest_state" is enabled.
>>> This combination allows userspace to feed invalid guest state into the
>>> in-kernel emulator.
>>
>> Yes, you are right. I need to disable unrestricted_guest to reproduce the issue.
> 
> I can observe ctxt->exception.vector == 0xff which triggers Dmitry's
> report. Do you figure out the reason?
> 

Yes, this is caused by that emulation callback returns error code while
not emulate exception and not set exception vector.
ctxt->exception.vector is default to be 0xff in emulate instruction code
path.
Paolo Bonzini Dec. 11, 2017, 10:45 p.m. UTC | #5
On 08/12/2017 09:28, Tianyu Lan wrote:
> I find this is pop instruction emulation issue. According "SDM VOL2,
> chapter INSTRUCTION
> SET REFERENCE. POP—Pop a Value from the Stack"
> 
> Protected Mode Exceptions
> #GP(0) If attempt is made to load SS register with NULL segment selector.

This is not what the testcase is testing; this is already covered by 
__load_segment_descriptor:

        if (null_selector) {
                if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR)
                        goto exception;

                if (seg == VCPU_SREG_SS) {
                        if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl)
                                goto exception;
		...
	}

Is there a path that can return X86EMUL_PROPAGATE_FAULT without setting
ctxt->exception.vector and/or without going through emulate_exception?

I don't think it's possible to write a test in kvm-unit-tests, because the
state has "impossible" segment descriptor cache contents.

Paolo

> This test case hits it but current code doesn't check such case.
> The following patch can fix the issue.
> 
> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
> index abe74f7..e2ac5cc 100644
> --- a/arch/x86/kvm/emulate.c
> +++ b/arch/x86/kvm/emulate.c
> @@ -1844,6 +1844,9 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
>         int rc;
>         struct segmented_address addr;
> 
> +       if ( !get_segment_selector(ctxt, VCPU_SREG_SS))
> +               return emulate_gp(ctxt, 0);
> +
>         addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt);
>         addr.seg = VCPU_SREG_SS;
>         rc = segmented_read(ctxt, addr, dest, len);
lan,Tianyu Dec. 12, 2017, 8:50 a.m. UTC | #6
On 2017年12月12日 06:45, Paolo Bonzini wrote:
> On 08/12/2017 09:28, Tianyu Lan wrote:
>> I find this is pop instruction emulation issue. According "SDM VOL2,
>> chapter INSTRUCTION
>> SET REFERENCE. POP—Pop a Value from the Stack"
>>
>> Protected Mode Exceptions
>> #GP(0) If attempt is made to load SS register with NULL segment selector.
> 
> This is not what the testcase is testing; this is already covered by 
> __load_segment_descriptor:
> 
>         if (null_selector) {
>                 if (seg == VCPU_SREG_CS || seg == VCPU_SREG_TR)
>                         goto exception;
> 
>                 if (seg == VCPU_SREG_SS) {
>                         if (ctxt->mode != X86EMUL_MODE_PROT64 || rpl != cpl)
>                                 goto exception;
> 		...
> 	}

Yes, __load_segment_descriptor() does such check. I find em_pop doesn't
load SS segment. SS isn't loaded before calling em_pop in the test case.
Should this be fixed?

> 
> Is there a path that can return X86EMUL_PROPAGATE_FAULT without setting
> ctxt->exception.vector and/or without going through emulate_exception?
> 
> I don't think it's possible to write a test in kvm-unit-tests, because the
> state has "impossible" segment descriptor cache contents.

Sent out a fix patch for the issue. Please have a look. Thanks.
https://marc.info/?l=kvm&m=151306208214733&w=2

> 
> Paolo
> 
>> This test case hits it but current code doesn't check such case.
>> The following patch can fix the issue.
>>
>> diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
>> index abe74f7..e2ac5cc 100644
>> --- a/arch/x86/kvm/emulate.c
>> +++ b/arch/x86/kvm/emulate.c
>> @@ -1844,6 +1844,9 @@ static int emulate_pop(struct x86_emulate_ctxt *ctxt,
>>         int rc;
>>         struct segmented_address addr;
>>
>> +       if ( !get_segment_selector(ctxt, VCPU_SREG_SS))
>> +               return emulate_gp(ctxt, 0);
>> +
>>         addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt);
>>         addr.seg = VCPU_SREG_SS;
>>         rc = segmented_read(ctxt, addr, dest, len);
>
diff mbox

Patch

diff --git a/arch/x86/kvm/emulate.c b/arch/x86/kvm/emulate.c
index abe74f7..e2ac5cc 100644
--- a/arch/x86/kvm/emulate.c
+++ b/arch/x86/kvm/emulate.c
@@ -1844,6 +1844,9 @@  static int emulate_pop(struct x86_emulate_ctxt *ctxt,
        int rc;
        struct segmented_address addr;

+       if ( !get_segment_selector(ctxt, VCPU_SREG_SS))
+               return emulate_gp(ctxt, 0);
+
        addr.ea = reg_read(ctxt, VCPU_REGS_RSP) & stack_mask(ctxt);
        addr.seg = VCPU_SREG_SS;
        rc = segmented_read(ctxt, addr, dest, len);