Skip to content

Commit 04e7712

Browse files
committed
y2038: futex: Move compat implementation into futex.c
We are going to share the compat_sys_futex() handler between 64-bit architectures and 32-bit architectures that need to deal with both 32-bit and 64-bit time_t, and this is easier if both entry points are in the same file. In fact, most other system call handlers do the same thing these days, so let's follow the trend here and merge all of futex_compat.c into futex.c. In the process, a few minor changes have to be done to make sure everything still makes sense: handle_futex_death() and futex_cmpxchg_enabled() become local symbol, and the compat version of the fetch_robust_entry() function gets renamed to compat_fetch_robust_entry() to avoid a symbol clash. This is intended as a purely cosmetic patch, no behavior should change. Signed-off-by: Arnd Bergmann <arnd@arndb.de>
1 parent 7a35397 commit 04e7712

File tree

4 files changed

+192
-216
lines changed

4 files changed

+192
-216
lines changed

include/linux/futex.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,6 @@ struct inode;
99
struct mm_struct;
1010
struct task_struct;
1111

12-
extern int
13-
handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi);
14-
1512
/*
1613
* Futexes are matched on equal values of this key.
1714
* The key type depends on whether it's a shared or private mapping.
@@ -55,11 +52,6 @@ extern void exit_robust_list(struct task_struct *curr);
5552

5653
long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
5754
u32 __user *uaddr2, u32 val2, u32 val3);
58-
#ifdef CONFIG_HAVE_FUTEX_CMPXCHG
59-
#define futex_cmpxchg_enabled 1
60-
#else
61-
extern int futex_cmpxchg_enabled;
62-
#endif
6355
#else
6456
static inline void exit_robust_list(struct task_struct *curr)
6557
{

kernel/Makefile

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,6 @@ obj-$(CONFIG_PROFILING) += profile.o
4949
obj-$(CONFIG_STACKTRACE) += stacktrace.o
5050
obj-y += time/
5151
obj-$(CONFIG_FUTEX) += futex.o
52-
ifeq ($(CONFIG_COMPAT),y)
53-
obj-$(CONFIG_FUTEX) += futex_compat.o
54-
endif
5552
obj-$(CONFIG_GENERIC_ISA_DMA) += dma.o
5653
obj-$(CONFIG_SMP) += smp.o
5754
ifneq ($(CONFIG_SMP),y)

kernel/futex.c

Lines changed: 192 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,7 @@
4444
* along with this program; if not, write to the Free Software
4545
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
4646
*/
47+
#include <linux/compat.h>
4748
#include <linux/slab.h>
4849
#include <linux/poll.h>
4950
#include <linux/fs.h>
@@ -173,8 +174,10 @@
173174
* double_lock_hb() and double_unlock_hb(), respectively.
174175
*/
175176

176-
#ifndef CONFIG_HAVE_FUTEX_CMPXCHG
177-
int __read_mostly futex_cmpxchg_enabled;
177+
#ifdef CONFIG_HAVE_FUTEX_CMPXCHG
178+
#define futex_cmpxchg_enabled 1
179+
#else
180+
static int __read_mostly futex_cmpxchg_enabled;
178181
#endif
179182

180183
/*
@@ -3360,7 +3363,7 @@ SYSCALL_DEFINE3(get_robust_list, int, pid,
33603363
* Process a futex-list entry, check whether it's owned by the
33613364
* dying task, and do notification if so:
33623365
*/
3363-
int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)
3366+
static int handle_futex_death(u32 __user *uaddr, struct task_struct *curr, int pi)
33643367
{
33653368
u32 uval, uninitialized_var(nval), mval;
33663369

@@ -3589,6 +3592,192 @@ SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
35893592
return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
35903593
}
35913594

