[3.13.y-ckt stable] Patch "x86/xen: Probe target addresses in set_aliased_prot() before the hypercall" has been added to staging queue

Kamal Mostafa kamal at canonical.com
Wed Sep 2 00:55:51 UTC 2015


This is a note to let you know that I have just added a patch titled

    x86/xen: Probe target addresses in set_aliased_prot() before the hypercall

to the linux-3.13.y-queue branch of the 3.13.y-ckt extended stable tree 
which can be found at:

    http://kernel.ubuntu.com/git/ubuntu/linux.git/log/?h=linux-3.13.y-queue

This patch is scheduled to be released in version 3.13.11-ckt26.

If you, or anyone else, feels it should not be added to this tree, please 
reply to this email.

For more information about the 3.13.y-ckt tree, see
https://wiki.ubuntu.com/Kernel/Dev/ExtendedStable

Thanks.
-Kamal

------

>From f93fdf9dea4a12083cdd7a962de939933f901053 Mon Sep 17 00:00:00 2001
From: Andy Lutomirski <luto at kernel.org>
Date: Thu, 30 Jul 2015 14:31:31 -0700
Subject: x86/xen: Probe target addresses in set_aliased_prot() before the
 hypercall

commit aa1acff356bbedfd03b544051f5b371746735d89 upstream.

The update_va_mapping hypercall can fail if the VA isn't present
in the guest's page tables.  Under certain loads, this can
result in an OOPS when the target address is in unpopulated vmap
space.

While we're at it, add comments to help explain what's going on.

This isn't a great long-term fix.  This code should probably be
changed to use something like set_memory_ro.

Signed-off-by: Andy Lutomirski <luto at kernel.org>
Cc: Andrew Cooper <andrew.cooper3 at citrix.com>
Cc: Andy Lutomirski <luto at amacapital.net>
Cc: Boris Ostrovsky <boris.ostrovsky at oracle.com>
Cc: Borislav Petkov <bp at alien8.de>
Cc: Brian Gerst <brgerst at gmail.com>
Cc: David Vrabel <dvrabel at cantab.net>
Cc: Denys Vlasenko <dvlasenk at redhat.com>
Cc: H. Peter Anvin <hpa at zytor.com>
Cc: Jan Beulich <jbeulich at suse.com>
Cc: Konrad Rzeszutek Wilk <konrad.wilk at oracle.com>
Cc: Linus Torvalds <torvalds at linux-foundation.org>
Cc: Peter Zijlstra <peterz at infradead.org>
Cc: Sasha Levin <sasha.levin at oracle.com>
Cc: Steven Rostedt <rostedt at goodmis.org>
Cc: Thomas Gleixner <tglx at linutronix.de>
Cc: security at kernel.org <security at kernel.org>
Cc: xen-devel <xen-devel at lists.xen.org>
Link: http://lkml.kernel.org/r/0b0e55b995cda11e7829f140b833ef932fcabe3a.1438291540.git.luto@kernel.org
Signed-off-by: Ingo Molnar <mingo at kernel.org>
Signed-off-by: Kamal Mostafa <kamal at canonical.com>
---
 arch/x86/xen/enlighten.c | 40 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 40 insertions(+)

diff --git a/arch/x86/xen/enlighten.c b/arch/x86/xen/enlighten.c
index fa6ade7..2cbc2f2 100644
--- a/arch/x86/xen/enlighten.c
+++ b/arch/x86/xen/enlighten.c
@@ -480,6 +480,7 @@ static void set_aliased_prot(void *v, pgprot_t prot)
 	pte_t pte;
 	unsigned long pfn;
 	struct page *page;
+	unsigned char dummy;

 	ptep = lookup_address((unsigned long)v, &level);
 	BUG_ON(ptep == NULL);
@@ -489,6 +490,32 @@ static void set_aliased_prot(void *v, pgprot_t prot)

 	pte = pfn_pte(pfn, prot);

+	/*
+	 * Careful: update_va_mapping() will fail if the virtual address
+	 * we're poking isn't populated in the page tables.  We don't
+	 * need to worry about the direct map (that's always in the page
+	 * tables), but we need to be careful about vmap space.  In
+	 * particular, the top level page table can lazily propagate
+	 * entries between processes, so if we've switched mms since we
+	 * vmapped the target in the first place, we might not have the
+	 * top-level page table entry populated.
+	 *
+	 * We disable preemption because we want the same mm active when
+	 * we probe the target and when we issue the hypercall.  We'll
+	 * have the same nominal mm, but if we're a kernel thread, lazy
+	 * mm dropping could change our pgd.
+	 *
+	 * Out of an abundance of caution, this uses __get_user() to fault
+	 * in the target address just in case there's some obscure case
+	 * in which the target address isn't readable.
+	 */
+
+	preempt_disable();
+
+	pagefault_disable();	/* Avoid warnings due to being atomic. */
+	__get_user(dummy, (unsigned char __user __force *)v);
+	pagefault_enable();
+
 	if (HYPERVISOR_update_va_mapping((unsigned long)v, pte, 0))
 		BUG();

@@ -500,6 +527,8 @@ static void set_aliased_prot(void *v, pgprot_t prot)
 				BUG();
 	} else
 		kmap_flush_unused();
+
+	preempt_enable();
 }

 static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
@@ -507,6 +536,17 @@ static void xen_alloc_ldt(struct desc_struct *ldt, unsigned entries)
 	const unsigned entries_per_page = PAGE_SIZE / LDT_ENTRY_SIZE;
 	int i;

+	/*
+	 * We need to mark the all aliases of the LDT pages RO.  We
+	 * don't need to call vm_flush_aliases(), though, since that's
+	 * only responsible for flushing aliases out the TLBs, not the
+	 * page tables, and Xen will flush the TLB for us if needed.
+	 *
+	 * To avoid confusing future readers: none of this is necessary
+	 * to load the LDT.  The hypervisor only checks this when the
+	 * LDT is faulted in due to subsequent descriptor access.
+	 */
+
 	for(i = 0; i < entries; i += entries_per_page)
 		set_aliased_prot(ldt + i, PAGE_KERNEL_RO);
 }
--
1.9.1





More information about the kernel-team mailing list