[PULL 09/28] i386/cpu: Prevent delivering SIPI during SMM in TCG mode

Paolo Bonzini posted 28 patches 1 month ago
Maintainers: Paolo Bonzini <pbonzini@redhat.com>, "Dr. David Alan Gilbert" <dave@treblig.org>, Eduardo Habkost <eduardo@habkost.net>, Marcel Apfelbaum <marcel.apfelbaum@gmail.com>, "Philippe Mathieu-Daudé" <philmd@linaro.org>, Yanan Wang <wangyanan55@huawei.com>, Zhao Liu <zhao1.liu@intel.com>, "Michael S. Tsirkin" <mst@redhat.com>, Eric Blake <eblake@redhat.com>, Markus Armbruster <armbru@redhat.com>, Richard Henderson <richard.henderson@linaro.org>, Manos Pitsidianakis <manos.pitsidianakis@linaro.org>, Peter Maydell <peter.maydell@linaro.org>, Marcelo Tosatti <mtosatti@redhat.com>, Song Gao <gaosong@loongson.cn>, Huacai Chen <chenhuacai@kernel.org>, Aurelien Jarno <aurelien@aurel32.net>, Jiaxun Yang <jiaxun.yang@flygoat.com>, Aleksandar Rikalo <arikalo@gmail.com>, Nicholas Piggin <npiggin@gmail.com>, Harsh Prateek Bora <harshpb@linux.ibm.com>, Chinmay Rath <rathc@linux.ibm.com>, Palmer Dabbelt <palmer@dabbelt.com>, Alistair Francis <alistair.francis@wdc.com>, Weiwei Li <liwei1518@gmail.com>, Daniel Henrique Barboza <dbarboza@ventanamicro.com>, Liu Zhiwei <zhiwei_liu@linux.alibaba.com>, Halil Pasic <pasic@linux.ibm.com>, Christian Borntraeger <borntraeger@linux.ibm.com>, Eric Farman <farman@linux.ibm.com>, Matthew Rosato <mjrosato@linux.ibm.com>, Thomas Huth <thuth@redhat.com>, David Hildenbrand <david@redhat.com>, Ilya Leoshkevich <iii@linux.ibm.com>, Stefan Hajnoczi <stefanha@redhat.com>, Fam Zheng <fam@euphon.net>
[PULL 09/28] i386/cpu: Prevent delivering SIPI during SMM in TCG mode
Posted by Paolo Bonzini 1 month ago
[commit message by YiFei Zhu]

A malicious kernel may control the instruction pointer in SMM in a
multi-processor VM by sending a sequence of IPIs via APIC:

CPU0			CPU1
IPI(CPU1, MODE_INIT)
			x86_cpu_exec_reset()
			apic_init_reset()
			s->wait_for_sipi = true
IPI(CPU1, MODE_SMI)
			do_smm_enter()
			env->hflags |= HF_SMM_MASK;
IPI(CPU1, MODE_STARTUP, vector)
			do_cpu_sipi()
			apic_sipi()
			/* s->wait_for_sipi check passes */
			cpu_x86_load_seg_cache_sipi(vector)

A different sequence, SMI INIT SIPI, is also buggy in TCG because
INIT is not blocked or latched during SMM. However, it is not
vulnerable to an instruction pointer control in the same way because
x86_cpu_exec_reset clears env->hflags, exiting SMM.

Fixes: a9bad65d2c1f ("target-i386: wake up processors that receive an SMI")
Analyzed-by: YiFei Zhu <zhuyifei@google.com>
Cc: qemu-stable@nongnu.org
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
---
 hw/intc/apic.c                      | 2 --
 target/i386/helper.c                | 4 ++++
 target/i386/tcg/system/seg_helper.c | 1 +
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index 6d7859640c2..c7680338563 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -646,8 +646,6 @@ void apic_sipi(DeviceState *dev)
 {
     APICCommonState *s = APIC(dev);
 
-    cpu_reset_interrupt(CPU(s->cpu), CPU_INTERRUPT_SIPI);
-
     if (!s->wait_for_sipi)
         return;
     cpu_x86_load_seg_cache_sipi(s->cpu, s->sipi_vector);
diff --git a/target/i386/helper.c b/target/i386/helper.c
index 651041ccfa6..72b2e195a31 100644
--- a/target/i386/helper.c
+++ b/target/i386/helper.c
@@ -621,6 +621,10 @@ void do_cpu_init(X86CPU *cpu)
 
 void do_cpu_sipi(X86CPU *cpu)
 {
+    CPUX86State *env = &cpu->env;
+    if (env->hflags & HF_SMM_MASK) {
+        return;
+    }
     apic_sipi(cpu->apic_state);
 }
 
diff --git a/target/i386/tcg/system/seg_helper.c b/target/i386/tcg/system/seg_helper.c
index 38072e51d72..8c7856be81e 100644
--- a/target/i386/tcg/system/seg_helper.c
+++ b/target/i386/tcg/system/seg_helper.c
@@ -182,6 +182,7 @@ bool x86_cpu_exec_interrupt(CPUState *cs, int interrupt_request)
         apic_poll_irq(cpu->apic_state);
         break;
     case CPU_INTERRUPT_SIPI:
+        cpu_reset_interrupt(cs, CPU_INTERRUPT_SIPI);
         do_cpu_sipi(cpu);
         break;
     case CPU_INTERRUPT_SMI:
-- 
2.51.0
Re: [PULL 09/28] i386/cpu: Prevent delivering SIPI during SMM in TCG mode
Posted by Peter Maydell 3 weeks, 1 day ago
On Tue, 14 Oct 2025 at 14:38, Paolo Bonzini <pbonzini@redhat.com> wrote:
>
> [commit message by YiFei Zhu]
>
> A malicious kernel may control the instruction pointer in SMM in a
> multi-processor VM by sending a sequence of IPIs via APIC:
>
> CPU0                    CPU1
> IPI(CPU1, MODE_INIT)
>                         x86_cpu_exec_reset()
>                         apic_init_reset()
>                         s->wait_for_sipi = true
> IPI(CPU1, MODE_SMI)
>                         do_smm_enter()
>                         env->hflags |= HF_SMM_MASK;
> IPI(CPU1, MODE_STARTUP, vector)
>                         do_cpu_sipi()
>                         apic_sipi()
>                         /* s->wait_for_sipi check passes */
>                         cpu_x86_load_seg_cache_sipi(vector)
>
> A different sequence, SMI INIT SIPI, is also buggy in TCG because
> INIT is not blocked or latched during SMM. However, it is not
> vulnerable to an instruction pointer control in the same way because
> x86_cpu_exec_reset clears env->hflags, exiting SMM.
>
> Fixes: a9bad65d2c1f ("target-i386: wake up processors that receive an SMI")
> Analyzed-by: YiFei Zhu <zhuyifei@google.com>
> Cc: qemu-stable@nongnu.org
> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>

FYI, a bug report that just landed has bisected this commit
as the apparent cause of WHPX SMP boot no longer working:

https://gitlab.com/qemu-project/qemu/-/issues/3178

thanks
-- PMM