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

[Xen-changelog] [xen stable-4.9] x86/mm: fix race conditions in map_pages_to_xen()



commit 80eeaab09a1134f34c3c6912a8acb0c43c7c3ef7
Author:     Min He <min.he@xxxxxxxxx>
AuthorDate: Thu Nov 16 11:46:07 2017 +0100
Commit:     Jan Beulich <jbeulich@xxxxxxxx>
CommitDate: Thu Nov 16 11:46:07 2017 +0100

    x86/mm: fix race conditions in map_pages_to_xen()
    
    In map_pages_to_xen(), a L2 page table entry may be reset to point to
    a superpage, and its corresponding L1 page table need be freed in such
    scenario, when these L1 page table entries are mapping to consecutive
    page frames and having the same mapping flags.
    
    However, variable `pl1e` is not protected by the lock before L1 page table
    is enumerated. A race condition may happen if this code path is invoked
    simultaneously on different CPUs.
    
    For example, `pl1e` value on CPU0 may hold an obsolete value, pointing
    to a page which has just been freed on CPU1. Besides, before this page
    is reused, it will still be holding the old PTEs, referencing consecutive
    page frames. Consequently the `free_xen_pagetable(l2e_to_l1e(ol2e))` will
    be triggered on CPU0, resulting the unexpected free of a normal page.
    
    This patch fixes the above problem by protecting the `pl1e` with the lock.
    
    Also, there're other potential race conditions. For instance, the L2/L3
    entry may be modified concurrently on different CPUs, by routines such as
    map_pages_to_xen(), modify_xen_mappings() etc. To fix this, this patch will
    check the _PAGE_PRESENT and _PAGE_PSE flags, after the spinlock is obtained,
    for the corresponding L2/L3 entry.
    
    Signed-off-by: Min He <min.he@xxxxxxxxx>
    Signed-off-by: Yi Zhang <yi.z.zhang@xxxxxxxxx>
    Signed-off-by: Yu Zhang <yu.c.zhang@xxxxxxxxxxxxxxx>
    Reviewed-by: Jan Beulich <jbeulich@xxxxxxxx>
    master commit: a5114662297ad03efc36b52ad365ffa05fb357b7
    master date: 2017-11-14 17:10:56 +0100
---
 xen/arch/x86/mm.c | 36 ++++++++++++++++++++++++++++++++++--
 1 file changed, 34 insertions(+), 2 deletions(-)

diff --git a/xen/arch/x86/mm.c b/xen/arch/x86/mm.c
index 9e491a3..3641f0d 100644
--- a/xen/arch/x86/mm.c
+++ b/xen/arch/x86/mm.c
@@ -6285,9 +6285,29 @@ int map_pages_to_xen(
             {
                 unsigned long base_mfn;
 
-                pl1e = l2e_to_l1e(*pl2e);
                 if ( locking )
                     spin_lock(&map_pgdir_lock);
+
+                ol2e = *pl2e;
+                /*
+                 * L2E may be already cleared, or set to a superpage, by
+                 * concurrent paging structure modifications on other CPUs.
+                 */
+                if ( !(l2e_get_flags(ol2e) & _PAGE_PRESENT) )
+                {
+                    if ( locking )
+                        spin_unlock(&map_pgdir_lock);
+                    continue;
+                }
+
+                if ( l2e_get_flags(ol2e) & _PAGE_PSE )
+                {
+                    if ( locking )
+                        spin_unlock(&map_pgdir_lock);
+                    goto check_l3;
+                }
+
+                pl1e = l2e_to_l1e(ol2e);
                 base_mfn = l1e_get_pfn(*pl1e) & ~(L1_PAGETABLE_ENTRIES - 1);
                 for ( i = 0; i < L1_PAGETABLE_ENTRIES; i++, pl1e++ )
                     if ( (l1e_get_pfn(*pl1e) != (base_mfn + i)) ||
@@ -6295,7 +6315,6 @@ int map_pages_to_xen(
                         break;
                 if ( i == L1_PAGETABLE_ENTRIES )
                 {
-                    ol2e = *pl2e;
                     l2e_write_atomic(pl2e, l2e_from_pfn(base_mfn,
                                                         l1f_to_lNf(flags)));
                     if ( locking )
@@ -6321,7 +6340,20 @@ int map_pages_to_xen(
 
             if ( locking )
                 spin_lock(&map_pgdir_lock);
+
             ol3e = *pl3e;
+            /*
+             * L3E may be already cleared, or set to a superpage, by
+             * concurrent paging structure modifications on other CPUs.
+             */
+            if ( !(l3e_get_flags(ol3e) & _PAGE_PRESENT) ||
+                (l3e_get_flags(ol3e) & _PAGE_PSE) )
+            {
+                if ( locking )
+                    spin_unlock(&map_pgdir_lock);
+                continue;
+            }
+
             pl2e = l3e_to_l2e(ol3e);
             base_mfn = l2e_get_pfn(*pl2e) & ~(L2_PAGETABLE_ENTRIES *
                                               L1_PAGETABLE_ENTRIES - 1);
--
generated by git-patchbot for /home/xen/git/xen.git#stable-4.9

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxx
https://lists.xenproject.org/xen-changelog

 


Rackspace

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