summaryrefslogtreecommitdiff
path: root/xsa286-3.patch
diff options
context:
space:
mode:
Diffstat (limited to 'xsa286-3.patch')
-rw-r--r--xsa286-3.patch81
1 files changed, 81 insertions, 0 deletions
diff --git a/xsa286-3.patch b/xsa286-3.patch
new file mode 100644
index 0000000..2b0f703
--- /dev/null
+++ b/xsa286-3.patch
@@ -0,0 +1,81 @@
+x86/mm: avoid using linear page tables in map_guest_l1e()
+
+Replace the linear L2 table access by an actual page walk.
+
+This is part of XSA-286.
+
+Signed-off-by: Jan Beulich <jbeulich@suse.com>
+Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
+Reviewed-by: George Dunlap <george.dunlap@citrix.com>
+Reviewed-by: Andrew Cooper <andrew.cooper3@citrix.com>
+
+--- a/xen/arch/x86/pv/mm.c
++++ b/xen/arch/x86/pv/mm.c
+@@ -40,11 +40,14 @@ l1_pgentry_t *map_guest_l1e(unsigned lon
+ if ( unlikely(!__addr_ok(linear)) )
+ return NULL;
+
+- /* Find this l1e and its enclosing l1mfn in the linear map. */
+- if ( __copy_from_user(&l2e,
+- &__linear_l2_table[l2_linear_offset(linear)],
+- sizeof(l2_pgentry_t)) )
++ if ( unlikely(!(current->arch.flags & TF_kernel_mode)) )
++ {
++ ASSERT_UNREACHABLE();
+ return NULL;
++ }
++
++ /* Find this l1e and its enclosing l1mfn. */
++ l2e = page_walk_get_l2e(current->arch.guest_table, linear);
+
+ /* Check flags that it will be safe to read the l1e. */
+ if ( (l2e_get_flags(l2e) & (_PAGE_PRESENT | _PAGE_PSE)) != _PAGE_PRESENT )
+--- a/xen/arch/x86/x86_64/mm.c
++++ b/xen/arch/x86/x86_64/mm.c
+@@ -100,6 +100,34 @@ static l3_pgentry_t page_walk_get_l3e(pa
+ return l3e;
+ }
+
++l2_pgentry_t page_walk_get_l2e(pagetable_t root, unsigned long addr)
++{
++ l3_pgentry_t l3e = page_walk_get_l3e(root, addr);
++ mfn_t mfn = l3e_get_mfn(l3e);
++ struct page_info *pg;
++ l2_pgentry_t l2e = l2e_empty();
++
++ if ( !(l3e_get_flags(l3e) & _PAGE_PRESENT) ||
++ (l3e_get_flags(l3e) & _PAGE_PSE) )
++ return l2e_empty();
++
++ pg = mfn_to_page(mfn);
++ if ( !page_lock(pg) )
++ return l2e_empty();
++
++ if ( (pg->u.inuse.type_info & PGT_type_mask) == PGT_l2_page_table )
++ {
++ l2_pgentry_t *l2t = map_domain_page(mfn);
++
++ l2e = l2t[l2_table_offset(addr)];
++ unmap_domain_page(l2t);
++ }
++
++ page_unlock(pg);
++
++ return l2e;
++}
++
+ void *do_page_walk(struct vcpu *v, unsigned long addr)
+ {
+ l3_pgentry_t l3e;
+--- a/xen/include/asm-x86/mm.h
++++ b/xen/include/asm-x86/mm.h
+@@ -577,7 +577,9 @@ void audit_domains(void);
+ void make_cr3(struct vcpu *v, mfn_t mfn);
+ void update_cr3(struct vcpu *v);
+ int vcpu_destroy_pagetables(struct vcpu *);
++
+ void *do_page_walk(struct vcpu *v, unsigned long addr);
++l2_pgentry_t page_walk_get_l2e(pagetable_t root, unsigned long addr);
+
+ int __sync_local_execstate(void);
+