Skip to content

Commit

Permalink
[S390] uaccess: Always access the correct address space.
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Heiko Carstens committed Apr 17, 2008
1 parent a806170 commit 3f12ebc
Showing 1 changed file with 41 additions and 18 deletions.
59 changes: 41 additions & 18 deletions arch/s390/lib/uaccess_pt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -361,18 +365,10 @@ static size_t copy_in_user_pt(size_t n, void __user *to,
: "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",
Expand All @@ -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) {
Expand All @@ -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;
}
Expand Down

0 comments on commit 3f12ebc

Please sign in to comment.