]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blobdiff - src/patches/suse-2.6.27.31/patches.arch/s390-08-09-switch-amode-off.patch
Move xen patchset to new version's subdir.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.arch / s390-08-09-switch-amode-off.patch
diff --git a/src/patches/suse-2.6.27.31/patches.arch/s390-08-09-switch-amode-off.patch b/src/patches/suse-2.6.27.31/patches.arch/s390-08-09-switch-amode-off.patch
new file mode 100644 (file)
index 0000000..6d89bcd
--- /dev/null
@@ -0,0 +1,143 @@
+From: Gerald Schaefer <geraldsc@de.ibm.com>
+Subject: kernel: Fix user copy functions (pagetable walk) with KERNEL_DS.
+References: bnc#466462
+
+Symptom:     Kernel OOPS / system hang on user program core dump on pre z9
+             hardware.
+Problem:     Passing incorrect addresses to user copy functions is not handled
+             correctly when address spaces are switched and KERNEL_DS is set.
+Solution:    Verify addresses by handling KERNEL_DS case in the same way as
+             USER_DS (pagetable walk). Also disable switch_amode by default
+             because pagetable walk has negative performance impact.
+
+Acked-by: John Jolly <jjolly@suse.de>
+---
+ arch/s390/kernel/setup.c   |    4 ----
+ arch/s390/lib/uaccess_pt.c |   32 +++++++-------------------------
+ arch/s390/mm/pgtable.c     |    4 ++++
+ 3 files changed, 11 insertions(+), 29 deletions(-)
+
+Index: linux-sles11/arch/s390/kernel/setup.c
+===================================================================
+--- linux-sles11.orig/arch/s390/kernel/setup.c
++++ linux-sles11/arch/s390/kernel/setup.c
+@@ -285,11 +285,7 @@ static int __init early_parse_mem(char *
+ early_param("mem", early_parse_mem);
+ #ifdef CONFIG_S390_SWITCH_AMODE
+-#ifdef CONFIG_PGSTE
+-unsigned int switch_amode = 1;
+-#else
+ unsigned int switch_amode = 0;
+-#endif
+ EXPORT_SYMBOL_GPL(switch_amode);
+ static int set_amode_and_uaccess(unsigned long user_amode,
+Index: linux-sles11/arch/s390/mm/pgtable.c
+===================================================================
+--- linux-sles11.orig/arch/s390/mm/pgtable.c
++++ linux-sles11/arch/s390/mm/pgtable.c
+@@ -256,6 +256,10 @@ int s390_enable_sie(void)
+       struct task_struct *tsk = current;
+       struct mm_struct *mm, *old_mm;
++      /* Do we have switched amode? If no, we cannot do sie */
++      if (!switch_amode)
++              return -EINVAL;
++
+       /* Do we have pgstes? if yes, we are done */
+       if (tsk->mm->context.pgstes)
+               return 0;
+Index: linux-sles11/arch/s390/lib/uaccess_pt.c
+===================================================================
+--- linux-sles11.orig/arch/s390/lib/uaccess_pt.c
++++ linux-sles11/arch/s390/lib/uaccess_pt.c
+@@ -43,8 +43,9 @@ static int __handle_fault(struct mm_stru
+       int ret = -EFAULT;
+       int fault;
+-      if (in_atomic())
++      if (in_atomic() || segment_eq(get_fs(), KERNEL_DS))
+               return ret;
++
+       down_read(&mm->mmap_sem);
+       vma = find_vma(mm, address);
+       if (unlikely(!vma))
+@@ -109,6 +110,8 @@ static size_t __user_copy_pt(unsigned lo
+       pte_t *pte;
+       void *from, *to;
++      if (segment_eq(get_fs(), KERNEL_DS))
++              mm = &init_mm;
+       done = 0;
+ retry:
+       spin_lock(&mm->page_table_lock);
+@@ -182,10 +185,6 @@ size_t copy_from_user_pt(size_t n, const
+ {
+       size_t rc;
+-      if (segment_eq(get_fs(), KERNEL_DS)) {
+-              memcpy(to, (void __kernel __force *) from, n);
+-              return 0;
+-      }
+       rc = __user_copy_pt((unsigned long) from, to, n, 0);
+       if (unlikely(rc))
+               memset(to + n - rc, 0, rc);
+@@ -194,10 +193,6 @@ size_t copy_from_user_pt(size_t n, const
+ size_t copy_to_user_pt(size_t n, void __user *to, const void *from)
+ {
+-      if (segment_eq(get_fs(), KERNEL_DS)) {
+-              memcpy((void __kernel __force *) to, from, n);
+-              return 0;
+-      }
+       return __user_copy_pt((unsigned long) to, (void *) from, n, 1);
+ }
+@@ -205,10 +200,6 @@ static size_t clear_user_pt(size_t n, vo
+ {
+       long done, size, ret;
+-      if (segment_eq(get_fs(), KERNEL_DS)) {
+-              memset((void __kernel __force *) to, 0, n);
+-              return 0;
+-      }
+       done = 0;
+       do {
+               if (n - done > PAGE_SIZE)
+@@ -234,7 +225,7 @@ static size_t strnlen_user_pt(size_t cou
+       size_t len_str;
+       if (segment_eq(get_fs(), KERNEL_DS))
+-              return strnlen((const char __kernel __force *) src, count) + 1;
++              mm = &init_mm;
+       done = 0;
+ retry:
+       spin_lock(&mm->page_table_lock);
+@@ -276,13 +267,6 @@ static size_t strncpy_from_user_pt(size_
+               return -EFAULT;
+       if (n > count)
+               n = count;
+-      if (segment_eq(get_fs(), KERNEL_DS)) {
+-              memcpy(dst, (const char __kernel __force *) src, n);
+-              if (dst[n-1] == '\0')
+-                      return n-1;
+-              else
+-                      return n;
+-      }
+       if (__user_copy_pt((unsigned long) src, dst, n, 0))
+               return -EFAULT;
+       if (dst[n-1] == '\0')
+@@ -302,10 +286,8 @@ static size_t copy_in_user_pt(size_t n,
+       pte_t *pte_from, *pte_to;
+       int write_user;
+-      if (segment_eq(get_fs(), KERNEL_DS)) {
+-              memcpy((void __force *) to, (void __force *) from, n);
+-              return 0;
+-      }
++      if (segment_eq(get_fs(), KERNEL_DS))
++              mm = &init_mm;
+       done = 0;
+ retry:
+       spin_lock(&mm->page_table_lock);