3595+
#ifdef CONFIG_COMPAT
3596+
/*
3597+
* Fetch a robust-list pointer. Bit 0 signals PI futexes:
3598+
*/
3599+
static inline int
3600+
compat_fetch_robust_entry(compat_uptr_t *uentry, struct robust_list __user **entry,
3601+
compat_uptr_t __user *head, unsigned int *pi)
3602+
{
3603+
if (get_user(*uentry, head))
3604+
return -EFAULT;
3605+
3606+
*entry = compat_ptr((*uentry) & ~1);
3607+
*pi = (unsigned int)(*uentry) & 1;
3608+
3609+
return 0;
3610+
}
3611+
3612+
static void __user *futex_uaddr(struct robust_list __user *entry,
3613+
compat_long_t futex_offset)
3614+
{
3615+
compat_uptr_t base = ptr_to_compat(entry);
3616+
void __user *uaddr = compat_ptr(base + futex_offset);
3617+
3618+
return uaddr;
3619+
}
3620+
3621+
/*
3622+
* Walk curr->robust_list (very carefully, it's a userspace list!)
3623+
* and mark any locks found there dead, and notify any waiters.
3624+
*
3625+
* We silently return on any sign of list-walking problem.
3626+
*/
3627+
void compat_exit_robust_list(struct task_struct *curr)
3628+
{
3629+
struct compat_robust_list_head __user *head = curr->compat_robust_list;
3630+
struct robust_list __user *entry, *next_entry, *pending;
3631+
unsigned int limit = ROBUST_LIST_LIMIT, pi, pip;
3632+
unsigned int uninitialized_var(next_pi);
3633+
compat_uptr_t uentry, next_uentry, upending;
3634+
compat_long_t futex_offset;
3635+
int rc;
3636+
3637+
if (!futex_cmpxchg_enabled)
3638+
return;
3639+
3640+
/*
3641+
* Fetch the list head (which was registered earlier, via
3642+
* sys_set_robust_list()):
3643+
*/
3644+
if (compat_fetch_robust_entry(&uentry, &entry, &head->list.next, &pi))
3645+
return;
3646+
/*
3647+
* Fetch the relative futex offset:
3648+
*/
3649+
if (get_user(futex_offset, &head->futex_offset))
3650+
return;
3651+
/*
3652+
* Fetch any possibly pending lock-add first, and handle it
3653+
* if it exists:
3654+
*/
3655+
if (compat_fetch_robust_entry(&upending, &pending,
3656+
&head->list_op_pending, &pip))
3657+
return;
3658+
3659+
next_entry = NULL; /* avoid warning with gcc */
3660+
while (entry != (struct robust_list __user *) &head->list) {
3661+
/*
3662+
* Fetch the next entry in the list before calling
3663+
* handle_futex_death:
3664+
*/
3665+
rc = compat_fetch_robust_entry(&next_uentry, &next_entry,
3666+
(compat_uptr_t __user *)&entry->next, &next_pi);
3667+
/*
3668+
* A pending lock might already be on the list, so
3669+
* dont process it twice:
3670+
*/
3671+
if (entry != pending) {
3672+
void __user *uaddr = futex_uaddr(entry, futex_offset);
3673+
3674+
if (handle_futex_death(uaddr, curr, pi))
3675+
return;
3676+
}
3677+
if (rc)
3678+
return;
3679+
uentry = next_uentry;
3680+
entry = next_entry;
3681+
pi = next_pi;
3682+
/*
3683+
* Avoid excessively long or circular lists:
3684+
*/
3685+
if (!--limit)
3686+
break;
3687+
3688+
cond_resched();
3689+
}
3690+
if (pending) {
3691+
void __user *uaddr = futex_uaddr(pending, futex_offset);
3692+
3693+
handle_futex_death(uaddr, curr, pip);
3694+
}
3695+
}
3696+
3697+
COMPAT_SYSCALL_DEFINE2(set_robust_list,
3698+
struct compat_robust_list_head __user *, head,
3699+
compat_size_t, len)
3700+
{
3701+
if (!futex_cmpxchg_enabled)
3702+
return -ENOSYS;
3703+
3704+
if (unlikely(len != sizeof(*head)))
3705+
return -EINVAL;
3706+
3707+
current->compat_robust_list = head;
3708+
3709+
return 0;
3710+
}
3711+
3712+
COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
3713+
compat_uptr_t __user *, head_ptr,
3714+
compat_size_t __user *, len_ptr)
3715+
{
3716+
struct compat_robust_list_head __user *head;
3717+
unsigned long ret;
3718+
struct task_struct *p;
3719+
3720+
if (!futex_cmpxchg_enabled)
3721+
return -ENOSYS;
3722+
3723+
rcu_read_lock();
3724+
3725+
ret = -ESRCH;
3726+
if (!pid)
3727+
p = current;
3728+
else {
3729+
p = find_task_by_vpid(pid);
3730+
if (!p)
3731+
goto err_unlock;
3732+
}
3733+
3734+
ret = -EPERM;
3735+
if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
3736+
goto err_unlock;
3737+
3738+
head = p->compat_robust_list;
3739+
rcu_read_unlock();
3740+
3741+
if (put_user(sizeof(*head), len_ptr))
3742+
return -EFAULT;
3743+
return put_user(ptr_to_compat(head), head_ptr);
3744+
3745+
err_unlock:
3746+
rcu_read_unlock();
3747+
3748+
return ret;
3749+
}
3750+
3751+
COMPAT_SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
3752+
struct old_timespec32 __user *, utime, u32 __user *, uaddr2,
3753+
u32, val3)
3754+
{
3755+
struct timespec ts;
3756+
ktime_t t, *tp = NULL;
3757+
int val2 = 0;
3758+
int cmd = op & FUTEX_CMD_MASK;
3759+
3760+
if (utime && (cmd == FUTEX_WAIT || cmd == FUTEX_LOCK_PI ||
3761+
cmd == FUTEX_WAIT_BITSET ||
3762+
cmd == FUTEX_WAIT_REQUEUE_PI)) {
3763+
if (compat_get_timespec(&ts, utime))
3764+
return -EFAULT;
3765+
if (!timespec_valid(&ts))
3766+
return -EINVAL;
3767+
3768+
t = timespec_to_ktime(ts);
3769+
if (cmd == FUTEX_WAIT)
3770+
t = ktime_add_safe(ktime_get(), t);
3771+
tp = &t;
3772+
}
3773+
if (cmd == FUTEX_REQUEUE || cmd == FUTEX_CMP_REQUEUE ||
3774+
cmd == FUTEX_CMP_REQUEUE_PI || cmd == FUTEX_WAKE_OP)
3775+
val2 = (int) (unsigned long) utime;
3776+
3777+
return do_futex(uaddr, op, val, tp, uaddr2, val2, val3);
3778+
}
3779+
#endif /* CONFIG_COMPAT */
3780+
35923781
static void __init futex_detect_cmpxchg(void)
35933782
{
35943783
#ifndef CONFIG_HAVE_FUTEX_CMPXCHG

0 commit comments

Comments
 (0)