[PATCH 3.12 48/82] x86/xen: Probe target addresses in set_aliased_prot() before the hypercall
From: Andy Lutomirski 3.12-stable review patch. If anyone has any objections, please let me know. === 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 Cc: Andrew Cooper Cc: Andy Lutomirski Cc: Boris Ostrovsky Cc: Borislav Petkov Cc: Brian Gerst Cc: David Vrabel Cc: Denys Vlasenko Cc: H. Peter Anvin Cc: Jan Beulich Cc: Konrad Rzeszutek Wilk Cc: Linus Torvalds Cc: Peter Zijlstra Cc: Sasha Levin Cc: Steven Rostedt Cc: Thomas Gleixner Cc: secur...@kernel.org Cc: xen-devel Link: http://lkml.kernel.org/r/0b0e55b995cda11e7829f140b833ef932fcabe3a.1438291540.git.l...@kernel.org Signed-off-by: Ingo Molnar Signed-off-by: Jiri Slaby --- 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 fa6ade76ef3f..2cbc2f2cf43e 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, ); 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); } -- 2.5.0 -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH 3.12 48/82] x86/xen: Probe target addresses in set_aliased_prot() before the hypercall
From: Andy Lutomirski l...@kernel.org 3.12-stable review patch. If anyone has any objections, please let me know. === 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 l...@kernel.org Cc: Andrew Cooper andrew.coop...@citrix.com Cc: Andy Lutomirski l...@amacapital.net Cc: Boris Ostrovsky boris.ostrov...@oracle.com Cc: Borislav Petkov b...@alien8.de Cc: Brian Gerst brge...@gmail.com Cc: David Vrabel dvra...@cantab.net Cc: Denys Vlasenko dvlas...@redhat.com Cc: H. Peter Anvin h...@zytor.com Cc: Jan Beulich jbeul...@suse.com Cc: Konrad Rzeszutek Wilk konrad.w...@oracle.com Cc: Linus Torvalds torva...@linux-foundation.org Cc: Peter Zijlstra pet...@infradead.org Cc: Sasha Levin sasha.le...@oracle.com Cc: Steven Rostedt rost...@goodmis.org Cc: Thomas Gleixner t...@linutronix.de Cc: secur...@kernel.org secur...@kernel.org Cc: xen-devel xen-de...@lists.xen.org Link: http://lkml.kernel.org/r/0b0e55b995cda11e7829f140b833ef932fcabe3a.1438291540.git.l...@kernel.org Signed-off-by: Ingo Molnar mi...@kernel.org Signed-off-by: Jiri Slaby jsl...@suse.cz --- 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 fa6ade76ef3f..2cbc2f2cf43e 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); } -- 2.5.0 -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/