]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/4.6.5/kvm-nvmx-vmx-instructions-fix-segment-checks-when-l1-is-in-long-mode.patch
5.1-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 4.6.5 / kvm-nvmx-vmx-instructions-fix-segment-checks-when-l1-is-in-long-mode.patch
1 From ff30ef40deca4658e27b0c596e7baf39115e858f Mon Sep 17 00:00:00 2001
2 From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
3 Date: Sat, 18 Jun 2016 11:01:05 +0200
4 Subject: KVM: nVMX: VMX instructions: fix segment checks when L1 is in long mode.
5 MIME-Version: 1.0
6 Content-Type: text/plain; charset=UTF-8
7 Content-Transfer-Encoding: 8bit
8
9 From: Quentin Casasnovas <quentin.casasnovas@oracle.com>
10
11 commit ff30ef40deca4658e27b0c596e7baf39115e858f upstream.
12
13 I couldn't get Xen to boot a L2 HVM when it was nested under KVM - it was
14 getting a GP(0) on a rather unspecial vmread from Xen:
15
16 (XEN) ----[ Xen-4.7.0-rc x86_64 debug=n Not tainted ]----
17 (XEN) CPU: 1
18 (XEN) RIP: e008:[<ffff82d0801e629e>] vmx_get_segment_register+0x14e/0x450
19 (XEN) RFLAGS: 0000000000010202 CONTEXT: hypervisor (d1v0)
20 (XEN) rax: ffff82d0801e6288 rbx: ffff83003ffbfb7c rcx: fffffffffffab928
21 (XEN) rdx: 0000000000000000 rsi: 0000000000000000 rdi: ffff83000bdd0000
22 (XEN) rbp: ffff83000bdd0000 rsp: ffff83003ffbfab0 r8: ffff830038813910
23 (XEN) r9: ffff83003faf3958 r10: 0000000a3b9f7640 r11: ffff83003f82d418
24 (XEN) r12: 0000000000000000 r13: ffff83003ffbffff r14: 0000000000004802
25 (XEN) r15: 0000000000000008 cr0: 0000000080050033 cr4: 00000000001526e0
26 (XEN) cr3: 000000003fc79000 cr2: 0000000000000000
27 (XEN) ds: 0000 es: 0000 fs: 0000 gs: 0000 ss: 0000 cs: e008
28 (XEN) Xen code around <ffff82d0801e629e> (vmx_get_segment_register+0x14e/0x450):
29 (XEN) 00 00 41 be 02 48 00 00 <44> 0f 78 74 24 08 0f 86 38 56 00 00 b8 08 68 00
30 (XEN) Xen stack trace from rsp=ffff83003ffbfab0:
31
32 ...
33
34 (XEN) Xen call trace:
35 (XEN) [<ffff82d0801e629e>] vmx_get_segment_register+0x14e/0x450
36 (XEN) [<ffff82d0801f3695>] get_page_from_gfn_p2m+0x165/0x300
37 (XEN) [<ffff82d0801bfe32>] hvmemul_get_seg_reg+0x52/0x60
38 (XEN) [<ffff82d0801bfe93>] hvm_emulate_prepare+0x53/0x70
39 (XEN) [<ffff82d0801ccacb>] handle_mmio+0x2b/0xd0
40 (XEN) [<ffff82d0801be591>] emulate.c#_hvm_emulate_one+0x111/0x2c0
41 (XEN) [<ffff82d0801cd6a4>] handle_hvm_io_completion+0x274/0x2a0
42 (XEN) [<ffff82d0801f334a>] __get_gfn_type_access+0xfa/0x270
43 (XEN) [<ffff82d08012f3bb>] timer.c#add_entry+0x4b/0xb0
44 (XEN) [<ffff82d08012f80c>] timer.c#remove_entry+0x7c/0x90
45 (XEN) [<ffff82d0801c8433>] hvm_do_resume+0x23/0x140
46 (XEN) [<ffff82d0801e4fe7>] vmx_do_resume+0xa7/0x140
47 (XEN) [<ffff82d080164aeb>] context_switch+0x13b/0xe40
48 (XEN) [<ffff82d080128e6e>] schedule.c#schedule+0x22e/0x570
49 (XEN) [<ffff82d08012c0cc>] softirq.c#__do_softirq+0x5c/0x90
50 (XEN) [<ffff82d0801602c5>] domain.c#idle_loop+0x25/0x50
51 (XEN)
52 (XEN)
53 (XEN) ****************************************
54 (XEN) Panic on CPU 1:
55 (XEN) GENERAL PROTECTION FAULT
56 (XEN) [error_code=0000]
57 (XEN) ****************************************
58
59 Tracing my host KVM showed it was the one injecting the GP(0) when
60 emulating the VMREAD and checking the destination segment permissions in
61 get_vmx_mem_address():
62
63 3) | vmx_handle_exit() {
64 3) | handle_vmread() {
65 3) | nested_vmx_check_permission() {
66 3) | vmx_get_segment() {
67 3) 0.074 us | vmx_read_guest_seg_base();
68 3) 0.065 us | vmx_read_guest_seg_selector();
69 3) 0.066 us | vmx_read_guest_seg_ar();
70 3) 1.636 us | }
71 3) 0.058 us | vmx_get_rflags();
72 3) 0.062 us | vmx_read_guest_seg_ar();
73 3) 3.469 us | }
74 3) | vmx_get_cs_db_l_bits() {
75 3) 0.058 us | vmx_read_guest_seg_ar();
76 3) 0.662 us | }
77 3) | get_vmx_mem_address() {
78 3) 0.068 us | vmx_cache_reg();
79 3) | vmx_get_segment() {
80 3) 0.074 us | vmx_read_guest_seg_base();
81 3) 0.068 us | vmx_read_guest_seg_selector();
82 3) 0.071 us | vmx_read_guest_seg_ar();
83 3) 1.756 us | }
84 3) | kvm_queue_exception_e() {
85 3) 0.066 us | kvm_multiple_exception();
86 3) 0.684 us | }
87 3) 4.085 us | }
88 3) 9.833 us | }
89 3) + 10.366 us | }
90
91 Cross-checking the KVM/VMX VMREAD emulation code with the Intel Software
92 Developper Manual Volume 3C - "VMREAD - Read Field from Virtual-Machine
93 Control Structure", I found that we're enforcing that the destination
94 operand is NOT located in a read-only data segment or any code segment when
95 the L1 is in long mode - BUT that check should only happen when it is in
96 protected mode.
97
98 Shuffling the code a bit to make our emulation follow the specification
99 allows me to boot a Xen dom0 in a nested KVM and start HVM L2 guests
100 without problems.
101
102 Fixes: f9eb4af67c9d ("KVM: nVMX: VMX instructions: add checks for #GP/#SS exceptions")
103 Signed-off-by: Quentin Casasnovas <quentin.casasnovas@oracle.com>
104 Cc: Eugene Korenevsky <ekorenevsky@gmail.com>
105 Cc: Paolo Bonzini <pbonzini@redhat.com>
106 Cc: Radim Krčmář <rkrcmar@redhat.com>
107 Cc: Thomas Gleixner <tglx@linutronix.de>
108 Cc: Ingo Molnar <mingo@redhat.com>
109 Cc: H. Peter Anvin <hpa@zytor.com>
110 Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
111 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
112
113 ---
114 arch/x86/kvm/vmx.c | 23 +++++++++++------------
115 1 file changed, 11 insertions(+), 12 deletions(-)
116
117 --- a/arch/x86/kvm/vmx.c
118 +++ b/arch/x86/kvm/vmx.c
119 @@ -6659,7 +6659,13 @@ static int get_vmx_mem_address(struct kv
120
121 /* Checks for #GP/#SS exceptions. */
122 exn = false;
123 - if (is_protmode(vcpu)) {
124 + if (is_long_mode(vcpu)) {
125 + /* Long mode: #GP(0)/#SS(0) if the memory address is in a
126 + * non-canonical form. This is the only check on the memory
127 + * destination for long mode!
128 + */
129 + exn = is_noncanonical_address(*ret);
130 + } else if (is_protmode(vcpu)) {
131 /* Protected mode: apply checks for segment validity in the
132 * following order:
133 * - segment type check (#GP(0) may be thrown)
134 @@ -6676,17 +6682,10 @@ static int get_vmx_mem_address(struct kv
135 * execute-only code segment
136 */
137 exn = ((s.type & 0xa) == 8);
138 - }
139 - if (exn) {
140 - kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
141 - return 1;
142 - }
143 - if (is_long_mode(vcpu)) {
144 - /* Long mode: #GP(0)/#SS(0) if the memory address is in a
145 - * non-canonical form. This is an only check for long mode.
146 - */
147 - exn = is_noncanonical_address(*ret);
148 - } else if (is_protmode(vcpu)) {
149 + if (exn) {
150 + kvm_queue_exception_e(vcpu, GP_VECTOR, 0);
151 + return 1;
152 + }
153 /* Protected mode: #GP(0)/#SS(0) if the segment is unusable.
154 */
155 exn = (s.unusable != 0);