From 3f12ebce6a004c8e9bf639801842f67e578ee7c6 Mon Sep 17 00:00:00 2001 From: Heiko Carstens Date: Thu, 17 Apr 2008 07:46:27 +0200 Subject: [PATCH] [S390] uaccess: Always access the correct address space. 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 Signed-off-by: Heiko Carstens --- arch/s390/lib/uaccess_pt.c | 59 ++++++++++++++++++++++++++------------ 1 file changed, 41 insertions(+), 18 deletions(-) diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 5efdfe9f5e7..d66215b0fde 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -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(¤t->mm->page_table_lock); - uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); - if (!uaddr) { - spin_unlock(¤t->mm->page_table_lock); - return -EFAULT; - } - get_page(virt_to_page(uaddr)); - spin_unlock(¤t->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(¤t->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(¤t->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(¤t->mm->page_table_lock); + uaddr = (int __user *) __dat_user_addr((unsigned long) uaddr); + if (!uaddr) { + spin_unlock(¤t->mm->page_table_lock); + return -EFAULT; + } + get_page(virt_to_page(uaddr)); + spin_unlock(¤t->mm->page_table_lock); + ret = __futex_atomic_cmpxchg_pt(uaddr, oldval, newval); put_page(virt_to_page(uaddr)); return ret; } -- 2.41.1