summaryrefslogtreecommitdiffstats
path: root/sys/compat/linux/linux_futex.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/compat/linux/linux_futex.c')
-rw-r--r--sys/compat/linux/linux_futex.c37
1 files changed, 31 insertions, 6 deletions
diff --git a/sys/compat/linux/linux_futex.c b/sys/compat/linux/linux_futex.c
index cd1231a50ef..7c2289dfbb7 100644
--- a/sys/compat/linux/linux_futex.c
+++ b/sys/compat/linux/linux_futex.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: linux_futex.c,v 1.5 2012/06/19 11:40:16 jasper Exp $ */
+/* $OpenBSD: linux_futex.c,v 1.6 2012/06/19 11:43:45 pirofti Exp $ */
/* $NetBSD: linux_futex.c,v 1.26 2010/07/07 01:30:35 chs Exp $ */
/*-
@@ -188,12 +188,17 @@ linux_do_futex(struct proc *p, const struct linux_sys_futex_args *uap,
return EWOULDBLOCK;
}
- if ((error = futex_itimespecfix(ts)) != 0) {
- mtx_leave(&futex_lock);
- return error;
+ /* Check for infinity */
+ if (ts->tv_sec == 0 && ts->tv_nsec == 0) {
+ timeout_hz = 0;
+ } else {
+ if ((error = futex_itimespecfix(ts)) != 0) {
+ mtx_leave(&futex_lock);
+ return error;
+ }
+ TIMESPEC_TO_TIMEVAL(&tv, ts);
+ timeout_hz = tvtohz(&tv);
}
- TIMESPEC_TO_TIMEVAL(&tv, ts);
- timeout_hz = tvtohz(&tv);
/*
* If the user process requests a non null timeout,
@@ -272,6 +277,15 @@ linux_do_futex(struct proc *p, const struct linux_sys_futex_args *uap,
if (args_val < 0)
return EINVAL;
+ /*
+ * Don't allow using the same address for requeueing.
+ *
+ * glibc seems to cope with this.
+ */
+ if (SCARG(uap, uaddr) == SCARG(uap, uaddr2)) {
+ return EINVAL;
+ }
+
mtx_enter(&futex_lock);
if ((error = copyin(SCARG(uap, uaddr),
&uaddr_val, sizeof(uaddr_val))) != 0) {
@@ -294,6 +308,17 @@ linux_do_futex(struct proc *p, const struct linux_sys_futex_args *uap,
f = futex_get(SCARG(uap, uaddr));
newf = futex_get(SCARG(uap, uaddr2));
+ /*
+ * Check if uaddr2 is in use.
+ * If true, return EINVAL to avoid deadlock.
+ *
+ * glibc seems to cope with this.
+ */
+ if (newf->f_refcount != 1) {
+ futex_put(f);
+ futex_put(newf);
+ return EINVAL;
+ }
*retval = futex_wake(f, args_val, newf,
(int)(unsigned long)SCARG(uap, timeout));