Martin Natano wrote:
> Stefan Kempf wrote:
> > I'm a bit uneasy though with passing signed values as-is to uiomove().
> > Can we somehow make it explicit that we know that the uiomove() argument is
> > >= 0?
> > 
> > Changing types all over the place would be too much churn though.
> > 
> > I'm leaning towards an explicit size_t cast for signed size arguments as
> > an annotation, e.g.
> >     uiomove(buf, (size_t)signed_value, uio);
> 
> I agree, a cast like that would make the intent clear to the reader. See
> the regenerated diff below.
> 
> 
> > And a check in uiomove(). If a negative value gets passed in by
> > accident, it will be caught.
> > 
> > Thoughts?
> >  
> > Index: kern_subr.c
> > ===================================================================
> > RCS file: /cvs/src/sys/kern/kern_subr.c,v
> > retrieving revision 1.45
> > diff -u -p -U10 -r1.45 kern_subr.c
> > --- kern_subr.c     11 Dec 2015 16:07:02 -0000      1.45
> > +++ kern_subr.c     17 Jan 2016 10:56:11 -0000
> > @@ -46,20 +46,23 @@
> >  #include <sys/resourcevar.h>
> >  
> >  int
> >  uiomove(void *cp, size_t n, struct uio *uio)
> >  {
> >     struct iovec *iov;
> >     size_t cnt;
> >     int error = 0;
> >     struct proc *p;
> >  
> > +   if (n > SSIZE_MAX)
> > +           return (EINVAL);
> > +
> >     p = uio->uio_procp;
> >  
> >  #ifdef DIAGNOSTIC
> >     if (uio->uio_rw != UIO_READ && uio->uio_rw != UIO_WRITE)
> >             panic("uiomove: mode");
> >     if (uio->uio_segflg == UIO_USERSPACE && p != curproc)
> >             panic("uiomove: proc");
> >  #endif
> >     while (n > 0 && uio->uio_resid) {
> >             iov = uio->uio_iov;
> 
> I don't think this will fix the underlying problem. It is not possible
> to detect all types of overflow inside of uiomove(). Let's take a look
> at our tmpfs example: An off_t value is passed to uimove(). On i386,
> size_t is an unsigned 32 bit integer and off_t is a signed 64 bit
> integer.  When the off_t value is truncated on conversion, the
> 'if (n > SSIZE_MAX)' condition might trigger, or not, depending on the
> exact value of the original off_t value, resulting in unreliable
> behaviour.

D'oh. Yes, you are right. It's too late for such a check in uiomove().
Let's go with your second diff then.
 
> Unfortunately, I think the best we can do is to audit and fix all
> uiomove() callers, which we already do for the purpose of the
> conversion.
> 
> cheers,
> natano
> 
> 
> Index: tmpfs_subr.c
> ===================================================================
> RCS file: /cvs/src/sys/tmpfs/tmpfs_subr.c,v
> retrieving revision 1.14
> diff -u -p -u -r1.14 tmpfs_subr.c
> --- tmpfs_subr.c      17 Apr 2015 04:43:21 -0000      1.14
> +++ tmpfs_subr.c      17 Jan 2016 12:05:59 -0000
> @@ -740,7 +740,7 @@ tmpfs_dir_getdotents(tmpfs_node_t *node,
>               return EJUSTRETURN;
>       }
>  
> -     if ((error = uiomovei(dp, dp->d_reclen, uio)) != 0) {
> +     if ((error = uiomove(dp, dp->d_reclen, uio)) != 0) {
>               return error;
>       }
>  
> @@ -837,7 +837,7 @@ tmpfs_dir_getdents(tmpfs_node_t *node, s
>               }
>  
>               /* Copy out the directory entry and continue. */
> -             error = uiomovei(&dent, dent.d_reclen, uio);
> +             error = uiomove(&dent, dent.d_reclen, uio);
>               if (error) {
>                       break;
>               }
> @@ -1225,7 +1225,7 @@ tmpfs_uiomove(tmpfs_node_t *node, struct
>       if (pgoff + len < PAGE_SIZE) {
>               va = tmpfs_uio_lookup(node, pgnum);
>               if (va != (vaddr_t)NULL)
> -                     return uiomovei((void *)va + pgoff, len, uio);
> +                     return uiomove((void *)va + pgoff, len, uio);
>       }
>  
>       if (len >= TMPFS_UIO_MAXBYTES) {
> @@ -1249,7 +1249,7 @@ tmpfs_uiomove(tmpfs_node_t *node, struct
>               return error;
>       }
>  
> -     error = uiomovei((void *)va + pgoff, sz, uio);
> +     error = uiomove((void *)va + pgoff, sz, uio);
>       if (error == 0 && pgoff + sz < PAGE_SIZE)
>               tmpfs_uio_cache(node, pgnum, va);
>       else
> Index: tmpfs_vnops.c
> ===================================================================
> RCS file: /cvs/src/sys/tmpfs/tmpfs_vnops.c,v
> retrieving revision 1.23
> diff -u -p -u -r1.23 tmpfs_vnops.c
> --- tmpfs_vnops.c     8 Dec 2015 15:26:25 -0000       1.23
> +++ tmpfs_vnops.c     17 Jan 2016 12:06:12 -0000
> @@ -1017,8 +1017,8 @@ tmpfs_readlink(void *v)
>       KASSERT(vp->v_type == VLNK);
>  
>       node = VP_TO_TMPFS_NODE(vp);
> -     error = uiomovei(node->tn_spec.tn_lnk.tn_link,
> -         MIN(node->tn_size, uio->uio_resid), uio);
> +     error = uiomove(node->tn_spec.tn_lnk.tn_link,
> +         MIN((size_t)node->tn_size, uio->uio_resid), uio);
>       tmpfs_update(node, TMPFS_NODE_ACCESSED);
>  
>       return error;

Reply via email to