Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

x86/reboot: Force all cpus to exit VMX root if VMX is supported

Force all CPUs to do VMXOFF (via NMI shootdown) during an emergency
reboot if VMX is _supported_, as VMX being off on the current CPU does
not prevent other CPUs from being in VMX root (post-VMXON). This fixes
a bug where a crash/panic reboot could leave other CPUs in VMX root and
prevent them from being woken via INIT-SIPI-SIPI in the new kernel.

Fixes: d176720d34c7 ("x86: disable VMX on all CPUs on reboot")
Cc: stable@vger.kernel.org
Suggested-by: Sean Christopherson <seanjc@google.com>
Signed-off-by: David P. Reed <dpreed@deepplum.com>
[sean: reworked changelog and further tweaked comment]
Signed-off-by: Sean Christopherson <seanjc@google.com>
Message-Id: <20201231002702.2223707-3-seanjc@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

authored by

Sean Christopherson and committed by
Paolo Bonzini
ed727361 aec511ad

+10 -20
+10 -20
arch/x86/kernel/reboot.c
··· 538 538 local_irq_disable(); 539 539 540 540 /* 541 - * We need to disable VMX on all CPUs before rebooting, otherwise 542 - * we risk hanging up the machine, because the CPU ignores INIT 543 - * signals when VMX is enabled. 541 + * Disable VMX on all CPUs before rebooting, otherwise we risk hanging 542 + * the machine, because the CPU blocks INIT when it's in VMX root. 544 543 * 545 - * We can't take any locks and we may be on an inconsistent 546 - * state, so we use NMIs as IPIs to tell the other CPUs to disable 547 - * VMX and halt. 544 + * We can't take any locks and we may be on an inconsistent state, so 545 + * use NMIs as IPIs to tell the other CPUs to exit VMX root and halt. 548 546 * 549 - * For safety, we will avoid running the nmi_shootdown_cpus() 550 - * stuff unnecessarily, but we don't have a way to check 551 - * if other CPUs have VMX enabled. So we will call it only if the 552 - * CPU we are running on has VMX enabled. 553 - * 554 - * We will miss cases where VMX is not enabled on all CPUs. This 555 - * shouldn't do much harm because KVM always enable VMX on all 556 - * CPUs anyway. But we can miss it on the small window where KVM 557 - * is still enabling VMX. 547 + * Do the NMI shootdown even if VMX if off on _this_ CPU, as that 548 + * doesn't prevent a different CPU from being in VMX root operation. 558 549 */ 559 - if (cpu_has_vmx() && cpu_vmx_enabled()) { 560 - /* Disable VMX on this CPU. */ 561 - cpu_vmxoff(); 550 + if (cpu_has_vmx()) { 551 + /* Safely force _this_ CPU out of VMX root operation. */ 552 + __cpu_emergency_vmxoff(); 562 553 563 - /* Halt and disable VMX on the other CPUs */ 554 + /* Halt and exit VMX root operation on the other CPUs. */ 564 555 nmi_shootdown_cpus(vmxoff_nmi); 565 - 566 556 } 567 557 } 568 558