]> err.no Git - linux-2.6/commitdiff
[S390] uaccess: Always access the correct address space.
authorHeiko Carstens <heiko.carstens@de.ibm.com>
Thu, 17 Apr 2008 05:46:27 +0000 (07:46 +0200)
committerHeiko Carstens <heiko.carstens@de.ibm.com>
Thu, 17 Apr 2008 05:47:06 +0000 (07:47 +0200)
The current uaccess page table walk code assumes at a few places that
any access is a user space access. This is not correct if somebody
has issued a set_fs(KERNEL_DS) in advance.
Add code which checks which address space we are in and with this make
sure we access the correct address space. This way we get also rid of
the dirty
if (!currrent-mm)
return -EFAULT;
hack in futex_atomic_cmpxchg_pt.

Signed-off-by: Martin Schwidefsky <schwidefsky@de.ibm.com>
Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
arch/s390/lib/uaccess_pt.c

index 5efdfe9f5e769732a17ca2b60bcee062f408e38b..d66215b0fde9d8d932cd31a43b3dee2e283b3a4a 100644 (file)
@@ -302,6 +302,10 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
        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;
+       }
        done = 0;
 retry:
        spin_lock(&mm->page_table_lock);
@@ -361,18 +365,10 @@ fault:
                     : "0" (-EFAULT), "d" (oparg), "a" (uaddr),         \
                       "m" (*uaddr) : "cc" );
 
-int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
+static int __futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
 {
        int oldval = 0, newval, ret;
 
-       spin_lock(&current->mm->page_table_lock);
-       uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
-       if (!uaddr) {
-               spin_unlock(&current->mm->page_table_lock);
-               return -EFAULT;
-       }
-       get_page(virt_to_page(uaddr));
-       spin_unlock(&current->mm->page_table_lock);
        switch (op) {
        case FUTEX_OP_SET:
                __futex_atomic_op("lr %2,%5\n",
@@ -397,17 +393,17 @@ int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
        default:
                ret = -ENOSYS;
        }
-       put_page(virt_to_page(uaddr));
-       *old = oldval;
+       if (ret == 0)
+               *old = oldval;
        return ret;
 }
 
-int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+int futex_atomic_op_pt(int op, int __user *uaddr, int oparg, int *old)
 {
        int ret;
 
-       if (!current->mm)
-               return -EFAULT;
+       if (segment_eq(get_fs(), KERNEL_DS))
+               return __futex_atomic_op_pt(op, uaddr, oparg, old);
        spin_lock(&current->mm->page_table_lock);
        uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
        if (!uaddr) {
@@ -416,13 +412,40 @@ int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
        }
        get_page(virt_to_page(uaddr));
        spin_unlock(&current->mm->page_table_lock);
-       asm volatile("   cs   %1,%4,0(%5)\n"
-                    "0: lr   %0,%1\n"
-                    "1:\n"
-                    EX_TABLE(0b,1b)
+       ret = __futex_atomic_op_pt(op, uaddr, oparg, old);
+       put_page(virt_to_page(uaddr));
+       return ret;
+}
+
+static int __futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+{
+       int ret;
+
+       asm volatile("0: cs   %1,%4,0(%5)\n"
+                    "1: lr   %0,%1\n"
+                    "2:\n"
+                    EX_TABLE(0b,2b) EX_TABLE(1b,2b)
                     : "=d" (ret), "+d" (oldval), "=m" (*uaddr)
                     : "0" (-EFAULT), "d" (newval), "a" (uaddr), "m" (*uaddr)
                     : "cc", "memory" );
+       return ret;
+}
+
+int futex_atomic_cmpxchg_pt(int __user *uaddr, int oldval, int newval)
+{
+       int ret;
+
+       if (segment_eq(get_fs(), KERNEL_DS))
+               return __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
+       spin_lock(&current->mm->page_table_lock);
+       uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr);
+       if (!uaddr) {
+               spin_unlock(&current->mm->page_table_lock);
+               return -EFAULT;
+       }
+       get_page(virt_to_page(uaddr));
+       spin_unlock(&current->mm->page_table_lock);
+       ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval);
        put_page(virt_to_page(uaddr));
        return ret;
 }