[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen stable-4.4] x86: don't crash when mapping a page using EFI runtime page tables



commit c76aeb51249fcce1a524d4102b71812744112645
Author:     Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
AuthorDate: Thu Jun 18 09:28:37 2015 +0200
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu Jun 18 09:28:37 2015 +0200

    x86: don't crash when mapping a page using EFI runtime page tables
    
    When an interrupt is received during an EFI runtime service call, Xen
    may call map_domain_page() while using the EFI runtime page tables.
    This fails because, although the EFI runtime page tables are a
    copy of the idle domain's page tables, current points at a different
    domain's vCPU.
    
    To fix this, return NULL from mapcache_current_vcpu() when using the EFI
    runtime page tables which is treated equivalently to running in an idle
    vCPU.
    
    This issue can be reproduced by repeatedly calling GetVariable() from
    dom0 while using VT-d, since VT-d frequently maps a page from interrupt
    context.
    
    Example call trace:
    [<ffff82d0801615dc>] __find_next_zero_bit+0x28/0x60
    [<ffff82d08016a10e>] map_domain_page+0x4c6/0x4eb
    [<ffff82d080156ae6>] map_vtd_domain_page+0xd/0xf
    [<ffff82d08015533a>] msi_msg_read_remap_rte+0xe3/0x1d8
    [<ffff82d08014e516>] iommu_read_msi_from_ire+0x31/0x34
    [<ffff82d08016ff6c>] set_msi_affinity+0x134/0x17a
    [<ffff82d0801737b5>] move_masked_irq+0x5c/0x98
    [<ffff82d080173816>] move_native_irq+0x25/0x36
    [<ffff82d08016ffcb>] ack_nonmaskable_msi_irq+0x19/0x20
    [<ffff82d08016ffdb>] ack_maskable_msi_irq+0x9/0x37
    [<ffff82d080173e8b>] do_IRQ+0x251/0x635
    [<ffff82d080234502>] common_interrupt+0x62/0x70
    [<00000000df7ed2be>] 00000000df7ed2be
    
    Signed-off-by: Ross Lagerwall <ross.lagerwall@xxxxxxxxxx>
    master commit: 591e1e357c29589e9d6121d8faadc4f4d3b9013e
    master date: 2015-06-01 11:59:14 +0200
---
 xen/arch/x86/domain_page.c |   13 +++++++++----
 xen/arch/x86/efi/runtime.c |   10 ++++++++--
 xen/arch/x86/efi/stub.c    |    2 +-
 xen/include/xen/efi.h      |    2 +-
 4 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/xen/arch/x86/domain_page.c b/xen/arch/x86/domain_page.c
index 158a164..9bdab61 100644
--- a/xen/arch/x86/domain_page.c
+++ b/xen/arch/x86/domain_page.c
@@ -32,20 +32,25 @@ static inline struct vcpu *mapcache_current_vcpu(void)
         return NULL;
 
     /*
+     * When using efi runtime page tables, we have the equivalent of the idle
+     * domain's page tables but current may point at another domain's VCPU.
+     * Return NULL as though current is not properly set up yet.
+     */
+    if ( efi_enabled && efi_rs_using_pgtables() )
+        return NULL;
+
+    /*
      * If guest_table is NULL, and we are running a paravirtualised guest,
      * then it means we are running on the idle domain's page table and must
      * therefore use its mapcache.
      */
     if ( unlikely(pagetable_is_null(v->arch.guest_table)) && is_pv_vcpu(v) )
     {
-        unsigned long cr3;
-
         /* If we really are idling, perform lazy context switch now. */
         if ( (v = idle_vcpu[smp_processor_id()]) == current )
             sync_local_execstate();
         /* We must now be running on the idle page table. */
-        ASSERT((cr3 = read_cr3()) == __pa(idle_pg_table) ||
-               (efi_enabled && cr3 == efi_rs_page_table()));
+        ASSERT(read_cr3() == __pa(idle_pg_table));
     }
 
     return v;
diff --git a/xen/arch/x86/efi/runtime.c b/xen/arch/x86/efi/runtime.c
index 441ec90..fe851d9 100644
--- a/xen/arch/x86/efi/runtime.c
+++ b/xen/arch/x86/efi/runtime.c
@@ -26,6 +26,7 @@ const CHAR16 *__read_mostly efi_fw_vendor;
 
 EFI_RUNTIME_SERVICES *__read_mostly efi_rs;
 static DEFINE_SPINLOCK(efi_rs_lock);
+static unsigned int efi_rs_on_cpu = NR_CPUS;
 
 UINTN __read_mostly efi_memmap_size;
 UINTN __read_mostly efi_mdesc_size;
@@ -67,6 +68,8 @@ unsigned long efi_rs_enter(void)
 
     spin_lock(&efi_rs_lock);
 
+    efi_rs_on_cpu = smp_processor_id();
+
     /* prevent fixup_page_fault() from doing anything */
     irq_enter();
 
@@ -101,13 +104,16 @@ void efi_rs_leave(unsigned long cr3)
         asm volatile ( "lgdt %0" : : "m" (gdt_desc) );
     }
     irq_exit();
+    efi_rs_on_cpu = NR_CPUS;
     spin_unlock(&efi_rs_lock);
     stts();
 }
 
-paddr_t efi_rs_page_table(void)
+bool_t efi_rs_using_pgtables(void)
 {
-    return efi_l4_pgtable ? virt_to_maddr(efi_l4_pgtable) : 0;
+    return efi_l4_pgtable &&
+           (smp_processor_id() == efi_rs_on_cpu) &&
+           (read_cr3() == virt_to_maddr(efi_l4_pgtable));
 }
 
 unsigned long efi_get_time(void)
diff --git a/xen/arch/x86/efi/stub.c b/xen/arch/x86/efi/stub.c
index 627009f..07c2bd0 100644
--- a/xen/arch/x86/efi/stub.c
+++ b/xen/arch/x86/efi/stub.c
@@ -12,7 +12,7 @@ void __init efi_init_memory(void) { }
 
 void efi_update_l4_pgtable(unsigned int l4idx, l4_pgentry_t l4e) { }
 
-paddr_t efi_rs_page_table(void)
+bool_t efi_rs_using_pgtables(void)
 {
     BUG();
     return 0;
diff --git a/xen/include/xen/efi.h b/xen/include/xen/efi.h
index 5e02724..f2782ce 100644
--- a/xen/include/xen/efi.h
+++ b/xen/include/xen/efi.h
@@ -28,7 +28,7 @@ struct xenpf_efi_runtime_call;
 struct compat_pf_efi_runtime_call;
 
 void efi_init_memory(void);
-paddr_t efi_rs_page_table(void);
+bool_t efi_rs_using_pgtables(void);
 unsigned long efi_get_time(void);
 void efi_halt_system(void);
 void efi_reset_system(bool_t warm);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.4

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.