svn commit: r232692 - head/sys/ufs/ffs
Peter Holm
peter at holm.cc
Fri Mar 9 17:18:21 UTC 2012
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
More information about the svn-src-all
mailing list