Make things more robust... Okay?

Index: linux_futex.c
===================================================================
RCS file: /cvs/src/sys/compat/linux/linux_futex.c,v
retrieving revision 1.4
diff -u -p -r1.4 linux_futex.c
--- linux_futex.c       19 Jun 2012 08:50:59 -0000      1.4
+++ linux_futex.c       19 Jun 2012 08:56:39 -0000
@@ -1,4 +1,4 @@
-/* $OpenBSD: linux_futex.c,v 1.4 2012/06/19 08:50:59 pirofti Exp $ */
+/* $OpenBSD: linux_futex.c,v 1.1 2011/09/18 02:23:18 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 str
                        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 str
                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 str
 
                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));

Reply via email to