Message ID | 20230525183347.2562472-4-mhal@rbox.co (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Out-of-bounds access in kvm_recalculate_phys_map() | expand |
On Thu, May 25, 2023, Michal Luczaj wrote: > Keep switching between LAPIC_MODE_X2APIC and LAPIC_MODE_DISABLED during > APIC map construction. > > Signed-off-by: Michal Luczaj <mhal@rbox.co> > --- > tools/testing/selftests/kvm/Makefile | 1 + > .../kvm/x86_64/recalc_apic_map_race.c | 110 ++++++++++++++++++ > 2 files changed, 111 insertions(+) > create mode 100644 tools/testing/selftests/kvm/x86_64/recalc_apic_map_race.c > > diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile > index 7a5ff646e7e7..c9b8f16fb23f 100644 > --- a/tools/testing/selftests/kvm/Makefile > +++ b/tools/testing/selftests/kvm/Makefile > @@ -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_race > 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 > diff --git a/tools/testing/selftests/kvm/x86_64/recalc_apic_map_race.c b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_race.c > new file mode 100644 > index 000000000000..1122df858623 > --- /dev/null > +++ b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_race.c > @@ -0,0 +1,110 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * recalc_apic_map_race > + * > + * Test for a race condition 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 STUFFING 100 > + > +#define LAPIC_MODE_DISABLED 0 > +#define LAPIC_MODE_X2APIC (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE) > +#define MAX_XAPIC_ID 0xff > + > +static int add_vcpu(struct kvm_vm *vm, long id) > +{ > + int vcpu = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)id); > + > + static struct { > + struct kvm_cpuid2 head; > + struct kvm_cpuid_entry2 entry; > + } cpuid = { > + .head.nent = 1, > + /* X86_FEATURE_X2APIC */ > + .entry = { > + .function = 0x1, > + .index = 0, > + .ecx = 1UL << 21 > + } > + }; > + > + ASSERT_EQ(ioctl(vcpu, KVM_SET_CPUID2, &cpuid.head), 0); > + > + return vcpu; > +} > + > +static void set_apicbase(int vcpu, u64 mode) > +{ > + struct { > + struct kvm_msrs head; > + struct kvm_msr_entry entry; > + } msr = { > + .head.nmsrs = 1, > + .entry = { > + .index = MSR_IA32_APICBASE, > + .data = mode > + } > + }; > + > + ASSERT_EQ(ioctl(vcpu, KVM_SET_MSRS, &msr.head), msr.head.nmsrs); > +} > + > +static void *race(void *arg) > +{ > + struct kvm_lapic_state state = {}; > + int vcpu = *(int *)arg; > + > + while (1) { > + /* Trigger kvm_recalculate_apic_map(). */ > + ioctl(vcpu, KVM_SET_LAPIC, &state); > + pthread_testcancel(); > + } > + > + return NULL; > +} > + > +int main(void) > +{ > + int vcpu0, vcpuN, i; > + struct kvm_vm *vm; > + pthread_t thread; > + time_t t; > + > + vm = vm_create_barebones(); > + vm_create_irqchip(vm); All of these open coded ioctl() calls is unnecessary. Ditto for the fancy stuffing, which through trial and error I discovered is done to avoid having vCPUs with aliased xAPIC IDs, which would cause KVM to bail before triggering the bug. It's much easier to just create the max number of vCPUs and enable x2APIC on all of them. This can all be distilled down to: // SPDX-License-Identifier: GPL-2.0-only /* * recalc_apic_map_race * * Test for a race condition 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); /* * Creating 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_release(vm); return 0; }
On 5/27/23 01:40, Sean Christopherson wrote: > All of these open coded ioctl() calls is unnecessary. Ditto for the fancy > stuffing, which through trial and error I discovered is done to avoid having > vCPUs with aliased xAPIC IDs, which would cause KVM to bail before triggering > the bug. It's much easier to just create the max number of vCPUs and enable > x2APIC on all of them. > ... Yup, this looks way better, thanks. (FWIW, the #defines were deliberately named to match enum lapic_mode.) In somewhat related news, I've hit kvm_recalculate_logical_map()'s WARN_ON_ONCE(ldr != kvm_apic_calc_x2apic_ldr(kvm_x2apic_id(apic))): [ 464.081627] WARNING: CPU: 2 PID: 958 at arch/x86/kvm/lapic.c:331 kvm_recalculate_apic_map+0x609/0xa00 [kvm] [ 464.081703] Modules linked in: kvm_intel 9p fscache netfs qrtr sunrpc intel_rapl_msr kvm 9pnet_virtio 9pnet intel_rapl_common rapl pcspkr i2c_piix4 drm zram crct10dif_pclmul crc32_pclmul crc32c_intel ghash_clmulni_intel ata_generic serio_raw virtio_blk virtio_console pata_acpi fuse qemu_fw_cfg [last unloaded: kvm_intel] [ 464.081778] CPU: 2 PID: 958 Comm: recalc_apic_map Not tainted 6.4.0-rc3-vanilla+ #35 [ 464.081782] Hardware name: QEMU Standard PC (i440FX + PIIX, 1996), BIOS Arch Linux 1.16.2-1-1 04/01/2014 [ 464.081785] RIP: 0010:kvm_recalculate_apic_map+0x609/0xa00 [kvm] [ 464.081852] Code: 04 0f 84 00 02 00 00 49 8d 7e 24 e8 b1 2d 13 c1 41 8b 56 24 89 d0 83 e2 0f c1 e8 04 c1 e0 10 0f ab d0 39 e8 0f 84 50 fe ff ff <0f> 0b e9 49 fe ff ff 4c 8d a5 b0 02 00 00 4c 89 e7 e8 a1 2e 13 c1 [ 464.081855] RSP: 0018:ffffc900015cf6c8 EFLAGS: 00010297 [ 464.081860] RAX: 0000000000000001 RBX: ffff888108bb3c00 RCX: dffffc0000000000 [ 464.081863] RDX: 0000000000000000 RSI: ffffffffc04875ef RDI: ffff888178a651a4 [ 464.081865] RBP: 0000000000000002 R08: 0000000000000000 R09: ffffffff8446e2e7 [ 464.081868] R10: fffffbfff088dc5c R11: 0000000000000000 R12: 0000000000000000 [ 464.081870] R13: 0000000000000003 R14: ffff888178a65180 R15: ffff8881131b2000 [ 464.081873] FS: 00007fade8a9a740(0000) GS:ffff8883eef00000(0000) knlGS:0000000000000000 [ 464.081876] CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 [ 464.081879] CR2: 00007fade88d0008 CR3: 000000014d68b000 CR4: 0000000000752ee0 [ 464.081883] PKRU: 55555554 [ 464.081886] Call Trace: [ 464.081888] <TASK> [ 464.081901] ? kvm_can_use_hv_timer+0x60/0x60 [kvm] [ 464.081969] ? queue_delayed_work_on+0x6c/0xa0 [ 464.081978] kvm_apic_set_state+0x1cf/0x5b0 [kvm] [ 464.082050] kvm_arch_vcpu_ioctl+0x1806/0x2100 [kvm] [ 464.082116] ? kvm_arch_vcpu_put+0x410/0x410 [kvm] [ 464.082180] ? mark_lock+0xf4/0xce0 [ 464.082185] ? kvm_arch_vcpu_put+0x410/0x410 [kvm] [ 464.082251] ? mark_lock+0xf4/0xce0 [ 464.082255] ? preempt_count_sub+0x14/0xc0 [ 464.082263] ? print_usage_bug.part.0+0x3b0/0x3b0 [ 464.082269] ? kvm_arch_vcpu_put+0x410/0x410 [kvm] [ 464.082363] ? mark_lock+0xf4/0xce0 [ 464.082369] ? __kernel_text_address+0xe/0x30 [ 464.082373] ? unwind_get_return_address+0x2f/0x50 [ 464.082382] ? print_usage_bug.part.0+0x3b0/0x3b0 [ 464.082392] ? __lock_acquire+0x9ed/0x3210 [ 464.082404] ? lockdep_hardirqs_on_prepare+0x220/0x220 [ 464.082410] ? lockdep_hardirqs_on_prepare+0x220/0x220 [ 464.082420] ? lock_acquire+0x159/0x3b0 [ 464.082426] ? lock_acquire+0x169/0x3b0 [ 464.082432] ? lock_sync+0x110/0x110 [ 464.082438] ? find_held_lock+0x83/0xa0 [ 464.082444] ? lock_release+0x214/0x3a0 [ 464.082448] ? kvm_vcpu_ioctl+0x1c6/0x8a0 [kvm] [ 464.082507] ? rcu_is_watching+0x34/0x50 [ 464.082524] ? preempt_count_sub+0x14/0xc0 [ 464.082527] ? __mutex_lock+0x201/0x1040 [ 464.082532] ? kvm_vcpu_ioctl+0x13a/0x8a0 [kvm] [ 464.082586] ? find_held_lock+0x83/0xa0 [ 464.082591] ? kvm_vcpu_ioctl+0x13a/0x8a0 [kvm] [ 464.082648] ? mutex_lock_io_nested+0xe40/0xe40 [ 464.082652] ? bit_wait_io_timeout+0xc0/0xc0 [ 464.082658] ? kvm_vcpu_ioctl+0x13a/0x8a0 [kvm] [ 464.082720] ? kvm_vcpu_ioctl+0x663/0x8a0 [kvm] [ 464.082774] kvm_vcpu_ioctl+0x663/0x8a0 [kvm] [ 464.082831] ? kvm_vcpu_kick+0x200/0x200 [kvm] [ 464.082884] ? vfs_fileattr_set+0x480/0x480 [ 464.082889] ? vfs_fileattr_set+0x480/0x480 [ 464.082893] ? rcu_is_watching+0x34/0x50 [ 464.082897] ? kfree+0x107/0x140 [ 464.082902] ? kvm_vcpu_ioctl+0x1d6/0x8a0 [kvm] [ 464.082955] ? ioctl_has_perm.constprop.0.isra.0+0x133/0x1f0 [ 464.082961] ? ioctl_has_perm.constprop.0.isra.0+0x133/0x1f0 [ 464.082967] ? selinux_bprm_creds_for_exec+0x440/0x440 [ 464.082988] __x64_sys_ioctl+0xb8/0xf0 [ 464.082994] do_syscall_64+0x56/0x80 [ 464.083000] ? mark_held_locks+0x1a/0x80 [ 464.083007] ? do_syscall_64+0x62/0x80 [ 464.083011] ? lockdep_hardirqs_on+0x7d/0x100 [ 464.083015] ? do_syscall_64+0x62/0x80 [ 464.083019] ? lockdep_hardirqs_on+0x7d/0x100 [ 464.083023] entry_SYSCALL_64_after_hwframe+0x46/0xb0 [ 464.083027] RIP: 0033:0x7fade8b9dd6f [ 464.083031] Code: 00 48 89 44 24 18 31 c0 48 8d 44 24 60 c7 04 24 10 00 00 00 48 89 44 24 08 48 8d 44 24 20 48 89 44 24 10 b8 10 00 00 00 0f 05 <89> c2 3d 00 f0 ff ff 77 18 48 8b 44 24 18 64 48 2b 04 25 28 00 00 [ 464.083034] RSP: 002b:00007ffffd2d4550 EFLAGS: 00000246 ORIG_RAX: 0000000000000010 [ 464.083038] RAX: ffffffffffffffda RBX: 00007ffffd2d4ae8 RCX: 00007fade8b9dd6f [ 464.083041] RDX: 00007ffffd2d45c0 RSI: 000000004400ae8f RDI: 0000000000000005 [ 464.083044] RBP: 0000000000000001 R08: 00000000004150a8 R09: 0000000000415004 [ 464.083047] R10: 0000000002268301 R11: 0000000000000246 R12: 00000000022662a0 [ 464.083050] R13: 00007ffffd2d4af8 R14: 0000000000421df0 R15: 00007fade8cc0000 [ 464.083064] </TASK> [ 464.083066] irq event stamp: 22889 [ 464.083069] hardirqs last enabled at (22895): [<ffffffff81234ede>] __up_console_sem+0x5e/0x70 [ 464.083073] hardirqs last disabled at (22900): [<ffffffff81234ec3>] __up_console_sem+0x43/0x70 [ 464.083077] softirqs last enabled at (22184): [<ffffffff811538cf>] __irq_exit_rcu+0xdf/0x1b0 [ 464.083082] softirqs last disabled at (22077): [<ffffffff811538cf>] __irq_exit_rcu+0xdf/0x1b0 diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index c9b8f16fb23f..1c7f9cf51998 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -117,6 +117,7 @@ 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_race +TEST_GEN_PROGS_x86_64 += x86_64/recalc_apic_map_warn 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 diff --git a/tools/testing/selftests/kvm/x86_64/recalc_apic_map_warn.c b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_warn.c new file mode 100644 index 000000000000..2845e1d9b865 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_warn.c @@ -0,0 +1,30 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * recalc_apic_map_warn + * + * Test for hitting WARN_ON_ONCE() in kvm_recalculate_logical_map(). + */ + +#include "processor.h" +#include "kvm_util.h" +#include "apic.h" + +#define LAPIC_X2APIC (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE) + +int main(void) +{ + struct kvm_lapic_state lapic = {}; + struct kvm_vcpu *vcpu; + struct kvm_vm *vm; + + vm = vm_create_with_one_vcpu(&vcpu, NULL); /* vcpu_id = 0 */ + vcpu_set_msr(vcpu, MSR_IA32_APICBASE, LAPIC_X2APIC); + + *(u32 *)(lapic.regs + APIC_ID) = 1 << 24; /* != vcpu_id */ + *(u32 *)(lapic.regs + APIC_SPIV) = APIC_SPIV_APIC_ENABLED; + vcpu_ioctl(vcpu, KVM_SET_LAPIC, &lapic); + + kvm_vm_release(vm); + + return 0; +}
On Sun, May 28, 2023, Michal Luczaj wrote: > On 5/27/23 01:40, Sean Christopherson wrote: > > All of these open coded ioctl() calls is unnecessary. Ditto for the fancy > > stuffing, which through trial and error I discovered is done to avoid having > > vCPUs with aliased xAPIC IDs, which would cause KVM to bail before triggering > > the bug. It's much easier to just create the max number of vCPUs and enable > > x2APIC on all of them. > > ... > > Yup, this looks way better, thanks. > (FWIW, the #defines were deliberately named to match enum lapic_mode.) I figured as much, but I find enum lapic_mode to be rather odd, and if that thing ever gets cleaned up I'd prefer not to have to go fixup selftests too. > In somewhat related news, I've hit kvm_recalculate_logical_map()'s > WARN_ON_ONCE(ldr != kvm_apic_calc_x2apic_ldr(kvm_x2apic_id(apic))): ... > diff --git a/tools/testing/selftests/kvm/x86_64/recalc_apic_map_warn.c b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_warn.c > new file mode 100644 > index 000000000000..2845e1d9b865 > --- /dev/null > +++ b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_warn.c > @@ -0,0 +1,30 @@ > +// SPDX-License-Identifier: GPL-2.0-only > +/* > + * recalc_apic_map_warn > + * > + * Test for hitting WARN_ON_ONCE() in kvm_recalculate_logical_map(). > + */ > + > +#include "processor.h" > +#include "kvm_util.h" > +#include "apic.h" > + > +#define LAPIC_X2APIC (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE) > + > +int main(void) > +{ > + struct kvm_lapic_state lapic = {}; > + struct kvm_vcpu *vcpu; > + struct kvm_vm *vm; > + > + vm = vm_create_with_one_vcpu(&vcpu, NULL); /* vcpu_id = 0 */ > + vcpu_set_msr(vcpu, MSR_IA32_APICBASE, LAPIC_X2APIC); > + > + *(u32 *)(lapic.regs + APIC_ID) = 1 << 24; /* != vcpu_id */ > + *(u32 *)(lapic.regs + APIC_SPIV) = APIC_SPIV_APIC_ENABLED; > + vcpu_ioctl(vcpu, KVM_SET_LAPIC, &lapic); Blech. There's a semi-known backdoor that lets userspace modify the x2APIC ID and thus the LDR. Sort of. KVM doesn't actually honor the modified ID except for guest RDMSR, e.g. KVM will never deliver interrupts to the unexpected ID. I'll send a patch (plus this test) to close that loophole, the odds of breaking an existing setup are basically nil, and it would be very nice to make the x2APIC ID (and LDR) fully readonly.
diff --git a/tools/testing/selftests/kvm/Makefile b/tools/testing/selftests/kvm/Makefile index 7a5ff646e7e7..c9b8f16fb23f 100644 --- a/tools/testing/selftests/kvm/Makefile +++ b/tools/testing/selftests/kvm/Makefile @@ -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_race 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 diff --git a/tools/testing/selftests/kvm/x86_64/recalc_apic_map_race.c b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_race.c new file mode 100644 index 000000000000..1122df858623 --- /dev/null +++ b/tools/testing/selftests/kvm/x86_64/recalc_apic_map_race.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0-only +/* + * recalc_apic_map_race + * + * Test for a race condition 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 STUFFING 100 + +#define LAPIC_MODE_DISABLED 0 +#define LAPIC_MODE_X2APIC (MSR_IA32_APICBASE_ENABLE | X2APIC_ENABLE) +#define MAX_XAPIC_ID 0xff + +static int add_vcpu(struct kvm_vm *vm, long id) +{ + int vcpu = __vm_ioctl(vm, KVM_CREATE_VCPU, (void *)id); + + static struct { + struct kvm_cpuid2 head; + struct kvm_cpuid_entry2 entry; + } cpuid = { + .head.nent = 1, + /* X86_FEATURE_X2APIC */ + .entry = { + .function = 0x1, + .index = 0, + .ecx = 1UL << 21 + } + }; + + ASSERT_EQ(ioctl(vcpu, KVM_SET_CPUID2, &cpuid.head), 0); + + return vcpu; +} + +static void set_apicbase(int vcpu, u64 mode) +{ + struct { + struct kvm_msrs head; + struct kvm_msr_entry entry; + } msr = { + .head.nmsrs = 1, + .entry = { + .index = MSR_IA32_APICBASE, + .data = mode + } + }; + + ASSERT_EQ(ioctl(vcpu, KVM_SET_MSRS, &msr.head), msr.head.nmsrs); +} + +static void *race(void *arg) +{ + struct kvm_lapic_state state = {}; + int vcpu = *(int *)arg; + + while (1) { + /* Trigger kvm_recalculate_apic_map(). */ + ioctl(vcpu, KVM_SET_LAPIC, &state); + pthread_testcancel(); + } + + return NULL; +} + +int main(void) +{ + int vcpu0, vcpuN, i; + struct kvm_vm *vm; + pthread_t thread; + time_t t; + + vm = vm_create_barebones(); + vm_create_irqchip(vm); + + vcpu0 = add_vcpu(vm, 0); + vcpuN = add_vcpu(vm, KVM_MAX_VCPUS); + + static_assert(MAX_XAPIC_ID + STUFFING < KVM_MAX_VCPUS); + for (i = 0; i < STUFFING; ++i) + close(add_vcpu(vm, MAX_XAPIC_ID + i)); + + ASSERT_EQ(pthread_create(&thread, NULL, race, &vcpu0), 0); + + pr_info("Testing recalc_apic_map_race...\n"); + + for (t = time(NULL) + TIMEOUT; time(NULL) < t;) { + set_apicbase(vcpuN, LAPIC_MODE_X2APIC); + set_apicbase(vcpuN, LAPIC_MODE_DISABLED); + } + + ASSERT_EQ(pthread_cancel(thread), 0); + ASSERT_EQ(pthread_join(thread, NULL), 0); + + close(vcpu0); + close(vcpuN); + kvm_vm_release(vm); + + return 0; +}
Keep switching between LAPIC_MODE_X2APIC and LAPIC_MODE_DISABLED during APIC map construction. Signed-off-by: Michal Luczaj <mhal@rbox.co> --- tools/testing/selftests/kvm/Makefile | 1 + .../kvm/x86_64/recalc_apic_map_race.c | 110 ++++++++++++++++++ 2 files changed, 111 insertions(+) create mode 100644 tools/testing/selftests/kvm/x86_64/recalc_apic_map_race.c