KVM x86 fixes for 6.4
- Fix a memslot lookup bug in the NX recovery thread that could theoretically let userspace bypass the NX hugepage mitigation - Fix a s/BLOCKING/PENDING bug in SVM's vNMI support - Account exit stats for fastpath VM-Exits that never leave the super tight run-loop - Fix an out-of-bounds bug in the optimized APIC map code, and add a regression test for the race. -----BEGIN PGP SIGNATURE----- iQJGBAABCgAwFiEEMHr+pfEFOIzK+KY1YJEiAU0MEvkFAmR6id4SHHNlYW5qY0Bn b29nbGUuY29tAAoJEGCRIgFNDBL5i8UP/0QqgBeVHluyG+0v+x1pXNsB1lEKjkTX 7W0OLkEPB2p4JVa0TG4zcBrs+JTCRGPnC3aL86Xd5LLQq51aZuEsFYRHJ6Ngs5jR Sy/EOHGwgL0Ol83KBPpRsAwX9TXspRq/fWDKqlNCFa90tJFqTioTaaG5T4YNqdR9 NcxmtvOi3GnqSUU+9MV0/DL4vOthhstQdj4JPptgP5hS/FH1F7ZdFSFC46AS0C60 bXJglcmv4l8tEGnIo2VtJAAK8MxCJp0m/4Ow+AXqAqIFDxP3F66KG60l4Jrty0GE URuXXFUtwYMhJaeZlnHM1po6RKX/E1etYEA4E0zHD/fntXg8ciE9j9XwQadXT44Q 8WIGmSt52OH3zRqbuMcOpdkuW9LepkrA2A8POpJuN9j9ELoNBHzMC+L1pe9FMEd+ VT2lfoAfDyQzIuwzOwyqc0/axUx0YeyMJy/3mVuk10hI4L32YRDvc97IVXf6MUQA DaAu+mgEjU6J+MVsWcpHHEq31VtpZXAaaluub2JlBOaPANMIM9Qfur2XtwFIuL3u sOZAiyBWQyUUzMEqdOAVpB1HB1QZ2Tb1NmhUXGLh5BrpkWxqEf89vtM6xN+sXmip lQDyxf1NDFxiAVfcnG0I0q0285mDr2mbGHTawu1vM5o46MWyqmXiSQMdAEbnyIUm uEF1Rppg4Hkc =ztue -----END PGP SIGNATURE----- Merge tag 'kvm-x86-fixes-6.4' of https://github.com/kvm-x86/linux into HEAD KVM x86 fixes for 6.4 - Fix a memslot lookup bug in the NX recovery thread that could theoretically let userspace bypass the NX hugepage mitigation - Fix a s/BLOCKING/PENDING bug in SVM's vNMI support - Account exit stats for fastpath VM-Exits that never leave the super tight run-loop - Fix an out-of-bounds bug in the optimized APIC map code, and add a regression test for the race.
This commit is contained in:
Коммит
f211b45057
|
@ -228,6 +228,23 @@ static int kvm_recalculate_phys_map(struct kvm_apic_map *new,
|
|||
u32 xapic_id = kvm_xapic_id(apic);
|
||||
u32 physical_id;
|
||||
|
||||
/*
|
||||
* For simplicity, KVM always allocates enough space for all possible
|
||||
* xAPIC IDs. Yell, but don't kill the VM, as KVM can continue on
|
||||
* without the optimized map.
|
||||
*/
|
||||
if (WARN_ON_ONCE(xapic_id > new->max_apic_id))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* Bail if a vCPU was added and/or enabled its APIC between allocating
|
||||
* the map and doing the actual calculations for the map. Note, KVM
|
||||
* hardcodes the x2APIC ID to vcpu_id, i.e. there's no TOCTOU bug if
|
||||
* the compiler decides to reload x2apic_id after this check.
|
||||
*/
|
||||
if (x2apic_id > new->max_apic_id)
|
||||
return -E2BIG;
|
||||
|
||||
/*
|
||||
* Deliberately truncate the vCPU ID when detecting a mismatched APIC
|
||||
* ID to avoid false positives if the vCPU ID, i.e. x2APIC ID, is a
|
||||
|
@ -253,8 +270,7 @@ static int kvm_recalculate_phys_map(struct kvm_apic_map *new,
|
|||
*/
|
||||
if (vcpu->kvm->arch.x2apic_format) {
|
||||
/* See also kvm_apic_match_physical_addr(). */
|
||||
if ((apic_x2apic_mode(apic) || x2apic_id > 0xff) &&
|
||||
x2apic_id <= new->max_apic_id)
|
||||
if (apic_x2apic_mode(apic) || x2apic_id > 0xff)
|
||||
new->phys_map[x2apic_id] = apic;
|
||||
|
||||
if (!apic_x2apic_mode(apic) && !new->phys_map[xapic_id])
|
||||
|
|
|
@ -7091,7 +7091,10 @@ static void kvm_recover_nx_huge_pages(struct kvm *kvm)
|
|||
*/
|
||||
slot = NULL;
|
||||
if (atomic_read(&kvm->nr_memslots_dirty_logging)) {
|
||||
slot = gfn_to_memslot(kvm, sp->gfn);
|
||||
struct kvm_memslots *slots;
|
||||
|
||||
slots = kvm_memslots_for_spte_role(kvm, sp->role);
|
||||
slot = __gfn_to_memslot(slots, sp->gfn);
|
||||
WARN_ON_ONCE(!slot);
|
||||
}
|
||||
|
||||
|
|
|
@ -3510,7 +3510,7 @@ static bool svm_is_vnmi_pending(struct kvm_vcpu *vcpu)
|
|||
if (!is_vnmi_enabled(svm))
|
||||
return false;
|
||||
|
||||
return !!(svm->vmcb->control.int_ctl & V_NMI_BLOCKING_MASK);
|
||||
return !!(svm->vmcb->control.int_ctl & V_NMI_PENDING_MASK);
|
||||
}
|
||||
|
||||
static bool svm_set_vnmi_pending(struct kvm_vcpu *vcpu)
|
||||
|
|
|
@ -10758,6 +10758,9 @@ static int vcpu_enter_guest(struct kvm_vcpu *vcpu)
|
|||
exit_fastpath = EXIT_FASTPATH_EXIT_HANDLED;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Note, VM-Exits that go down the "slow" path are accounted below. */
|
||||
++vcpu->stat.exits;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
|
@ -116,6 +116,7 @@ TEST_GEN_PROGS_x86_64 += x86_64/sev_migrate_tests
|
|||
TEST_GEN_PROGS_x86_64 += x86_64/amx_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/max_vcpuid_cap_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/triple_fault_event_test
|
||||
TEST_GEN_PROGS_x86_64 += x86_64/recalc_apic_map_test
|
||||
TEST_GEN_PROGS_x86_64 += access_tracking_perf_test
|
||||
TEST_GEN_PROGS_x86_64 += demand_paging_test
|
||||
TEST_GEN_PROGS_x86_64 += dirty_log_test
|
||||
|
|
|
@ -0,0 +1,74 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Test edge cases and race conditions in kvm_recalculate_apic_map().
|
||||
*/
|
||||
|
||||
#include <sys/ioctl.h>
|
||||
#include <pthread.h>
|
||||
#include <time.h>
|
||||
|
||||
#include "processor.h"
|
||||
#include "test_util.h"
|
||||
#include "kvm_util.h"
|
||||
#include "apic.h"
|
||||
|
||||
#define TIMEOUT 5 /* seconds */
|
||||
|
||||
#define LAPIC_DISABLED 0
|
||||
#define LAPIC_X2APIC (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE)
|
||||
#define MAX_XAPIC_ID 0xff
|
||||
|
||||
static void *race(void *arg)
|
||||
{
|
||||
struct kvm_lapic_state lapic = {};
|
||||
struct kvm_vcpu *vcpu = arg;
|
||||
|
||||
while (1) {
|
||||
/* Trigger kvm_recalculate_apic_map(). */
|
||||
vcpu_ioctl(vcpu, KVM_SET_LAPIC, &lapic);
|
||||
pthread_testcancel();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int main(void)
|
||||
{
|
||||
struct kvm_vcpu *vcpus[KVM_MAX_VCPUS];
|
||||
struct kvm_vcpu *vcpuN;
|
||||
struct kvm_vm *vm;
|
||||
pthread_t thread;
|
||||
time_t t;
|
||||
int i;
|
||||
|
||||
kvm_static_assert(KVM_MAX_VCPUS > MAX_XAPIC_ID);
|
||||
|
||||
/*
|
||||
* Create the max number of vCPUs supported by selftests so that KVM
|
||||
* has decent amount of work to do when recalculating the map, i.e. to
|
||||
* make the problematic window large enough to hit.
|
||||
*/
|
||||
vm = vm_create_with_vcpus(KVM_MAX_VCPUS, NULL, vcpus);
|
||||
|
||||
/*
|
||||
* Enable x2APIC on all vCPUs so that KVM doesn't bail from the recalc
|
||||
* due to vCPUs having aliased xAPIC IDs (truncated to 8 bits).
|
||||
*/
|
||||
for (i = 0; i < KVM_MAX_VCPUS; i++)
|
||||
vcpu_set_msr(vcpus[i], MSR_IA32_APICBASE, LAPIC_X2APIC);
|
||||
|
||||
ASSERT_EQ(pthread_create(&thread, NULL, race, vcpus[0]), 0);
|
||||
|
||||
vcpuN = vcpus[KVM_MAX_VCPUS - 1];
|
||||
for (t = time(NULL) + TIMEOUT; time(NULL) < t;) {
|
||||
vcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_X2APIC);
|
||||
vcpu_set_msr(vcpuN, MSR_IA32_APICBASE, LAPIC_DISABLED);
|
||||
}
|
||||
|
||||
ASSERT_EQ(pthread_cancel(thread), 0);
|
||||
ASSERT_EQ(pthread_join(thread, NULL), 0);
|
||||
|
||||
kvm_vm_free(vm);
|
||||
|
||||
return 0;
|
||||
}
|
Загрузка…
Ссылка в новой задаче