From: Julian Stecklina <jstec...@amazon.de>

Only the xpfo_kunmap call that needs to actually unmap the page
needs to be serialized. We need to be careful to handle the case,
where after the atomic decrement of the mapcount, a xpfo_kmap
increased the mapcount again. In this case, we can safely skip
modifying the page table.

Model-checked with up to 4 concurrent callers with Spin.

Signed-off-by: Julian Stecklina <jstec...@amazon.de>
Cc: x...@kernel.org
Cc: kernel-harden...@lists.openwall.com
Cc: Vasileios P. Kemerlis <v...@cs.columbia.edu>
Cc: Juerg Haefliger <juerg.haefli...@canonical.com>
Cc: Tycho Andersen <ty...@docker.com>
Cc: Marco Benatto <marco.antonio....@gmail.com>
Cc: David Woodhouse <dw...@infradead.org>
Signed-off-by: Khalid Aziz <khalid.a...@oracle.com>
---
 mm/xpfo.c | 22 ++++++++++++----------
 1 file changed, 12 insertions(+), 10 deletions(-)

diff --git a/mm/xpfo.c b/mm/xpfo.c
index cbfeafc2f10f..dbf20efb0499 100644
--- a/mm/xpfo.c
+++ b/mm/xpfo.c
@@ -149,22 +149,24 @@ void xpfo_kunmap(void *kaddr, struct page *page)
        if (!PageXpfoUser(page))
                return;
 
-       spin_lock(&page->xpfo_lock);
-
        /*
         * The page is to be allocated back to user space, so unmap it from the
         * kernel, flush the TLB and tag it as a user page.
         */
        if (atomic_dec_return(&page->xpfo_mapcount) == 0) {
-#ifdef CONFIG_XPFO_DEBUG
-               BUG_ON(PageXpfoUnmapped(page));
-#endif
-               SetPageXpfoUnmapped(page);
-               set_kpte(kaddr, page, __pgprot(0));
-               xpfo_cond_flush_kernel_tlb(page, 0);
-       }
+               spin_lock(&page->xpfo_lock);
 
-       spin_unlock(&page->xpfo_lock);
+               /*
+                * In the case, where we raced with kmap after the
+                * atomic_dec_return, we must not nuke the mapping.
+                */
+               if (atomic_read(&page->xpfo_mapcount) == 0) {
+                       SetPageXpfoUnmapped(page);
+                       set_kpte(kaddr, page, __pgprot(0));
+                       xpfo_cond_flush_kernel_tlb(page, 0);
+               }
+               spin_unlock(&page->xpfo_lock);
+       }
 }
 EXPORT_SYMBOL(xpfo_kunmap);
 
-- 
2.17.1

Reply via email to