1af8cc960SPeter Zijlstra // SPDX-License-Identifier: GPL-2.0-or-later
2af8cc960SPeter Zijlstra
3af8cc960SPeter Zijlstra #include <linux/syscalls.h>
4af8cc960SPeter Zijlstra #include <linux/time_namespace.h>
5af8cc960SPeter Zijlstra
6af8cc960SPeter Zijlstra #include "futex.h"
7af8cc960SPeter Zijlstra
8af8cc960SPeter Zijlstra /*
9af8cc960SPeter Zijlstra * Support for robust futexes: the kernel cleans up held futexes at
10af8cc960SPeter Zijlstra * thread exit time.
11af8cc960SPeter Zijlstra *
12af8cc960SPeter Zijlstra * Implementation: user-space maintains a per-thread list of locks it
13af8cc960SPeter Zijlstra * is holding. Upon do_exit(), the kernel carefully walks this list,
14af8cc960SPeter Zijlstra * and marks all locks that are owned by this thread with the
15af8cc960SPeter Zijlstra * FUTEX_OWNER_DIED bit, and wakes up a waiter (if any). The list is
16af8cc960SPeter Zijlstra * always manipulated with the lock held, so the list is private and
17af8cc960SPeter Zijlstra * per-thread. Userspace also maintains a per-thread 'list_op_pending'
18af8cc960SPeter Zijlstra * field, to allow the kernel to clean up if the thread dies after
19af8cc960SPeter Zijlstra * acquiring the lock, but just before it could have added itself to
20af8cc960SPeter Zijlstra * the list. There can only be one such pending lock.
21af8cc960SPeter Zijlstra */
22af8cc960SPeter Zijlstra
23af8cc960SPeter Zijlstra /**
24af8cc960SPeter Zijlstra * sys_set_robust_list() - Set the robust-futex list head of a task
25af8cc960SPeter Zijlstra * @head: pointer to the list-head
26af8cc960SPeter Zijlstra * @len: length of the list-head, as userspace expects
27af8cc960SPeter Zijlstra */
SYSCALL_DEFINE2(set_robust_list,struct robust_list_head __user *,head,size_t,len)28af8cc960SPeter Zijlstra SYSCALL_DEFINE2(set_robust_list, struct robust_list_head __user *, head,
29af8cc960SPeter Zijlstra size_t, len)
30af8cc960SPeter Zijlstra {
31af8cc960SPeter Zijlstra /*
32af8cc960SPeter Zijlstra * The kernel knows only one size for now:
33af8cc960SPeter Zijlstra */
34af8cc960SPeter Zijlstra if (unlikely(len != sizeof(*head)))
35af8cc960SPeter Zijlstra return -EINVAL;
36af8cc960SPeter Zijlstra
37af8cc960SPeter Zijlstra current->robust_list = head;
38af8cc960SPeter Zijlstra
39af8cc960SPeter Zijlstra return 0;
40af8cc960SPeter Zijlstra }
41af8cc960SPeter Zijlstra
42af8cc960SPeter Zijlstra /**
43af8cc960SPeter Zijlstra * sys_get_robust_list() - Get the robust-futex list head of a task
44af8cc960SPeter Zijlstra * @pid: pid of the process [zero for current task]
45af8cc960SPeter Zijlstra * @head_ptr: pointer to a list-head pointer, the kernel fills it in
46af8cc960SPeter Zijlstra * @len_ptr: pointer to a length field, the kernel fills in the header size
47af8cc960SPeter Zijlstra */
SYSCALL_DEFINE3(get_robust_list,int,pid,struct robust_list_head __user * __user *,head_ptr,size_t __user *,len_ptr)48af8cc960SPeter Zijlstra SYSCALL_DEFINE3(get_robust_list, int, pid,
49af8cc960SPeter Zijlstra struct robust_list_head __user * __user *, head_ptr,
50af8cc960SPeter Zijlstra size_t __user *, len_ptr)
51af8cc960SPeter Zijlstra {
52af8cc960SPeter Zijlstra struct robust_list_head __user *head;
53af8cc960SPeter Zijlstra unsigned long ret;
54af8cc960SPeter Zijlstra struct task_struct *p;
55af8cc960SPeter Zijlstra
56af8cc960SPeter Zijlstra rcu_read_lock();
57af8cc960SPeter Zijlstra
58af8cc960SPeter Zijlstra ret = -ESRCH;
59af8cc960SPeter Zijlstra if (!pid)
60af8cc960SPeter Zijlstra p = current;
61af8cc960SPeter Zijlstra else {
62af8cc960SPeter Zijlstra p = find_task_by_vpid(pid);
63af8cc960SPeter Zijlstra if (!p)
64af8cc960SPeter Zijlstra goto err_unlock;
65af8cc960SPeter Zijlstra }
66af8cc960SPeter Zijlstra
67af8cc960SPeter Zijlstra ret = -EPERM;
68af8cc960SPeter Zijlstra if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
69af8cc960SPeter Zijlstra goto err_unlock;
70af8cc960SPeter Zijlstra
71af8cc960SPeter Zijlstra head = p->robust_list;
72af8cc960SPeter Zijlstra rcu_read_unlock();
73af8cc960SPeter Zijlstra
74af8cc960SPeter Zijlstra if (put_user(sizeof(*head), len_ptr))
75af8cc960SPeter Zijlstra return -EFAULT;
76af8cc960SPeter Zijlstra return put_user(head, head_ptr);
77af8cc960SPeter Zijlstra
78af8cc960SPeter Zijlstra err_unlock:
79af8cc960SPeter Zijlstra rcu_read_unlock();
80af8cc960SPeter Zijlstra
81af8cc960SPeter Zijlstra return ret;
82af8cc960SPeter Zijlstra }
83af8cc960SPeter Zijlstra
do_futex(u32 __user * uaddr,int op,u32 val,ktime_t * timeout,u32 __user * uaddr2,u32 val2,u32 val3)84af8cc960SPeter Zijlstra long do_futex(u32 __user *uaddr, int op, u32 val, ktime_t *timeout,
85af8cc960SPeter Zijlstra u32 __user *uaddr2, u32 val2, u32 val3)
86af8cc960SPeter Zijlstra {
875694289cS[email protected] unsigned int flags = futex_to_flags(op);
88af8cc960SPeter Zijlstra int cmd = op & FUTEX_CMD_MASK;
89af8cc960SPeter Zijlstra
905694289cS[email protected] if (flags & FLAGS_CLOCKRT) {
915694289cS[email protected] if (cmd != FUTEX_WAIT_BITSET &&
925694289cS[email protected] cmd != FUTEX_WAIT_REQUEUE_PI &&
93af8cc960SPeter Zijlstra cmd != FUTEX_LOCK_PI2)
94af8cc960SPeter Zijlstra return -ENOSYS;
95af8cc960SPeter Zijlstra }
96af8cc960SPeter Zijlstra
97af8cc960SPeter Zijlstra switch (cmd) {
98af8cc960SPeter Zijlstra case FUTEX_WAIT:
99af8cc960SPeter Zijlstra val3 = FUTEX_BITSET_MATCH_ANY;
100af8cc960SPeter Zijlstra fallthrough;
101af8cc960SPeter Zijlstra case FUTEX_WAIT_BITSET:
102af8cc960SPeter Zijlstra return futex_wait(uaddr, flags, val, timeout, val3);
103af8cc960SPeter Zijlstra case FUTEX_WAKE:
104af8cc960SPeter Zijlstra val3 = FUTEX_BITSET_MATCH_ANY;
105af8cc960SPeter Zijlstra fallthrough;
106af8cc960SPeter Zijlstra case FUTEX_WAKE_BITSET:
107af8cc960SPeter Zijlstra return futex_wake(uaddr, flags, val, val3);
108af8cc960SPeter Zijlstra case FUTEX_REQUEUE:
10927b88f35S[email protected] return futex_requeue(uaddr, flags, uaddr2, flags, val, val2, NULL, 0);
110af8cc960SPeter Zijlstra case FUTEX_CMP_REQUEUE:
11127b88f35S[email protected] return futex_requeue(uaddr, flags, uaddr2, flags, val, val2, &val3, 0);
112af8cc960SPeter Zijlstra case FUTEX_WAKE_OP:
113af8cc960SPeter Zijlstra return futex_wake_op(uaddr, flags, uaddr2, val, val2, val3);
114af8cc960SPeter Zijlstra case FUTEX_LOCK_PI:
115af8cc960SPeter Zijlstra flags |= FLAGS_CLOCKRT;
116af8cc960SPeter Zijlstra fallthrough;
117af8cc960SPeter Zijlstra case FUTEX_LOCK_PI2:
118af8cc960SPeter Zijlstra return futex_lock_pi(uaddr, flags, timeout, 0);
119af8cc960SPeter Zijlstra case FUTEX_UNLOCK_PI:
120af8cc960SPeter Zijlstra return futex_unlock_pi(uaddr, flags);
121af8cc960SPeter Zijlstra case FUTEX_TRYLOCK_PI:
122af8cc960SPeter Zijlstra return futex_lock_pi(uaddr, flags, NULL, 1);
123af8cc960SPeter Zijlstra case FUTEX_WAIT_REQUEUE_PI:
124af8cc960SPeter Zijlstra val3 = FUTEX_BITSET_MATCH_ANY;
125af8cc960SPeter Zijlstra return futex_wait_requeue_pi(uaddr, flags, val, timeout, val3,
126af8cc960SPeter Zijlstra uaddr2);
127af8cc960SPeter Zijlstra case FUTEX_CMP_REQUEUE_PI:
12827b88f35S[email protected] return futex_requeue(uaddr, flags, uaddr2, flags, val, val2, &val3, 1);
129af8cc960SPeter Zijlstra }
130af8cc960SPeter Zijlstra return -ENOSYS;
131af8cc960SPeter Zijlstra }
132af8cc960SPeter Zijlstra
futex_cmd_has_timeout(u32 cmd)133af8cc960SPeter Zijlstra static __always_inline bool futex_cmd_has_timeout(u32 cmd)
134af8cc960SPeter Zijlstra {
135af8cc960SPeter Zijlstra switch (cmd) {
136af8cc960SPeter Zijlstra case FUTEX_WAIT:
137af8cc960SPeter Zijlstra case FUTEX_LOCK_PI:
138af8cc960SPeter Zijlstra case FUTEX_LOCK_PI2:
139af8cc960SPeter Zijlstra case FUTEX_WAIT_BITSET:
140af8cc960SPeter Zijlstra case FUTEX_WAIT_REQUEUE_PI:
141af8cc960SPeter Zijlstra return true;
142af8cc960SPeter Zijlstra }
143af8cc960SPeter Zijlstra return false;
144af8cc960SPeter Zijlstra }
145af8cc960SPeter Zijlstra
146af8cc960SPeter Zijlstra static __always_inline int
futex_init_timeout(u32 cmd,u32 op,struct timespec64 * ts,ktime_t * t)147af8cc960SPeter Zijlstra futex_init_timeout(u32 cmd, u32 op, struct timespec64 *ts, ktime_t *t)
148af8cc960SPeter Zijlstra {
149af8cc960SPeter Zijlstra if (!timespec64_valid(ts))
150af8cc960SPeter Zijlstra return -EINVAL;
151af8cc960SPeter Zijlstra
152af8cc960SPeter Zijlstra *t = timespec64_to_ktime(*ts);
153af8cc960SPeter Zijlstra if (cmd == FUTEX_WAIT)
154af8cc960SPeter Zijlstra *t = ktime_add_safe(ktime_get(), *t);
155af8cc960SPeter Zijlstra else if (cmd != FUTEX_LOCK_PI && !(op & FUTEX_CLOCK_REALTIME))
156af8cc960SPeter Zijlstra *t = timens_ktime_to_host(CLOCK_MONOTONIC, *t);
157af8cc960SPeter Zijlstra return 0;
158af8cc960SPeter Zijlstra }
159af8cc960SPeter Zijlstra
SYSCALL_DEFINE6(futex,u32 __user *,uaddr,int,op,u32,val,const struct __kernel_timespec __user *,utime,u32 __user *,uaddr2,u32,val3)160af8cc960SPeter Zijlstra SYSCALL_DEFINE6(futex, u32 __user *, uaddr, int, op, u32, val,
161af8cc960SPeter Zijlstra const struct __kernel_timespec __user *, utime,
162af8cc960SPeter Zijlstra u32 __user *, uaddr2, u32, val3)
163af8cc960SPeter Zijlstra {
164af8cc960SPeter Zijlstra int ret, cmd = op & FUTEX_CMD_MASK;
165af8cc960SPeter Zijlstra ktime_t t, *tp = NULL;
166af8cc960SPeter Zijlstra struct timespec64 ts;
167af8cc960SPeter Zijlstra
168af8cc960SPeter Zijlstra if (utime && futex_cmd_has_timeout(cmd)) {
169af8cc960SPeter Zijlstra if (unlikely(should_fail_futex(!(op & FUTEX_PRIVATE_FLAG))))
170af8cc960SPeter Zijlstra return -EFAULT;
171af8cc960SPeter Zijlstra if (get_timespec64(&ts, utime))
172af8cc960SPeter Zijlstra return -EFAULT;
173af8cc960SPeter Zijlstra ret = futex_init_timeout(cmd, op, &ts, &t);
174af8cc960SPeter Zijlstra if (ret)
175af8cc960SPeter Zijlstra return ret;
176af8cc960SPeter Zijlstra tp = &t;
177af8cc960SPeter Zijlstra }
178af8cc960SPeter Zijlstra
179af8cc960SPeter Zijlstra return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3);
180af8cc960SPeter Zijlstra }
181af8cc960SPeter Zijlstra
182bf69bad3SAndré Almeida /**
183bf69bad3SAndré Almeida * futex_parse_waitv - Parse a waitv array from userspace
184bf69bad3SAndré Almeida * @futexv: Kernel side list of waiters to be filled
185bf69bad3SAndré Almeida * @uwaitv: Userspace list to be parsed
186bf69bad3SAndré Almeida * @nr_futexes: Length of futexv
187*5177c0cbSJens Axboe * @wake: Wake to call when futex is woken
188*5177c0cbSJens Axboe * @wake_data: Data for the wake handler
189bf69bad3SAndré Almeida *
190bf69bad3SAndré Almeida * Return: Error code on failure, 0 on success
191bf69bad3SAndré Almeida */
futex_parse_waitv(struct futex_vector * futexv,struct futex_waitv __user * uwaitv,unsigned int nr_futexes,futex_wake_fn * wake,void * wake_data)192*5177c0cbSJens Axboe int futex_parse_waitv(struct futex_vector *futexv,
193bf69bad3SAndré Almeida struct futex_waitv __user *uwaitv,
194*5177c0cbSJens Axboe unsigned int nr_futexes, futex_wake_fn *wake,
195*5177c0cbSJens Axboe void *wake_data)
196bf69bad3SAndré Almeida {
197bf69bad3SAndré Almeida struct futex_waitv aux;
198bf69bad3SAndré Almeida unsigned int i;
199bf69bad3SAndré Almeida
200bf69bad3SAndré Almeida for (i = 0; i < nr_futexes; i++) {
2015694289cS[email protected] unsigned int flags;
2025694289cS[email protected]
203bf69bad3SAndré Almeida if (copy_from_user(&aux, &uwaitv[i], sizeof(aux)))
204bf69bad3SAndré Almeida return -EFAULT;
205bf69bad3SAndré Almeida
2064923954bS[email protected] if ((aux.flags & ~FUTEX2_VALID_MASK) || aux.__reserved)
207bf69bad3SAndré Almeida return -EINVAL;
208bf69bad3SAndré Almeida
2095694289cS[email protected] flags = futex2_to_flags(aux.flags);
2105694289cS[email protected] if (!futex_flags_valid(flags))
211bf69bad3SAndré Almeida return -EINVAL;
212bf69bad3SAndré Almeida
213698eb826S[email protected] if (!futex_validate_input(flags, aux.val))
214698eb826S[email protected] return -EINVAL;
215698eb826S[email protected]
2165694289cS[email protected] futexv[i].w.flags = flags;
217bf69bad3SAndré Almeida futexv[i].w.val = aux.val;
218bf69bad3SAndré Almeida futexv[i].w.uaddr = aux.uaddr;
219bf69bad3SAndré Almeida futexv[i].q = futex_q_init;
220*5177c0cbSJens Axboe futexv[i].q.wake = wake;
221*5177c0cbSJens Axboe futexv[i].q.wake_data = wake_data;
222bf69bad3SAndré Almeida }
223bf69bad3SAndré Almeida
224bf69bad3SAndré Almeida return 0;
225bf69bad3SAndré Almeida }
226bf69bad3SAndré Almeida
futex2_setup_timeout(struct __kernel_timespec __user * timeout,clockid_t clockid,struct hrtimer_sleeper * to)227cb8c4312S[email protected] static int futex2_setup_timeout(struct __kernel_timespec __user *timeout,
228cb8c4312S[email protected] clockid_t clockid, struct hrtimer_sleeper *to)
229cb8c4312S[email protected] {
230cb8c4312S[email protected] int flag_clkid = 0, flag_init = 0;
231cb8c4312S[email protected] struct timespec64 ts;
232cb8c4312S[email protected] ktime_t time;
233cb8c4312S[email protected] int ret;
234cb8c4312S[email protected]
235cb8c4312S[email protected] if (!timeout)
236cb8c4312S[email protected] return 0;
237cb8c4312S[email protected]
238cb8c4312S[email protected] if (clockid == CLOCK_REALTIME) {
239cb8c4312S[email protected] flag_clkid = FLAGS_CLOCKRT;
240cb8c4312S[email protected] flag_init = FUTEX_CLOCK_REALTIME;
241cb8c4312S[email protected] }
242cb8c4312S[email protected]
243cb8c4312S[email protected] if (clockid != CLOCK_REALTIME && clockid != CLOCK_MONOTONIC)
244cb8c4312S[email protected] return -EINVAL;
245cb8c4312S[email protected]
246cb8c4312S[email protected] if (get_timespec64(&ts, timeout))
247cb8c4312S[email protected] return -EFAULT;
248cb8c4312S[email protected]
249cb8c4312S[email protected] /*
250cb8c4312S[email protected] * Since there's no opcode for futex_waitv, use
251cb8c4312S[email protected] * FUTEX_WAIT_BITSET that uses absolute timeout as well
252cb8c4312S[email protected] */
253cb8c4312S[email protected] ret = futex_init_timeout(FUTEX_WAIT_BITSET, flag_init, &ts, &time);
254cb8c4312S[email protected] if (ret)
255cb8c4312S[email protected] return ret;
256cb8c4312S[email protected]
257cb8c4312S[email protected] futex_setup_timer(&time, to, flag_clkid, 0);
258cb8c4312S[email protected] return 0;
259cb8c4312S[email protected] }
260cb8c4312S[email protected]
futex2_destroy_timeout(struct hrtimer_sleeper * to)261cb8c4312S[email protected] static inline void futex2_destroy_timeout(struct hrtimer_sleeper *to)
262cb8c4312S[email protected] {
263cb8c4312S[email protected] hrtimer_cancel(&to->timer);
264cb8c4312S[email protected] destroy_hrtimer_on_stack(&to->timer);
265cb8c4312S[email protected] }
266cb8c4312S[email protected]
267bf69bad3SAndré Almeida /**
268bf69bad3SAndré Almeida * sys_futex_waitv - Wait on a list of futexes
269bf69bad3SAndré Almeida * @waiters: List of futexes to wait on
270bf69bad3SAndré Almeida * @nr_futexes: Length of futexv
271bf69bad3SAndré Almeida * @flags: Flag for timeout (monotonic/realtime)
272bf69bad3SAndré Almeida * @timeout: Optional absolute timeout.
273bf69bad3SAndré Almeida * @clockid: Clock to be used for the timeout, realtime or monotonic.
274bf69bad3SAndré Almeida *
275bf69bad3SAndré Almeida * Given an array of `struct futex_waitv`, wait on each uaddr. The thread wakes
276bf69bad3SAndré Almeida * if a futex_wake() is performed at any uaddr. The syscall returns immediately
277bf69bad3SAndré Almeida * if any waiter has *uaddr != val. *timeout is an optional timeout value for
278bf69bad3SAndré Almeida * the operation. Each waiter has individual flags. The `flags` argument for
279bf69bad3SAndré Almeida * the syscall should be used solely for specifying the timeout as realtime, if
280bf69bad3SAndré Almeida * needed. Flags for private futexes, sizes, etc. should be used on the
281bf69bad3SAndré Almeida * individual flags of each waiter.
282bf69bad3SAndré Almeida *
283bf69bad3SAndré Almeida * Returns the array index of one of the woken futexes. No further information
284bf69bad3SAndré Almeida * is provided: any number of other futexes may also have been woken by the
285bf69bad3SAndré Almeida * same event, and if more than one futex was woken, the retrned index may
286bf69bad3SAndré Almeida * refer to any one of them. (It is not necessaryily the futex with the
287bf69bad3SAndré Almeida * smallest index, nor the one most recently woken, nor...)
288bf69bad3SAndré Almeida */
289bf69bad3SAndré Almeida
SYSCALL_DEFINE5(futex_waitv,struct futex_waitv __user *,waiters,unsigned int,nr_futexes,unsigned int,flags,struct __kernel_timespec __user *,timeout,clockid_t,clockid)290bf69bad3SAndré Almeida SYSCALL_DEFINE5(futex_waitv, struct futex_waitv __user *, waiters,
291bf69bad3SAndré Almeida unsigned int, nr_futexes, unsigned int, flags,
292bf69bad3SAndré Almeida struct __kernel_timespec __user *, timeout, clockid_t, clockid)
293bf69bad3SAndré Almeida {
294bf69bad3SAndré Almeida struct hrtimer_sleeper to;
295bf69bad3SAndré Almeida struct futex_vector *futexv;
296bf69bad3SAndré Almeida int ret;
297bf69bad3SAndré Almeida
298bf69bad3SAndré Almeida /* This syscall supports no flags for now */
299bf69bad3SAndré Almeida if (flags)
300bf69bad3SAndré Almeida return -EINVAL;
301bf69bad3SAndré Almeida
302bf69bad3SAndré Almeida if (!nr_futexes || nr_futexes > FUTEX_WAITV_MAX || !waiters)
303bf69bad3SAndré Almeida return -EINVAL;
304bf69bad3SAndré Almeida
305cb8c4312S[email protected] if (timeout && (ret = futex2_setup_timeout(timeout, clockid, &to)))
306bf69bad3SAndré Almeida return ret;
307bf69bad3SAndré Almeida
308bf69bad3SAndré Almeida futexv = kcalloc(nr_futexes, sizeof(*futexv), GFP_KERNEL);
30994cd8fa0SMathieu Desnoyers if (!futexv) {
31094cd8fa0SMathieu Desnoyers ret = -ENOMEM;
31194cd8fa0SMathieu Desnoyers goto destroy_timer;
31294cd8fa0SMathieu Desnoyers }
313bf69bad3SAndré Almeida
314*5177c0cbSJens Axboe ret = futex_parse_waitv(futexv, waiters, nr_futexes, futex_wake_mark,
315*5177c0cbSJens Axboe NULL);
316bf69bad3SAndré Almeida if (!ret)
317bf69bad3SAndré Almeida ret = futex_wait_multiple(futexv, nr_futexes, timeout ? &to : NULL);
318bf69bad3SAndré Almeida
31994cd8fa0SMathieu Desnoyers kfree(futexv);
32094cd8fa0SMathieu Desnoyers
32194cd8fa0SMathieu Desnoyers destroy_timer:
322cb8c4312S[email protected] if (timeout)
323cb8c4312S[email protected] futex2_destroy_timeout(&to);
324bf69bad3SAndré Almeida return ret;
325bf69bad3SAndré Almeida }
326bf69bad3SAndré Almeida
3279f6c532fS[email protected] /*
3289f6c532fS[email protected] * sys_futex_wake - Wake a number of futexes
3299f6c532fS[email protected] * @uaddr: Address of the futex(es) to wake
3309f6c532fS[email protected] * @mask: bitmask
3319f6c532fS[email protected] * @nr: Number of the futexes to wake
3329f6c532fS[email protected] * @flags: FUTEX2 flags
3339f6c532fS[email protected] *
3349f6c532fS[email protected] * Identical to the traditional FUTEX_WAKE_BITSET op, except it is part of the
3359f6c532fS[email protected] * futex2 family of calls.
3369f6c532fS[email protected] */
3379f6c532fS[email protected]
SYSCALL_DEFINE4(futex_wake,void __user *,uaddr,unsigned long,mask,int,nr,unsigned int,flags)3389f6c532fS[email protected] SYSCALL_DEFINE4(futex_wake,
3399f6c532fS[email protected] void __user *, uaddr,
3409f6c532fS[email protected] unsigned long, mask,
3419f6c532fS[email protected] int, nr,
3429f6c532fS[email protected] unsigned int, flags)
3439f6c532fS[email protected] {
3449f6c532fS[email protected] if (flags & ~FUTEX2_VALID_MASK)
3459f6c532fS[email protected] return -EINVAL;
3469f6c532fS[email protected]
3479f6c532fS[email protected] flags = futex2_to_flags(flags);
3489f6c532fS[email protected] if (!futex_flags_valid(flags))
3499f6c532fS[email protected] return -EINVAL;
3509f6c532fS[email protected]
3519f6c532fS[email protected] if (!futex_validate_input(flags, mask))
3529f6c532fS[email protected] return -EINVAL;
3539f6c532fS[email protected]
35443adf844S[email protected] return futex_wake(uaddr, FLAGS_STRICT | flags, nr, mask);
3559f6c532fS[email protected] }
3569f6c532fS[email protected]
357cb8c4312S[email protected] /*
358cb8c4312S[email protected] * sys_futex_wait - Wait on a futex
359cb8c4312S[email protected] * @uaddr: Address of the futex to wait on
360cb8c4312S[email protected] * @val: Value of @uaddr
361cb8c4312S[email protected] * @mask: bitmask
362cb8c4312S[email protected] * @flags: FUTEX2 flags
363cb8c4312S[email protected] * @timeout: Optional absolute timeout
364cb8c4312S[email protected] * @clockid: Clock to be used for the timeout, realtime or monotonic
365cb8c4312S[email protected] *
366cb8c4312S[email protected] * Identical to the traditional FUTEX_WAIT_BITSET op, except it is part of the
367cb8c4312S[email protected] * futex2 familiy of calls.
368cb8c4312S[email protected] */
369cb8c4312S[email protected]
SYSCALL_DEFINE6(futex_wait,void __user *,uaddr,unsigned long,val,unsigned long,mask,unsigned int,flags,struct __kernel_timespec __user *,timeout,clockid_t,clockid)370cb8c4312S[email protected] SYSCALL_DEFINE6(futex_wait,
371cb8c4312S[email protected] void __user *, uaddr,
372cb8c4312S[email protected] unsigned long, val,
373cb8c4312S[email protected] unsigned long, mask,
374cb8c4312S[email protected] unsigned int, flags,
375cb8c4312S[email protected] struct __kernel_timespec __user *, timeout,
376cb8c4312S[email protected] clockid_t, clockid)
377cb8c4312S[email protected] {
378cb8c4312S[email protected] struct hrtimer_sleeper to;
379cb8c4312S[email protected] int ret;
380cb8c4312S[email protected]
381cb8c4312S[email protected] if (flags & ~FUTEX2_VALID_MASK)
382cb8c4312S[email protected] return -EINVAL;
383cb8c4312S[email protected]
384cb8c4312S[email protected] flags = futex2_to_flags(flags);
385cb8c4312S[email protected] if (!futex_flags_valid(flags))
386cb8c4312S[email protected] return -EINVAL;
387cb8c4312S[email protected]
388cb8c4312S[email protected] if (!futex_validate_input(flags, val) ||
389cb8c4312S[email protected] !futex_validate_input(flags, mask))
390cb8c4312S[email protected] return -EINVAL;
391cb8c4312S[email protected]
392cb8c4312S[email protected] if (timeout && (ret = futex2_setup_timeout(timeout, clockid, &to)))
393cb8c4312S[email protected] return ret;
394cb8c4312S[email protected]
395cb8c4312S[email protected] ret = __futex_wait(uaddr, flags, val, timeout ? &to : NULL, mask);
396cb8c4312S[email protected]
397cb8c4312S[email protected] if (timeout)
398cb8c4312S[email protected] futex2_destroy_timeout(&to);
399cb8c4312S[email protected]
400cb8c4312S[email protected] return ret;
401cb8c4312S[email protected] }
402cb8c4312S[email protected]
4030f4b5f97S[email protected] /*
4040f4b5f97S[email protected] * sys_futex_requeue - Requeue a waiter from one futex to another
4050f4b5f97S[email protected] * @waiters: array describing the source and destination futex
4060f4b5f97S[email protected] * @flags: unused
4070f4b5f97S[email protected] * @nr_wake: number of futexes to wake
4080f4b5f97S[email protected] * @nr_requeue: number of futexes to requeue
4090f4b5f97S[email protected] *
4100f4b5f97S[email protected] * Identical to the traditional FUTEX_CMP_REQUEUE op, except it is part of the
4110f4b5f97S[email protected] * futex2 family of calls.
4120f4b5f97S[email protected] */
4130f4b5f97S[email protected]
SYSCALL_DEFINE4(futex_requeue,struct futex_waitv __user *,waiters,unsigned int,flags,int,nr_wake,int,nr_requeue)4140f4b5f97S[email protected] SYSCALL_DEFINE4(futex_requeue,
4150f4b5f97S[email protected] struct futex_waitv __user *, waiters,
4160f4b5f97S[email protected] unsigned int, flags,
4170f4b5f97S[email protected] int, nr_wake,
4180f4b5f97S[email protected] int, nr_requeue)
4190f4b5f97S[email protected] {
4200f4b5f97S[email protected] struct futex_vector futexes[2];
4210f4b5f97S[email protected] u32 cmpval;
4220f4b5f97S[email protected] int ret;
4230f4b5f97S[email protected]
4240f4b5f97S[email protected] if (flags)
4250f4b5f97S[email protected] return -EINVAL;
4260f4b5f97S[email protected]
4270f4b5f97S[email protected] if (!waiters)
4280f4b5f97S[email protected] return -EINVAL;
4290f4b5f97S[email protected]
430*5177c0cbSJens Axboe ret = futex_parse_waitv(futexes, waiters, 2, futex_wake_mark, NULL);
4310f4b5f97S[email protected] if (ret)
4320f4b5f97S[email protected] return ret;
4330f4b5f97S[email protected]
4340f4b5f97S[email protected] cmpval = futexes[0].w.val;
4350f4b5f97S[email protected]
4360f4b5f97S[email protected] return futex_requeue(u64_to_user_ptr(futexes[0].w.uaddr), futexes[0].w.flags,
4370f4b5f97S[email protected] u64_to_user_ptr(futexes[1].w.uaddr), futexes[1].w.flags,
4380f4b5f97S[email protected] nr_wake, nr_requeue, &cmpval, 0);
4390f4b5f97S[email protected] }
4400f4b5f97S[email protected]
441af8cc960SPeter Zijlstra #ifdef CONFIG_COMPAT
COMPAT_SYSCALL_DEFINE2(set_robust_list,struct compat_robust_list_head __user *,head,compat_size_t,len)442af8cc960SPeter Zijlstra COMPAT_SYSCALL_DEFINE2(set_robust_list,
443af8cc960SPeter Zijlstra struct compat_robust_list_head __user *, head,
444af8cc960SPeter Zijlstra compat_size_t, len)
445af8cc960SPeter Zijlstra {
446af8cc960SPeter Zijlstra if (unlikely(len != sizeof(*head)))
447af8cc960SPeter Zijlstra return -EINVAL;
448af8cc960SPeter Zijlstra
449af8cc960SPeter Zijlstra current->compat_robust_list = head;
450af8cc960SPeter Zijlstra
451af8cc960SPeter Zijlstra return 0;
452af8cc960SPeter Zijlstra }
453af8cc960SPeter Zijlstra
COMPAT_SYSCALL_DEFINE3(get_robust_list,int,pid,compat_uptr_t __user *,head_ptr,compat_size_t __user *,len_ptr)454af8cc960SPeter Zijlstra COMPAT_SYSCALL_DEFINE3(get_robust_list, int, pid,
455af8cc960SPeter Zijlstra compat_uptr_t __user *, head_ptr,
456af8cc960SPeter Zijlstra compat_size_t __user *, len_ptr)
457af8cc960SPeter Zijlstra {
458af8cc960SPeter Zijlstra struct compat_robust_list_head __user *head;
459af8cc960SPeter Zijlstra unsigned long ret;
460af8cc960SPeter Zijlstra struct task_struct *p;
461af8cc960SPeter Zijlstra
462af8cc960SPeter Zijlstra rcu_read_lock();
463af8cc960SPeter Zijlstra
464af8cc960SPeter Zijlstra ret = -ESRCH;
465af8cc960SPeter Zijlstra if (!pid)
466af8cc960SPeter Zijlstra p = current;
467af8cc960SPeter Zijlstra else {
468af8cc960SPeter Zijlstra p = find_task_by_vpid(pid);
469af8cc960SPeter Zijlstra if (!p)
470af8cc960SPeter Zijlstra goto err_unlock;
471af8cc960SPeter Zijlstra }
472af8cc960SPeter Zijlstra
473af8cc960SPeter Zijlstra ret = -EPERM;
474af8cc960SPeter Zijlstra if (!ptrace_may_access(p, PTRACE_MODE_READ_REALCREDS))
475af8cc960SPeter Zijlstra goto err_unlock;
476af8cc960SPeter Zijlstra
477af8cc960SPeter Zijlstra head = p->compat_robust_list;
478af8cc960SPeter Zijlstra rcu_read_unlock();
479af8cc960SPeter Zijlstra
480af8cc960SPeter Zijlstra if (put_user(sizeof(*head), len_ptr))
481af8cc960SPeter Zijlstra return -EFAULT;
482af8cc960SPeter Zijlstra return put_user(ptr_to_compat(head), head_ptr);
483af8cc960SPeter Zijlstra
484af8cc960SPeter Zijlstra err_unlock:
485af8cc960SPeter Zijlstra rcu_read_unlock();
486af8cc960SPeter Zijlstra
487af8cc960SPeter Zijlstra return ret;
488af8cc960SPeter Zijlstra }
489af8cc960SPeter Zijlstra #endif /* CONFIG_COMPAT */
490af8cc960SPeter Zijlstra
491af8cc960SPeter Zijlstra #ifdef CONFIG_COMPAT_32BIT_TIME
SYSCALL_DEFINE6(futex_time32,u32 __user *,uaddr,int,op,u32,val,const struct old_timespec32 __user *,utime,u32 __user *,uaddr2,u32,val3)492af8cc960SPeter Zijlstra SYSCALL_DEFINE6(futex_time32, u32 __user *, uaddr, int, op, u32, val,
493af8cc960SPeter Zijlstra const struct old_timespec32 __user *, utime, u32 __user *, uaddr2,
494af8cc960SPeter Zijlstra u32, val3)
495af8cc960SPeter Zijlstra {
496af8cc960SPeter Zijlstra int ret, cmd = op & FUTEX_CMD_MASK;
497af8cc960SPeter Zijlstra ktime_t t, *tp = NULL;
498af8cc960SPeter Zijlstra struct timespec64 ts;
499af8cc960SPeter Zijlstra
500af8cc960SPeter Zijlstra if (utime && futex_cmd_has_timeout(cmd)) {
501af8cc960SPeter Zijlstra if (get_old_timespec32(&ts, utime))
502af8cc960SPeter Zijlstra return -EFAULT;
503af8cc960SPeter Zijlstra ret = futex_init_timeout(cmd, op, &ts, &t);
504af8cc960SPeter Zijlstra if (ret)
505af8cc960SPeter Zijlstra return ret;
506af8cc960SPeter Zijlstra tp = &t;
507af8cc960SPeter Zijlstra }
508af8cc960SPeter Zijlstra
509af8cc960SPeter Zijlstra return do_futex(uaddr, op, val, tp, uaddr2, (unsigned long)utime, val3);
510af8cc960SPeter Zijlstra }
511af8cc960SPeter Zijlstra #endif /* CONFIG_COMPAT_32BIT_TIME */
512af8cc960SPeter Zijlstra
513