Skip to content

Commit e7422e1

Browse files
committed
KVM: x86: Load "FPU" state during GET_MP_STATE if CET is supported
Load (and put) FPU state in kvm_arch_vcpu_ioctl_get_mpstate() if KVM (and the host) supports CET, as kvm_apic_accept_events() can trigger emulation of INIT, which in turn can lead to putting FPU state. E.g. on a host with CET but not MPX, syzkaller+KASAN generates: Oops: general protection fault, probably for non-canonical address 0xdffffc0000000004: 0000 [#1] SMP KASAN NOPTI KASAN: null-ptr-deref in range [0x0000000000000020-0x0000000000000027] CPU: 211 UID: 0 PID: 20451 Comm: syz.9.26 Tainted: G S 6.18.0-smp-DEV torvalds#7 NONE Tainted: [S]=CPU_OUT_OF_SPEC Hardware name: Google Izumi/izumi, BIOS 0.20250729.1-0 07/29/2025 RIP: 0010:fpu_swap_kvm_fpstate+0x3ce/0x610 ../arch/x86/kernel/fpu/core.c:377 RSP: 0018:ff1100410c167cc0 EFLAGS: 00010202 RAX: 0000000000000004 RBX: 0000000000000020 RCX: 00000000000001aa RDX: 00000000000001ab RSI: ffffffff817bb960 RDI: 0000000022600000 RBP: dffffc0000000000 R08: ff110040d23c8007 R09: 1fe220081a479000 R10: dffffc0000000000 R11: ffe21c081a479001 R12: ff110040d23c8d98 R13: 00000000fffdc578 R14: 0000000000000000 R15: ff110040d23c8d90 FS: 00007f86dd1876c0(0000) GS:ff11007fc969b000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 0000000080050033 CR2: 00007f86dd186fa8 CR3: 00000040d1dfa003 CR4: 0000000000f73ef0 PKRU: 80000000 Call Trace: <TASK> kvm_vcpu_reset+0x80d/0x12c0 ../arch/x86/kvm/x86.c:11818 kvm_apic_accept_events+0x1cb/0x500 ../arch/x86/kvm/lapic.c:3489 kvm_arch_vcpu_ioctl_get_mpstate+0xd0/0x4e0 ../arch/x86/kvm/x86.c:12145 kvm_vcpu_ioctl+0x5e2/0xed0 ../virt/kvm/kvm_main.c:4539 __se_sys_ioctl+0x11d/0x1b0 ../fs/ioctl.c:51 do_syscall_x64 ../arch/x86/entry/syscall_64.c:63 [inline] do_syscall_64+0x6e/0x940 ../arch/x86/entry/syscall_64.c:94 entry_SYSCALL_64_after_hwframe+0x76/0x7e RIP: 0033:0x7f86de71d9c9 </TASK> with a very simple reproducer: r0 = openat$kvm(0xffffffffffffff9c, &(0x7f0000000000), 0x80b00, 0x0) r1 = ioctl$KVM_CREATE_VM(r0, 0xae01, 0x0) ioctl$KVM_CREATE_IRQCHIP(r1, 0xae60) r2 = ioctl$KVM_CREATE_VCPU(r1, 0xae41, 0x0) ioctl$KVM_SET_IRQCHIP(r1, 0x8208ae63, ...) ioctl$KVM_GET_MP_STATE(r2, 0x8004ae98, &(0x7f00000000c0)) For now, defer a more robust/pretty fix and address the immediate issue in the same way as commit f958bd2 ("KVM: x86: Fix potential put_fpu() w/o load_fpu() on MPX platform") in order to minimize the change in functionality. Commit f958bd2's justification for its hackery of "MPX is being removed from the kernel" obviously doesn't apply to CET, but providing a cleaner solution isn't an urgent concern. Reported-by: Alexander Potapenko <glider@google.com> Fixes: 69cc3e8 ("KVM: x86: Add XSS support for CET_KERNEL and CET_USER") Signed-off-by: Sean Christopherson <seanjc@google.com>
1 parent 4361f5a commit e7422e1

File tree

1 file changed

+12
-10
lines changed

1 file changed

+12
-10
lines changed

arch/x86/kvm/x86.c

Lines changed: 12 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12137,9 +12137,6 @@ int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
1213712137
int r;
1213812138

1213912139
vcpu_load(vcpu);
12140-
if (kvm_mpx_supported())
12141-
kvm_load_guest_fpu(vcpu);
12142-
1214312140
kvm_vcpu_srcu_read_lock(vcpu);
1214412141

1214512142
r = kvm_apic_accept_events(vcpu);
@@ -12156,9 +12153,6 @@ int kvm_arch_vcpu_ioctl_get_mpstate(struct kvm_vcpu *vcpu,
1215612153

1215712154
out:
1215812155
kvm_vcpu_srcu_read_unlock(vcpu);
12159-
12160-
if (kvm_mpx_supported())
12161-
kvm_put_guest_fpu(vcpu);
1216212156
vcpu_put(vcpu);
1216312157
return r;
1216412158
}
@@ -12811,13 +12805,21 @@ static void kvm_xstate_reset(struct kvm_vcpu *vcpu, bool init_event)
1281112805
BUILD_BUG_ON(sizeof(xfeatures_mask) * BITS_PER_BYTE <= XFEATURE_MAX);
1281212806

1281312807
/*
12814-
* All paths that lead to INIT are required to load the guest's FPU
12815-
* state (because most paths are buried in KVM_RUN).
12808+
* Unload guest FPU state (if necessary) before clearing the components
12809+
* as the kernel can only modify the state when its resident in memory,
12810+
* i.e. when it's not loaded into hardware.
12811+
*
12812+
* WARN if the vCPU's desire to run, i.e. whether or not its in KVM_RUN,
12813+
* doesn't match the loaded/in-use state of the FPU, as KVM_RUN is the
12814+
* only path that can trigger INIT emulation *and* loads FPU state.
1281612815
*/
12817-
kvm_put_guest_fpu(vcpu);
12816+
WARN_ON_ONCE(vcpu->wants_to_run != fpstate->in_use);
12817+
if (fpstate->in_use)
12818+
kvm_put_guest_fpu(vcpu);
1281812819
for_each_set_bit(i, (unsigned long *)&xfeatures_mask, XFEATURE_MAX)
1281912820
fpstate_clear_xstate_component(fpstate, i);
12820-
kvm_load_guest_fpu(vcpu);
12821+
if (fpstate->in_use)
12822+
kvm_load_guest_fpu(vcpu);
1282112823
}
1282212824

1282312825
void kvm_vcpu_reset(struct kvm_vcpu *vcpu, bool init_event)

0 commit comments

Comments
 (0)