forked from Minki/linux
[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 <schwidefsky@de.ibm.com> Signed-off-by: Heiko Carstens <heiko.carstens@de.ibm.com>
This commit is contained in:
parent
a806170e29
commit
3f12ebce6a
@ -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;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user