From: Heiko Carstens Date: Fri, 17 Jan 2014 12:12:34 +0000 (+0100) Subject: s390/uaccess: test if current->mm is set before walking page tables X-Git-Tag: v3.14-rc1~74^2~4 X-Git-Url: https://git.openpandora.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=b03b467944b3e88a36a33b5429425c42dbd5b8a0;p=pandora-kernel.git s390/uaccess: test if current->mm is set before walking page tables If get_fs() == USER_DS we better test if current->mm is not zero before walking page tables. The page table walk code would try to lock mm->page_table_lock, however if mm is zero this might crash. Now it is arguably incorrect trying to access userspace if current->mm is zero, however we have seen that and s390 would be the only architecture which would crash in such a case. So we better make the page table walk code a bit more robust and report always a fault instead. Signed-off-by: Heiko Carstens Signed-off-by: Martin Schwidefsky --- diff --git a/arch/s390/lib/uaccess_pt.c b/arch/s390/lib/uaccess_pt.c index 0632dc50da78..5b77c341a1e3 100644 --- a/arch/s390/lib/uaccess_pt.c +++ b/arch/s390/lib/uaccess_pt.c @@ -153,6 +153,8 @@ static __always_inline size_t __user_copy_pt(unsigned long uaddr, void *kptr, unsigned long offset, done, size, kaddr; void *from, *to; + if (!mm) + return n; done = 0; retry: spin_lock(&mm->page_table_lock); @@ -262,6 +264,8 @@ static size_t strnlen_user_pt(size_t count, const char __user *src) return 0; if (segment_eq(get_fs(), KERNEL_DS)) return strnlen_kernel(count, src); + if (!mm) + return 0; done = 0; retry: spin_lock(&mm->page_table_lock); @@ -323,6 +327,8 @@ static size_t copy_in_user_pt(size_t n, void __user *to, if (segment_eq(get_fs(), KERNEL_DS)) return copy_in_kernel(n, to, from); + if (!mm) + return n; done = 0; retry: spin_lock(&mm->page_table_lock); @@ -411,6 +417,8 @@ int futex_atomic_op_pt(int op, u32 __user *uaddr, int oparg, int *old) if (segment_eq(get_fs(), KERNEL_DS)) return __futex_atomic_op_pt(op, uaddr, oparg, old); + if (unlikely(!current->mm)) + return -EFAULT; spin_lock(¤t->mm->page_table_lock); uaddr = (u32 __force __user *) __dat_user_addr((__force unsigned long) uaddr, 1); @@ -448,6 +456,8 @@ int futex_atomic_cmpxchg_pt(u32 *uval, u32 __user *uaddr, if (segment_eq(get_fs(), KERNEL_DS)) return __futex_atomic_cmpxchg_pt(uval, uaddr, oldval, newval); + if (unlikely(!current->mm)) + return -EFAULT; spin_lock(¤t->mm->page_table_lock); uaddr = (u32 __force __user *) __dat_user_addr((__force unsigned long) uaddr, 1);