On Sat, Mar 10, 2012 at 01:48:20AM +1100, Bruce Evans wrote:
> On Fri, 9 Mar 2012, Peter Holm wrote:
> 
> >On Fri, Mar 09, 2012 at 03:51:30PM +1100, Bruce Evans wrote:
> >>On Thu, 8 Mar 2012, Peter Holm wrote:
> >>
> >>>Log:
> >>>syscall() fuzzing can trigger this panic. Return EINVAL instead.
> >>>
> >>>MFC after: 1 week
> >>
> >>If so, then, this is not the place to hide the bug.
> >
> >OK
> >
> >This specific problem here was discover by:
> >
> >       for (i = 0; i < 2000; i++) {
> >               if ((dirp = opendir(path)) == NULL)
> >                       break;
> >               bcopy(dirp, &fuzz, sizeof(fuzz));
> >               fuzz.dd_len = arc4random();
> >               readdir(&fuzz);
> >               closedir(dirp);
> >       }
> 
> Try this fix.  You already fixed getdirentries() in 2008, but it was
> broken recently.
> 
> % Index: vfs_syscalls.c
> % ===================================================================
> % RCS file: /home/ncvs/src/sys/kern/vfs_syscalls.c,v
> % retrieving revision 1.522
> % diff -u -2 -r1.522 vfs_syscalls.c
> % --- vfs_syscalls.c  21 Feb 2012 01:05:12 -0000      1.522
> % +++ vfs_syscalls.c  9 Mar 2012 14:22:57 -0000
> % @@ -4154,7 +4154,7 @@
> % 
> %     AUDIT_ARG_FD(fd);
> % -   auio.uio_resid = count;
> % -   if (auio.uio_resid > IOSIZE_MAX)
> % +   if (count > IOSIZE_MAX)
> %             return (EINVAL);
> % +   auio.uio_resid = count;
> %     if ((error = getvnode(td->td_proc->p_fd, fd, CAP_READ | CAP_SEEK,
> %         &fp)) != 0)
> 
> The broken version checked `count' only after possibly clobbering it.
> Clobbering occurs in practice on 32-bit arches, since then uio_resid
> has type int so it cannot hold a value of INT_MAX + 1U.  The behaviour
> was undefined.  The actual behaviour was normally to store a negative
> value in uio_resid.  Comparing this with IOSIZE_MAX then always passed,
> since IOSIZE_MAX is a large int.
> 
> `count' only has type u_int, not the usual size_t.  It would be safer
> to keep comparing it with INT_MAX.  Supporting directory reads of more
> than INT_MAX bytes is even more useless bloat than supporting regular
> files reads of more than INT_MAX bytes.  But it seems safe enough.
> The limit is still INT_MAX on 32-bit arches.  On 64-bit arches, it is
> now UINT_MAX = 2**32-1, not actually IOSIZE_MAX = 2**63-1 like the code
> checks for, since u_int can't go nearly as high as IOSIZE_MAX.  At least
> after the above change, the compiler should see that the check always
> passes, and not generate any code for it, and maybe complain about it.
> Perhaps this is why it was broken.  However, the compiler can't see this
> now, since IOSIZE_MAX is actually a macro that depends on a configuration
> variable, so it isn't always > UINT_MAX on 64-bit arches.  Without the
> dynamic configuration, the broken check would obviously always pass on
> 32-bit arches, and the compiler complaining about it would be just what
> was required to avoid the bug.  And even with dynamic configuration, it
> is almost obvious that the check always passed, since IOSIZE_MAX is
> (var ? INT_MAX : SSIZE_MAX), which is always INT_MAX.
> 
> Bruce

Thank you for the analysis. I have tested your patch, without r232692
and it works as expected.
I'll back out r232692.

Thank you.

-- 
Peter
_______________________________________________
[email protected] mailing list
http://lists.freebsd.org/mailman/listinfo/svn-src-head
To unsubscribe, send any mail to "[email protected]"

Reply via email to