Author: oshogbo
Date: Fri Oct 21 16:12:23 2016
New Revision: 307734
URL: https://svnweb.freebsd.org/changeset/base/307734

Log:
  capsicum: perform copyout without the fildesc lock held in sys_cap_ioctls_get
  
  Reviewed by:  pjd

Modified:
  head/sys/kern/sys_capability.c

Modified: head/sys/kern/sys_capability.c
==============================================================================
--- head/sys/kern/sys_capability.c      Fri Oct 21 16:12:09 2016        
(r307733)
+++ head/sys/kern/sys_capability.c      Fri Oct 21 16:12:23 2016        
(r307734)
@@ -89,6 +89,8 @@ SYSCTL_INT(_kern, OID_AUTO, trap_enotcap
 
 #ifdef CAPABILITY_MODE
 
+#define        IOCTLS_MAX_COUNT        256     /* XXX: Is 256 sane? */
+
 FEATURE(security_capability_mode, "Capsicum Capability Mode");
 
 /*
@@ -398,6 +400,11 @@ kern_cap_ioctls_limit(struct thread *td,
 
        AUDIT_ARG_FD(fd);
 
+       if (ncmds > IOCTLS_MAX_COUNT) {
+               error = EINVAL;
+               goto out_free;
+       }
+
        fdp = td->td_proc->p_fd;
        FILEDESC_XLOCK(fdp);
 
@@ -418,6 +425,7 @@ kern_cap_ioctls_limit(struct thread *td,
        error = 0;
 out:
        FILEDESC_XUNLOCK(fdp);
+out_free:
        free(cmds, M_FILECAPS);
        return (error);
 }
@@ -431,7 +439,7 @@ sys_cap_ioctls_limit(struct thread *td, 
 
        ncmds = uap->ncmds;
 
-       if (ncmds > 256)        /* XXX: Is 256 sane? */
+       if (ncmds > IOCTLS_MAX_COUNT)
                return (EINVAL);
 
        if (ncmds == 0) {
@@ -453,45 +461,59 @@ sys_cap_ioctls_get(struct thread *td, st
 {
        struct filedesc *fdp;
        struct filedescent *fdep;
-       u_long *cmds;
-       size_t maxcmds;
+       u_long *cmdsp, *dstcmds;
+       size_t maxcmds, ncmds;
+       int16_t count;
        int error, fd;
 
        fd = uap->fd;
-       cmds = uap->cmds;
+       dstcmds = uap->cmds;
        maxcmds = uap->maxcmds;
 
        AUDIT_ARG_FD(fd);
 
        fdp = td->td_proc->p_fd;
-       FILEDESC_SLOCK(fdp);
 
-       if (fget_locked(fdp, fd) == NULL) {
+       cmdsp = NULL;
+       if (dstcmds != NULL) {
+               cmdsp = malloc(sizeof(cmdsp[0]) * IOCTLS_MAX_COUNT, M_FILECAPS,
+                   M_WAITOK | M_ZERO);
+       }
+
+       FILEDESC_SLOCK(fdp);
+       fdep = fdeget_locked(fdp, fd);
+       if (fdep == NULL) {
                error = EBADF;
+               FILEDESC_SUNLOCK(fdp);
                goto out;
        }
+       count = fdep->fde_nioctls;
+       if (count != -1 && cmdsp != NULL) {
+               ncmds = MIN(count, maxcmds);
+               memcpy(cmdsp, fdep->fde_ioctls, sizeof(cmdsp[0]) * ncmds);
+       }
+       FILEDESC_SUNLOCK(fdp);
 
        /*
         * If all ioctls are allowed (fde_nioctls == -1 && fde_ioctls == NULL)
         * the only sane thing we can do is to not populate the given array and
         * return CAP_IOCTLS_ALL.
         */
-
-       fdep = &fdp->fd_ofiles[fd];
-       if (cmds != NULL && fdep->fde_ioctls != NULL) {
-               error = copyout(fdep->fde_ioctls, cmds,
-                   sizeof(cmds[0]) * MIN(fdep->fde_nioctls, maxcmds));
-               if (error != 0)
-                       goto out;
-       }
-       if (fdep->fde_nioctls == -1)
+       if (count != -1) {
+               if (cmdsp != NULL) {
+                       error = copyout(cmdsp, dstcmds,
+                           sizeof(cmdsp[0]) * ncmds);
+                       if (error != 0)
+                               goto out;
+               }
+               td->td_retval[0] = count;
+       } else {
                td->td_retval[0] = CAP_IOCTLS_ALL;
-       else
-               td->td_retval[0] = fdep->fde_nioctls;
+       }
 
        error = 0;
 out:
-       FILEDESC_SUNLOCK(fdp);
+       free(cmdsp, M_FILECAPS);
        return (error);
 }
 
_______________________________________________
svn-src-all@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-all
To unsubscribe, send any mail to "svn-src-all-unsubscr...@freebsd.org"

Reply via email to