Follow @Openwall on Twitter for new release announcements and other news
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Date: Thu, 27 Jun 2013 00:10:28 -0400
From: Rich Felker <dalias@...ifal.cx>
To: musl@...ts.openwall.com
Subject: Re: Use of size_t and ssize_t in mseek

On Thu, Jun 27, 2013 at 01:52:01PM +1000, Matthew Fernandez wrote:
> Hi all,
> 
> My question refers to the latest git commit at time of writing,
> b17c75a4d539d7ec5b81cc7ce7ce6b065a87e7a6. My issue was encountered on
> ARM, but it applies to most 32-bit platforms.
> 
> The function mseek() accesses a size_t variable, c->size, and casts this
> to a ssize_t. I know there aren't strong standards on what to expect
> from ssize_t, but the Musl C constants SIZE_MAX (== UINT32_MAX) and
> SSIZE_MAX (== LONG_MAX) seem to imply that you would be wise to assume
> ssize_t is signed and the same width as size_t.
> 
> As a result, the cast I mentioned produces some unexpected results when
> operating on a file of size greater than SSIZE_MAX. In my case I had an
> in-memory file of size SIZE_MAX and was surprised to find I couldn't
> fseek this file.
> 
> Is the code in mseek() correct? If so, I would recommend failing
> fmemopen() when the requested size is greater than SSIZE_MAX. OTOH
> perhaps I'm misunderstanding something more subtle here. If so, please
> correct me.

The argument to a function like fmemopen that takes a size_t
representing the size of an object must actually correspond to the
size of an object. It's always been the intent in musl that objects
larger than SSIZE_MAX (which is also PTRDIFF_MAX) not be able to
exist, since they result in overflow (and undefined behavior) if you
subtract pointers within them, and implementation-defined behavior if
you pass their sizes to functions like read, write, etc. The malloc
implementation in musl explicitly rejects size arguments greater than
SSIZE_MAX, with the intent of ensuring that such objects don't exist,
so as far as I can tell, the only remaining "backdoor" to get such an
object is mmap.

Unless there are strong objections, I'd like to make mmap reject such
sizes too. On 32-bit archs, the maximum vm size is already bounded by
3gb, and once you get the program and a few shared libraries loaded
too, it's a good bit less, so it would be hard to map more than 2.5gb
or so anyway.

Once all the doors to obtaining objects of size greater than SSIZE_MAX
are closed, the issue goes away entirely. If you pass a size greater
than SSIZE_MAX to fmemopen or similar functions, it can't actually be
the correct size of the object (since no object that large exists),
and thus you must be invoking UB by passing an incorrect size, so it
doesn't matter what the function does.

Does this all make sense and sound reasonable?

Rich

Powered by blists - more mailing lists

Confused about mailing lists and their use? Read about mailing lists on Wikipedia and check out these guidelines on proper formatting of your messages.