From: Paolo Bonzini <[email protected]>

[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 <[email protected]>
Cc: [email protected]
Signed-off-by: Paolo Bonzini <[email protected]>
(cherry picked from commit df32e5c568c9cf68c15a9bbd98d0c3aff19eab63)
Signed-off-by: Michael Tokarev <[email protected]>

diff --git a/hw/intc/apic.c b/hw/intc/apic.c
index a7c2b301a8..315bef8f43 100644
--- a/hw/intc/apic.c
+++ b/hw/intc/apic.c
@@ -499,8 +499,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 290d9d309c..723f50279a 100644
--- a/target/i386/helper.c
+++ b/target/i386/helper.c
@@ -602,6 +602,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);
 }
 #else
diff --git a/target/i386/tcg/sysemu/seg_helper.c 
b/target/i386/tcg/sysemu/seg_helper.c
index 2c9bd007ad..8294a668d6 100644
--- a/target/i386/tcg/sysemu/seg_helper.c
+++ b/target/i386/tcg/sysemu/seg_helper.c
@@ -146,6 +146,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.47.3


Reply via email to