Skip to content

Commit bf82d38

Browse files
committed
Merge tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm
Pull kvm fixes from Paolo Bonzini: "x86: - Fixes for Xen emulation. While nobody should be enabling it in the kernel (the only public users of the feature are the selftests), the bug effectively allows userspace to read arbitrary memory. - Correctness fixes for nested hypervisors that do not intercept INIT or SHUTDOWN on AMD; the subsequent CPU reset can cause a use-after-free when it disables virtualization extensions. While downgrading the panic to a WARN is quite easy, the full fix is a bit more laborious; there are also tests. This is the bulk of the pull request. - Fix race condition due to incorrect mmu_lock use around make_mmu_pages_available(). Generic: - Obey changes to the kvm.halt_poll_ns module parameter in VMs not using KVM_CAP_HALT_POLL, restoring behavior from before the introduction of the capability" * tag 'for-linus' of git://git.kernel.org/pub/scm/virt/kvm/kvm: KVM: Update gfn_to_pfn_cache khva when it moves within the same page KVM: x86/xen: Only do in-kernel acceleration of hypercalls for guest CPL0 KVM: x86/xen: Validate port number in SCHEDOP_poll KVM: x86/mmu: Fix race condition in direct_page_fault KVM: x86: remove exit_int_info warning in svm_handle_exit KVM: selftests: add svm part to triple_fault_test KVM: x86: allow L1 to not intercept triple fault kvm: selftests: add svm nested shutdown test KVM: selftests: move idt_entry to header KVM: x86: forcibly leave nested mode on vCPU reset KVM: x86: add kvm_leave_nested KVM: x86: nSVM: harden svm_free_nested against freeing vmcb02 while still in use KVM: x86: nSVM: leave nested mode on vCPU free KVM: Obey kvm.halt_poll_ns in VMs not using KVM_CAP_HALT_POLL KVM: Avoid re-reading kvm->max_halt_poll_ns during halt-polling KVM: Cap vcpu->halt_poll_ns before halting rather than after
2 parents 30a853c + fe08e36 commit bf82d38

File tree

15 files changed

+251
-83
lines changed

15 files changed

+251
-83
lines changed

