Author: mjg
Date: Wed Mar 28 03:07:02 2018
New Revision: 331657
URL: https://svnweb.freebsd.org/changeset/base/331657

Log:
  fd: tighten seq protected areas to not contain malloc/free

Modified:
  head/sys/kern/kern_descrip.c

Modified: head/sys/kern/kern_descrip.c
==============================================================================
--- head/sys/kern/kern_descrip.c        Tue Mar 27 22:49:06 2018        
(r331656)
+++ head/sys/kern/kern_descrip.c        Wed Mar 28 03:07:02 2018        
(r331657)
@@ -111,6 +111,11 @@ static void        fdgrowtable_exp(struct filedesc *fdp, 
int 
 static void    fdunused(struct filedesc *fdp, int fd);
 static void    fdused(struct filedesc *fdp, int fd);
 static int     getmaxfd(struct thread *td);
+static u_long  *filecaps_copy_prep(const struct filecaps *src);
+static void    filecaps_copy_finish(const struct filecaps *src,
+                   struct filecaps *dst, u_long *ioctls);
+static u_long  *filecaps_free_prep(struct filecaps *fcaps);
+static void    filecaps_free_finish(u_long *ioctls);
 
 /*
  * Each process has:
@@ -302,12 +307,12 @@ fdfree(struct filedesc *fdp, int fd)
 #ifdef CAPABILITIES
        seq_write_begin(&fde->fde_seq);
 #endif
-       fdefree_last(fde);
        fde->fde_file = NULL;
-       fdunused(fdp, fd);
 #ifdef CAPABILITIES
        seq_write_end(&fde->fde_seq);
 #endif
+       fdefree_last(fde);
+       fdunused(fdp, fd);
 }
 
 void
@@ -813,6 +818,7 @@ kern_dup(struct thread *td, u_int mode, int flags, int
        struct filedescent *oldfde, *newfde;
        struct proc *p;
        struct file *delfp;
+       u_long *oioctls, *nioctls;
        int error, maxfd;
 
        p = td->td_proc;
@@ -902,15 +908,18 @@ kern_dup(struct thread *td, u_int mode, int flags, int
        newfde = &fdp->fd_ofiles[new];
        delfp = newfde->fde_file;
 
+       oioctls = filecaps_free_prep(&newfde->fde_caps);
+       nioctls = filecaps_copy_prep(&oldfde->fde_caps);
+
        /*
         * Duplicate the source descriptor.
         */
 #ifdef CAPABILITIES
        seq_write_begin(&newfde->fde_seq);
 #endif
-       filecaps_free(&newfde->fde_caps);
        memcpy(newfde, oldfde, fde_change_size);
-       filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps, true);
+       filecaps_copy_finish(&oldfde->fde_caps, &newfde->fde_caps,
+           nioctls);
        if ((flags & FDDUP_FLAG_CLOEXEC) != 0)
                newfde->fde_flags = oldfde->fde_flags | UF_EXCLOSE;
        else
@@ -918,6 +927,7 @@ kern_dup(struct thread *td, u_int mode, int flags, int
 #ifdef CAPABILITIES
        seq_write_end(&newfde->fde_seq);
 #endif
+       filecaps_free_finish(oioctls);
        td->td_retval[0] = new;
 
        error = 0;
@@ -1503,6 +1513,40 @@ filecaps_copy(const struct filecaps *src, struct filec
        return (0);
 }
 
+static u_long *
+filecaps_copy_prep(const struct filecaps *src)
+{
+       u_long *ioctls;
+       size_t size;
+
+       if (src->fc_ioctls == NULL)
+               return (NULL);
+
+       KASSERT(src->fc_nioctls > 0,
+           ("fc_ioctls != NULL, but fc_nioctls=%hd", src->fc_nioctls));
+
+       size = sizeof(src->fc_ioctls[0]) * src->fc_nioctls;
+       ioctls = malloc(size, M_FILECAPS, M_WAITOK);
+       return (ioctls);
+}
+
+static void
+filecaps_copy_finish(const struct filecaps *src, struct filecaps *dst,
+    u_long *ioctls)
+{
+       size_t size;
+
+       *dst = *src;
+       if (src->fc_ioctls == NULL) {
+               MPASS(ioctls == NULL);
+               return;
+       }
+
+       size = sizeof(src->fc_ioctls[0]) * src->fc_nioctls;
+       dst->fc_ioctls = ioctls;
+       bcopy(src->fc_ioctls, dst->fc_ioctls, size);
+}
+
 /*
  * Move filecaps structure to the new place and clear the old place.
  */
@@ -1538,6 +1582,23 @@ filecaps_free(struct filecaps *fcaps)
        bzero(fcaps, sizeof(*fcaps));
 }
 
+static u_long *
+filecaps_free_prep(struct filecaps *fcaps)
+{
+       u_long *ioctls;
+
+       ioctls = fcaps->fc_ioctls;
+       bzero(fcaps, sizeof(*fcaps));
+       return (ioctls);
+}
+
+static void
+filecaps_free_finish(u_long *ioctls)
+{
+
+       free(ioctls, M_FILECAPS);
+}
+
 /*
  * Validate the given filecaps structure.
  */
@@ -2963,6 +3024,7 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int
 {
        struct filedescent *newfde, *oldfde;
        struct file *fp;
+       u_long *ioctls;
        int error, indx;
 
        KASSERT(openerror == ENODEV || openerror == ENXIO,
@@ -3007,11 +3069,13 @@ dupfdopen(struct thread *td, struct filedesc *fdp, int
                fhold(fp);
                newfde = &fdp->fd_ofiles[indx];
                oldfde = &fdp->fd_ofiles[dfd];
+               ioctls = filecaps_copy_prep(&oldfde->fde_caps);
 #ifdef CAPABILITIES
                seq_write_begin(&newfde->fde_seq);
 #endif
                memcpy(newfde, oldfde, fde_change_size);
-               filecaps_copy(&oldfde->fde_caps, &newfde->fde_caps, true);
+               filecaps_copy_finish(&oldfde->fde_caps, &newfde->fde_caps,
+                   ioctls);
 #ifdef CAPABILITIES
                seq_write_end(&newfde->fde_seq);
 #endif
_______________________________________________
svn-src-head@freebsd.org mailing list
https://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "svn-src-head-unsubscr...@freebsd.org"

Reply via email to