svn commit: r328346 - in head/sys: fs/ext2fs ufs/ffs ufs/ufs

Pedro Giffuni pfg at FreeBSD.org
Thu Jan 25 20:01:25 UTC 2018


On 25/01/2018 14:24, Bruce Evans wrote:
> On Thu, 25 Jan 2018, Pedro Giffuni wrote:
>
> This is almost unreadable due to hard-coded UTF-8 (mostly for tabs 
> corrupted
> to spaces) even in previously-literally quoted C code.
>
Mailer agents ... they all suck :(
>> On 01/25/18 11:28, Bruce Evans wrote:
>>> On Wed, 24 Jan 2018, Pedro F. Giffuni wrote:
>
> [... Most unreadable lines deleted]
>
>>> X     ncookies = uio->uio_resid;
>>>
>>> This has a more serious type error and consequent overflow bugs. 
>>> uio_resid
>>> used to have type int, and cookies had to have type int to match 
>>> that, else
>>> there overflow occurs before the bounds checks.  Now uio_resid has type
>>> ssize_t, which is excessively large on 64-bit arches (64 bits then), 
>>> so the
>>> assignment overflowed when ncookies had type int and uio_resid > 
>>> INT_MAX.
>>> Now it overflows differently when uio_resid > UINT_MAX, and unsign 
>>> extension
>>> causes overflow when uio_resid < 0.  There might be a sanity check on
>>> uio_resid at higher levels, but I can only find a check related to 
>>> EOF in
>>> vfs_read_dirent().
>>>
>> I will argue that none of the code in this function is prepared for 
>> the eventually of
>> uio->uio_resid < 0
>
> All of it except the cookies code has to be prepared for that, and seems
> to handle it OK, since this userland can set uio_resid.  The other code
> is not broken by either the ssize_t expansion or the unsigned bugs, since
> it mostly doesn't truncate uio_resid by assigning it to a variable of the
> wrong type (it uses uio->uio_resid in-place, except for copying its 
> initial
> value to startresid, and startresid is not missing the ssize_t 
> expansion).
> It mostly does comparisons of the form (uio->uio_resid > 0), where it is
> 0 in uio_resid means EOF, negative is treated as EOF, and strictly 
> positive
> means more to do.
>
> There is a clear up-front check that uio_offset >= 0 (return EINVAL if
> uio_offset < 0).  This is not needed for the trusted nfs caller, but is
> needed for syscalls and is done for both.
>
>> In that case we would have a rather spectacular failure in malloc.
>> Unsigning ncookies is a theoretical, although likely impractical, 
>> improvement here.
>
> No, it increases the bug slightly.  E.g., if uio_resid is -1, ncookies
> was -1 / (offsetof(...) + 4) + 1 = 0 + 1 after rounding.  This might even
> work (1 cookie at a time, just like if the caller asked for that).  Now
> ncookies is -1U / (offsetof(...) + 4) + 1 = a large value. However, if
> uio_resid was slightly more negative than -2 * (offsetof(...) + 4), then
> ncookies was -1 and in the multiplication this overflows to -1U = a large
> value and the result is much the same as for earlier overflow on 
> assignment
> to u_int ncookies.
>
> This code only works because (if?) nfs is the only caller and nfs never
> passes insane values.
>

I am starting to think that we should simply match uio_resid and set it 
to ssize_t.
Returning the value to int is certainly not the solution.

>> It is not clear to me that using int or u_int makes a difference 
>> given it is a local variable
>> and in this scope the signedness of the variable is basically 
>> irrelevant.
>
> It is clear to me that overflow bugs occur with both if untrusted 
> callers are
> allowed.
>
>> From a logical point of view .. we can't really have a negative 
>> number of cookies.
>
> Malicious and buggy callers do illogical things to get through holes in
> your logic.
>
> It is also illogical to have a zero number of cookies, but ncookies can
> be 0 in various ways.  First, ncookies is 0 in the EOF case (and cookies
> are requested).  We depend on 0 not being an invalid size for malloc()
> so that we malloc() nothing and later do more nothings in the main loop.
> This is a standard use for 0.  If you don't like negative numbers, then
> you also shouldn't like 0.  Both exist to make some calculations easier.
> Later, ncookies is abused as a residual count, so it becomes 0 at the 
> end.
> This is another standard use for 0.
>
> Bruce



More information about the svn-src-head mailing list