arch/x86/kvm/mmu/mmu.c

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2443,6 +2443,7 @@ static bool __kvm_mmu_prepare_zap_page(struct kvm *kvm,
24432443
{
24442444
bool list_unstable, zapped_root = false;
24452445

2446+
lockdep_assert_held_write(&kvm->mmu_lock);
24462447
trace_kvm_mmu_prepare_zap_page(sp);
24472448
++kvm->stat.mmu_shadow_zapped;
24482449
*nr_zapped = mmu_zap_unsync_children(kvm, sp, invalid_list);
@@ -4262,14 +4263,14 @@ static int direct_page_fault(struct kvm_vcpu *vcpu, struct kvm_page_fault *fault
42624263
if (is_page_fault_stale(vcpu, fault, mmu_seq))
42634264
goto out_unlock;
42644265

4265-
r = make_mmu_pages_available(vcpu);
4266-
if (r)
4267-
goto out_unlock;
4268-
4269-
if (is_tdp_mmu_fault)
4266+
if (is_tdp_mmu_fault) {
42704267
r = kvm_tdp_mmu_map(vcpu, fault);
4271-
else
4268+
} else {
4269+
r = make_mmu_pages_available(vcpu);
4270+
if (r)
4271+
goto out_unlock;
42724272
r = __direct_map(vcpu, fault);
4273+
}
42734274

42744275
out_unlock:
42754276
if (is_tdp_mmu_fault)

arch/x86/kvm/svm/nested.c

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1091,6 +1091,12 @@ int nested_svm_vmexit(struct vcpu_svm *svm)
10911091

10921092
static void nested_svm_triple_fault(struct kvm_vcpu *vcpu)
10931093
{
1094+
struct vcpu_svm *svm = to_svm(vcpu);
1095+
1096+
if (!vmcb12_is_intercept(&svm->nested.ctl, INTERCEPT_SHUTDOWN))
1097+
return;
1098+
1099+
kvm_clear_request(KVM_REQ_TRIPLE_FAULT, vcpu);
10941100
nested_svm_simple_vmexit(to_svm(vcpu), SVM_EXIT_SHUTDOWN);
10951101
}
10961102

@@ -1125,6 +1131,9 @@ void svm_free_nested(struct vcpu_svm *svm)
11251131
if (!svm->nested.initialized)
11261132
return;
11271133

1134+
if (WARN_ON_ONCE(svm->vmcb != svm->vmcb01.ptr))
1135+
svm_switch_vmcb(svm, &svm->vmcb01);
1136+
11281137
svm_vcpu_free_msrpm(svm->nested.msrpm);
11291138
svm->nested.msrpm = NULL;
11301139

@@ -1143,9 +1152,6 @@ void svm_free_nested(struct vcpu_svm *svm)
11431152
svm->nested.initialized = false;
11441153
}
11451154

1146-
/*
1147-
* Forcibly leave nested mode in order to be able to reset the VCPU later on.
1148-
*/
11491155
void svm_leave_nested(struct kvm_vcpu *vcpu)
11501156
{
11511157
struct vcpu_svm *svm = to_svm(vcpu);

arch/x86/kvm/svm/svm.c

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -346,12 +346,6 @@ int svm_set_efer(struct kvm_vcpu *vcpu, u64 efer)
346346
return 0;
347347
}
348348

349-
static int is_external_interrupt(u32 info)
350-
{
351-
info &= SVM_EVTINJ_TYPE_MASK | SVM_EVTINJ_VALID;
352-
return info == (SVM_EVTINJ_VALID | SVM_EVTINJ_TYPE_INTR);
353-
}
354-
355349
static u32 svm_get_interrupt_shadow(struct kvm_vcpu *vcpu)
356350
{
357351
struct vcpu_svm *svm = to_svm(vcpu);
@@ -1438,6 +1432,7 @@ static void svm_vcpu_free(struct kvm_vcpu *vcpu)
14381432
*/
14391433
svm_clear_current_vmcb(svm->vmcb);
14401434

1435+
svm_leave_nested(vcpu);
14411436
svm_free_nested(svm);
14421437

14431438
sev_free_vcpu(vcpu);
@@ -3425,15 +3420,6 @@ static int svm_handle_exit(struct kvm_vcpu *vcpu, fastpath_t exit_fastpath)
34253420
return 0;
34263421
}
34273422

3428-
if (is_external_interrupt(svm->vmcb->control.exit_int_info) &&
3429-
exit_code != SVM_EXIT_EXCP_BASE + PF_VECTOR &&
3430-
exit_code != SVM_EXIT_NPF && exit_code != SVM_EXIT_TASK_SWITCH &&
3431-
exit_code != SVM_EXIT_INTR && exit_code != SVM_EXIT_NMI)
3432-
printk(KERN_ERR "%s: unexpected exit_int_info 0x%x "
3433-
"exit_code 0x%x\n",
3434-
__func__, svm->vmcb->control.exit_int_info,
3435-
exit_code);
3436-
34373423
if (exit_fastpath != EXIT_FASTPATH_NONE)
34383424
return 1;
34393425

arch/x86/kvm/vmx/nested.c

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4854,6 +4854,7 @@ void nested_vmx_vmexit(struct kvm_vcpu *vcpu, u32 vm_exit_reason,
48544854

48554855
static void nested_vmx_triple_fault(struct kvm_vcpu *vcpu)
48564856
{
4857+
kvm_clear_request(KVM_REQ_TRIPLE_FAULT, vcpu);
48574858
nested_vmx_vmexit(vcpu, EXIT_REASON_TRIPLE_FAULT, 0, 0);
48584859
}
48594860

@@ -6440,9 +6441,6 @@ static int vmx_get_nested_state(struct kvm_vcpu *vcpu,
64406441
return kvm_state.size;
64416442
}
64426443

6443-
/*
6444-
* Forcibly leave nested mode in order to be able to reset the VCPU later on.
6445-
*/
64466444
void vmx_leave_nested(struct kvm_vcpu *vcpu)
64476445
{
64486446
if (is_guest_mode(vcpu)) {

arch/x86/kvm/x86.c

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -628,6 +628,12 @@ static void kvm_queue_exception_vmexit(struct kvm_vcpu *vcpu, unsigned int vecto
628628
ex->payload = payload;
629629
}
630630

631+
/* Forcibly leave the nested mode in cases like a vCPU reset */
632+
static void kvm_leave_nested(struct kvm_vcpu *vcpu)
633+
{
634+
kvm_x86_ops.nested_ops->leave_nested(vcpu);
635+
}
636+
631637
static void kvm_multiple_exception(struct kvm_vcpu *vcpu,
632638
unsigned nr, bool has_error, u32 error_code,
633639
bool has_payload, unsigned long payload, bool reinject)
@@ -5195,7 +5201,7 @@ static int kvm_vcpu_ioctl_x86_set_vcpu_events(struct kvm_vcpu *vcpu,
51955201

51965202
if (events->flags & KVM_VCPUEVENT_VALID_SMM) {
51975203
if (!!(vcpu->arch.hflags & HF_SMM_MASK) != events->smi.smm) {
5198-
kvm_x86_ops.nested_ops->leave_nested(vcpu);
5204+
kvm_leave_nested(vcpu);
51995205
kvm_smm_changed(vcpu, events->smi.smm);
52005206
}
52015207

@@ -9805,7 +9811,7 @@ static void update_cr8_intercept(struct kvm_vcpu *vcpu)
98059811

98069812
int kvm_check_nested_events(struct kvm_vcpu *vcpu)
98079813
{
9808-
if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
9814+
if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
98099815
kvm_x86_ops.nested_ops->triple_fault(vcpu);
98109816
return 1;
98119817
}
@@ -10560,15 +10566,16 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
1056010566
r = 0;
1056110567
goto out;
1056210568
}
10563-
if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
10564-
if (is_guest_mode(vcpu)) {
10569+
if (kvm_test_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
10570+
if (is_guest_mode(vcpu))
1056510571
kvm_x86_ops.nested_ops->triple_fault(vcpu);
10566-
} else {
10572+
10573+
if (kvm_check_request(KVM_REQ_TRIPLE_FAULT, vcpu)) {
1056710574
vcpu->run->exit_reason = KVM_EXIT_SHUTDOWN;
1056810575
vcpu->mmio_needed = 0;
1056910576
r = 0;
10570-
goto out;
1057110577
}
10578+
goto out;
1057210579
}
1057310580
if (kvm_check_request(KVM_REQ_APF_HALT, vcpu)) {
1057410581
/* Page is swapped out. Do synthetic halt */
@@ -11997,8 +12004,18 @@ void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)
1199712004
WARN_ON_ONCE(!init_event &&
1199812005
(old_cr0 || kvm_read_cr3(vcpu) || kvm_read_cr4(vcpu)));
1199912006

12007+
/*
12008+
* SVM doesn't unconditionally VM-Exit on INIT and SHUTDOWN, thus it's
12009+
* possible to INIT the vCPU while L2 is active. Force the vCPU back
12010+
* into L1 as EFER.SVME is cleared on INIT (along with all other EFER
12011+
* bits), i.e. virtualization is disabled.
12012+
*/
12013+
if (is_guest_mode(vcpu))
12014+
kvm_leave_nested(vcpu);
12015+
1200012016
kvm_lapic_reset(vcpu, init_event);
1200112017

12018+
WARN_ON_ONCE(is_guest_mode(vcpu) || is_smm(vcpu));
1200212019
vcpu->arch.hflags = 0;
1200312020

1200412021
vcpu->arch.smi_pending = 0;

arch/x86/kvm/xen.c

Lines changed: 23 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -954,6 +954,14 @@ static int kvm_xen_hypercall_complete_userspace(struct kvm_vcpu *vcpu)
954954
return kvm_xen_hypercall_set_result(vcpu, run->xen.u.hcall.result);
955955
}
956956

957+
static inline int max_evtchn_port(struct kvm *kvm)
958+
{
959+
if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode)
960+
return EVTCHN_2L_NR_CHANNELS;
961+
else
962+
return COMPAT_EVTCHN_2L_NR_CHANNELS;
963+
}
964+
957965
static bool wait_pending_event(struct kvm_vcpu *vcpu, int nr_ports,
958966
evtchn_port_t *ports)
959967
{
@@ -1042,6 +1050,10 @@ static bool kvm_xen_schedop_poll(struct kvm_vcpu *vcpu, bool longmode,
10421050
*r = -EFAULT;
10431051
goto out;
10441052
}
1053+
if (ports[i] >= max_evtchn_port(vcpu->kvm)) {
1054+
*r = -EINVAL;
1055+
goto out;
1056+
}
10451057
}
10461058

10471059
if (sched_poll.nr_ports == 1)
@@ -1215,6 +1227,7 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
12151227
bool longmode;
12161228
u64 input, params[6], r = -ENOSYS;
12171229
bool handled = false;
1230+
u8 cpl;
12181231

12191232
input = (u64)kvm_register_read(vcpu, VCPU_REGS_RAX);
12201233

@@ -1242,9 +1255,17 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
12421255
params[5] = (u64)kvm_r9_read(vcpu);
12431256
}
12441257
#endif
1258+
cpl = static_call(kvm_x86_get_cpl)(vcpu);
12451259
trace_kvm_xen_hypercall(input, params[0], params[1], params[2],
12461260
params[3], params[4], params[5]);
12471261

1262+
/*
1263+
* Only allow hypercall acceleration for CPL0. The rare hypercalls that
1264+
* are permitted in guest userspace can be handled by the VMM.
1265+
*/
1266+
if (unlikely(cpl > 0))
1267+
goto handle_in_userspace;
1268+
12481269
switch (input) {
12491270
case __HYPERVISOR_xen_version:
12501271
if (params[0] == XENVER_version && vcpu->kvm->arch.xen.xen_version) {
@@ -1279,10 +1300,11 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
12791300
if (handled)
12801301
return kvm_xen_hypercall_set_result(vcpu, r);
12811302

1303+
handle_in_userspace:
12821304
vcpu->run->exit_reason = KVM_EXIT_XEN;
12831305
vcpu->run->xen.type = KVM_EXIT_XEN_HCALL;
12841306
vcpu->run->xen.u.hcall.longmode = longmode;
1285-
vcpu->run->xen.u.hcall.cpl = static_call(kvm_x86_get_cpl)(vcpu);
1307+
vcpu->run->xen.u.hcall.cpl = cpl;
12861308
vcpu->run->xen.u.hcall.input = input;
12871309
vcpu->run->xen.u.hcall.params[0] = params[0];
12881310
vcpu->run->xen.u.hcall.params[1] = params[1];
@@ -1297,14 +1319,6 @@ int kvm_xen_hypercall(struct kvm_vcpu *vcpu)
12971319
return 0;
12981320
}
12991321

1300-
static inline int max_evtchn_port(struct kvm *kvm)
1301-
{
1302-
if (IS_ENABLED(CONFIG_64BIT) && kvm->arch.xen.long_mode)
1303-
return EVTCHN_2L_NR_CHANNELS;
1304-
else
1305-
return COMPAT_EVTCHN_2L_NR_CHANNELS;
1306-
}
1307-
13081322
static void kvm_xen_check_poller(struct kvm_vcpu *vcpu, int port)
13091323
{
13101324
int poll_evtchn = vcpu->arch.xen.poll_evtchn;

include/linux/kvm_host.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -776,6 +776,7 @@ struct kvm {
776776
struct srcu_struct srcu;
777777
struct srcu_struct irq_srcu;
778778
pid_t userspace_pid;
779+
bool override_halt_poll_ns;
779780
unsigned int max_halt_poll_ns;
780781
u32 dirty_ring_size;
781782
bool vm_bugged;

tools/testing/selftests/kvm/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,7 @@
4141
/x86_64/svm_vmcall_test
4242
/x86_64/svm_int_ctl_test
4343
/x86_64/svm_nested_soft_inject_test
44+
/x86_64/svm_nested_shutdown_test
4445
/x86_64/sync_regs_test
4546
/x86_64/tsc_msrs_test
4647
/x86_64/tsc_scaling_sync

tools/testing/selftests/kvm/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/state_test
101101
TEST_GEN_PROGS_x86_64 += x86_64/vmx_preemption_timer_test
102102
TEST_GEN_PROGS_x86_64 += x86_64/svm_vmcall_test
103103
TEST_GEN_PROGS_x86_64 += x86_64/svm_int_ctl_test
104+
TEST_GEN_PROGS_x86_64 += x86_64/svm_nested_shutdown_test
104105
TEST_GEN_PROGS_x86_64 += x86_64/svm_nested_soft_inject_test
105106
TEST_GEN_PROGS_x86_64 += x86_64/tsc_scaling_sync
106107
TEST_GEN_PROGS_x86_64 += x86_64/sync_regs_test

tools/testing/selftests/kvm/include/x86_64/processor.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -748,6 +748,19 @@ struct ex_regs {
748748
uint64_t rflags;
749749
};
750750

751+
struct idt_entry {
752+
uint16_t offset0;
753+
uint16_t selector;
754+
uint16_t ist : 3;
755+
uint16_t : 5;
756+
uint16_t type : 4;
757+
uint16_t : 1;
758+
uint16_t dpl : 2;
759+
uint16_t p : 1;
760+
uint16_t offset1;
761+
uint32_t offset2; uint32_t reserved;
762+
};
763+
751764
void vm_init_descriptor_tables(struct kvm_vm *vm);
752765
void vcpu_init_descriptor_tables(struct kvm_vcpu *vcpu);
753766
void vm_install_exception_handler(struct kvm_vm *vm, int vector,

0 commit comments

Comments
 (0)