lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date:   Mon, 10 Jul 2017 08:48:01 -0700
From:   Nadav Amit <nadav.amit@...il.com>
To:     Wanpeng Li <kernellwp@...il.com>
Cc:     Paolo Bonzini <pbonzini@...hat.com>,
        Radim Krcmar <rkrcmar@...hat.com>, kvm <kvm@...r.kernel.org>,
        "linux-kernel@...r.kernel.org" <linux-kernel@...r.kernel.org>,
        Jan Kiszka <jan.kiszka@....de>
Subject: Re: RFC: Task switch emulation fails for VM86 mode

Wanpeng Li <kernellwp@...il.com> wrote:

> Cc Nadav, Jan,
> 2017-07-09 15:30 GMT+08:00 Wanpeng Li <kernellwp@...il.com>:
>> Hi all,
>> 
>> I found that task switch emulation fails to work for VM86 mode if
>> guest state is invalid. It can be reproduced by running
>> kvm-unit-tests/taskswitch2.flat, EPT = 0 or EPT=1,
>> unrestricted_guest=N, emulate_invalid_guest_state=Y.
>> 
>> When EPT=1, unrestricted_guest=Y, emulate_invalid_state=Y, the trace
>> of kvm-unit-tests/taskswitch2.flat is like below:
>> 
>> kvm_entry: vcpu 0
>> kvm_exit: reason TASK_SWITCH rip 0x4008d0 info 40000058 0
>> kvm_entry: vcpu 0
>> kvm_exit: reason EXCEPTION_NMI rip 0x0 info 0 80000306
>> kvm_emulate_insn: 42000:0:0f 0b (0x2)
>> kvm_inj_exception: #UD (0x0)
>> kvm_entry: vcpu 0
>> kvm_exit: reason TASK_SWITCH rip 0x0 info c0000050 0
>> kvm_entry: vcpu 0
>> 
>> When EPT=1, unrestricted_guest=Y, emulate_invalid_state=Y, the trace
>> of kvm-unit-tests/taskswitch2.flat is like below, when emulating "0f
>> 0b(#UD)" fails, it injects another #UD and triggers a task switch in
>> the kvm-unit-tests/taskswitch2.flat again.
>> 
>> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
>> kvm_emulate_insn: 42000:0:0f 0b (0x2)
>> kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
>> kvm_inj_exception: #UD (0x0)
>> kvm_entry: vcpu 0
>> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
>> kvm_emulate_insn: 42000:0:0f 0b (0x2)
>> kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
>> kvm_inj_exception: #UD (0x0)
>> kvm_entry: vcpu 0
>> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
>> kvm_emulate_insn: 42000:0:0f 0b (0x2)
>> kvm_emulate_insn: 42000:0:0f 0b (0x2) failed
>> kvm_inj_exception: #UD (0x0)
>> .....................
>> 
>> Then I try to add the task switch emulation in the
>> handle_invalid_guest_state() path, however, I will get TRIPLE FAULT.
>> 
>> diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c
>> index f76efad..758f728 100644
>> --- a/arch/x86/kvm/vmx.c
>> +++ b/arch/x86/kvm/vmx.c
>> @@ -6312,11 +6312,15 @@ static int handle_invalid_guest_state(struct
>> kvm_vcpu *vcpu)
>>     u32 cpu_exec_ctrl;
>>     bool intr_window_requested;
>>     unsigned count = 130;
>> +    u32 exit_reason = vmx->exit_reason;
>> 
>>     cpu_exec_ctrl = vmcs_read32(CPU_BASED_VM_EXEC_CONTROL);
>>     intr_window_requested = cpu_exec_ctrl & CPU_BASED_VIRTUAL_INTR_PENDING;
>> 
>>     while (vmx->emulation_required && count-- != 0) {
>> +        if (exit_reason == EXIT_REASON_TASK_SWITCH)
>> +            return handle_task_switch(vcpu);
>> +
>>         if (intr_window_requested && vmx_interrupt_allowed(vcpu))
>>             return handle_interrupt_window(&vmx->vcpu);
>> 
>> 
>> kvm_exit: reason TASK_SWITCH rip 0x4008d0 info 40000058 0
>> kvm_entry: vcpu 0
>> kvm_exit: reason TASK_SWITCH rip 0x0 info 40000058 0
>> kvm_entry: vcpu 0
>> kvm_exit: reason TRIPLE_FAULT rip 0xffff info 0 0
>> kvm_userspace_exit: reason KVM_EXIT_SHUTDOWN (8)
>> 
>> Any proposal is a great appreciated. :)

I don’t see a (very) easy solution. The code was (apparently) never built to
deal with a task switch during an instruction emulation.

AFAIU kvm_task_switch() expects information about the task-switch from the
CPU “task-switch assist” mechanisms, and this information (or even the fact
that a task-switch is needed due to an exception) are unavailable from the
instruction emulator. The instruction emulator itself does not know to
emulate task-switches, e.g., during far CALL and JMP.

A complete solution is therefore complicated and requires some work. Your
specific problem may be addressed by detecting the injection of an exception
while having invalid guest state in vm86 in vmx_queue_exception() or in
handle_invalid_guest_state(), and emulating the “task-switch assist”
mechanism.

Powered by blists - more mailing lists