Hi,

The following diff makes the effect of multiple threads calling
pledge(2) to be serializable.

It adds a loop (with tsleep(9)) at pledge(2) entrance if another thread
is already inside (due to sleep), changes return to goto statment, and
wakeup other threads at end.

The check for looping or continue is done using a new flag PLEDGE_BUSY,
which mark a thread of the current process is currently inside
sys_pledge().

This diff was done with the help of deraadt@ and guenther@.

Comments or OK ?
-- 
Sebastien Marie


Index: sys/kern/kern_pledge.c
===================================================================
RCS file: /cvs/src/sys/kern/kern_pledge.c,v
retrieving revision 1.162
diff -u -p -r1.162 kern_pledge.c
--- sys/kern/kern_pledge.c      30 Mar 2016 07:49:11 -0000      1.162
+++ sys/kern/kern_pledge.c      9 Apr 2016 08:34:16 -0000
@@ -399,8 +399,23 @@ sys_pledge(struct proc *p, void *v, regi
                syscallarg(const char *)request;
                syscallarg(const char **)paths;
        } */    *uap = v;
-       uint64_t flags = 0;
-       int error;
+       uint64_t flags = PLEDGE_BUSY;
+       int error = 0;
+
+       /*
+        * makes the effect of multiple threads calling pledge(2) to be
+        * serializable. We are under KERN_LOCK, but pledge(2) could sleep due
+        * to malloc(M_WAITOK) usage.
+        *
+        * so wait to `PLEDGE_BUSY' be cleared.
+        */
+       while (ISSET(p->p_p->ps_pledge, PLEDGE_BUSY)) {
+               error = tsleep(&p->p_p->ps_pledge, PUSER, "pledge", 0);
+               if (error)
+                       return error;
+       }
+       SET(p->p_p->ps_pledge, PLEDGE_BUSY);
+
 
        if (SCARG(uap, request)) {
                size_t rbuflen;
@@ -412,7 +427,7 @@ sys_pledge(struct proc *p, void *v, regi
                    &rbuflen);
                if (error) {
                        free(rbuf, M_TEMP, MAXPATHLEN);
-                       return (error);
+                       goto out;
                }
 #ifdef KTRACE
                if (KTRPOINT(p, KTR_STRUCT))
@@ -428,20 +443,24 @@ sys_pledge(struct proc *p, void *v, regi
 
                        if ((f = pledgereq_flags(rp)) == 0) {
                                free(rbuf, M_TEMP, MAXPATHLEN);
-                               return (EINVAL);
+                               error = EINVAL;
+                               goto out;
                        }
                        flags |= f;
                }
                free(rbuf, M_TEMP, MAXPATHLEN);
 
-               if (flags & ~PLEDGE_USERSET)
-                       return (EINVAL);
+               if (flags & ~PLEDGE_USERSET) {
+                       error = EINVAL;
+                       goto out;
+               }
 
                if ((p->p_p->ps_flags & PS_PLEDGE)) {
                        /* Already pledged, only allow reductions */
                        if (((flags | p->p_p->ps_pledge) & PLEDGE_USERSET) !=
                            (p->p_p->ps_pledge & PLEDGE_USERSET)) {
-                               return (EPERM);
+                               error = EPERM;
+                               goto out;
                        }
 
                        flags &= p->p_p->ps_pledge;
@@ -451,7 +470,8 @@ sys_pledge(struct proc *p, void *v, regi
 
        if (SCARG(uap, paths)) {
 #if 1
-               return (EINVAL);
+               error = EINVAL;
+               goto out;
 #else
                const char **u = SCARG(uap, paths), *sp;
                struct whitepaths *wl;
@@ -545,7 +565,13 @@ sys_pledge(struct proc *p, void *v, regi
                p->p_p->ps_flags |= PS_PLEDGE;
        }
 
-       return (0);
+out:
+       /*
+        * unbusying pledge, and wakeup other threads if any.
+        */
+       CLR(p->p_p->ps_pledge, PLEDGE_BUSY);
+       wakeup(&p->p_p->ps_pledge);
+       return error;
 }
 
 int
Index: sys/sys/pledge.h
===================================================================
RCS file: /cvs/src/sys/sys/pledge.h,v
retrieving revision 1.27
diff -u -p -r1.27 pledge.h
--- sys/sys/pledge.h    9 Jan 2016 06:13:44 -0000       1.27
+++ sys/sys/pledge.h    9 Apr 2016 08:34:16 -0000
@@ -56,6 +56,7 @@
 #define PLEDGE_DPATH   0x0000000010000000ULL   /* mknod & mkfifo */
 #define PLEDGE_DRM     0x0000000020000000ULL   /* drm ioctls */
 #define PLEDGE_VMM     0x0000000040000000ULL   /* vmm ioctls */
+#define PLEDGE_BUSY    0x0000000080000000ULL   /* pledge in progress */
 
 /*
  * Bits outside PLEDGE_USERSET are used by the kernel itself

Reply via email to