]> xenbits.xensource.com Git - people/iwj/xen.git/commitdiff
x86/cpu: Fix IST handling during PCPU bringup
authorAndrew Cooper <andrew.cooper3@citrix.com>
Thu, 12 Oct 2017 12:50:31 +0000 (14:50 +0200)
committerJan Beulich <jbeulich@suse.com>
Thu, 12 Oct 2017 12:50:31 +0000 (14:50 +0200)
Clear IST references in newly allocated IDTs.  Nothing good will come of
having them set before the TSS is suitably constructed (although the chances
of the CPU surviving such an IST interrupt/exception is extremely slim).

Uniformly set the IST references after the TSS is in place.  This fixes an
issue on AMD hardware, where onlining a PCPU while PCPU0 is in HVM context
will cause IST_NONE to be copied into the new IDT, making that PCPU vulnerable
to privilege escalation from PV guests until it subsequently schedules an HVM
guest.

This is XSA-244.

Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
xen/arch/x86/cpu/common.c
xen/arch/x86/smpboot.c

index 78f56671e7e6879fa3aaef9a756c644644dc775d..6cf362849e85fc871d4274d19610ef044a61517c 100644 (file)
@@ -640,6 +640,7 @@ void __init early_cpu_init(void)
  * - Sets up TSS with stack pointers, including ISTs
  * - Inserts TSS selector into regular and compat GDTs
  * - Loads GDT, IDT, TR then null LDT
+ * - Sets up IST references in the IDT
  */
 void load_system_tables(void)
 {
@@ -702,6 +703,10 @@ void load_system_tables(void)
        asm volatile ("ltr  %w0" : : "rm" (TSS_ENTRY << 3) );
        asm volatile ("lldt %w0" : : "rm" (0) );
 
+       set_ist(&idt_tables[cpu][TRAP_double_fault],  IST_DF);
+       set_ist(&idt_tables[cpu][TRAP_nmi],           IST_NMI);
+       set_ist(&idt_tables[cpu][TRAP_machine_check], IST_MCE);
+
        /*
         * Bottom-of-stack must be 16-byte aligned!
         *
index 3ca716c59ff82a721c1f1447c2a172d94679cdb3..1609b627ae4a2257ccc21ed578b2db173acf31bf 100644 (file)
@@ -724,6 +724,9 @@ static int cpu_smpboot_alloc(unsigned int cpu)
     if ( idt_tables[cpu] == NULL )
         goto oom;
     memcpy(idt_tables[cpu], idt_table, IDT_ENTRIES * sizeof(idt_entry_t));
+    set_ist(&idt_tables[cpu][TRAP_double_fault],  IST_NONE);
+    set_ist(&idt_tables[cpu][TRAP_nmi],           IST_NONE);
+    set_ist(&idt_tables[cpu][TRAP_machine_check], IST_NONE);
 
     for ( stub_page = 0, i = cpu & ~(STUBS_PER_PAGE - 1);
           i < nr_cpu_ids && i <= (cpu | (STUBS_PER_PAGE - 1)); ++i )