Hi I discovered that there's a off by one bug in the bounds checking in statcheck(), convM2D(), convD2M() and convM2S(). For example in convM2D() it sets ebuf as: ebuf = buf + nbuf; and then checks if reads will go past ebuf. But ebuf will point to the first byte after the buffer, so past ebuf will include the byte after the buffer. So it can potentially try to read of write to one byte past the buffer in all these functions. -- Erik Dalén dalen@socialisterna.org
> For example in convM2D() it sets ebuf as:
> ebuf = buf + nbuf;
>
> and then checks if reads will go past ebuf. But ebuf will point to the
> first byte after the buffer, so past ebuf will include the byte after
> the buffer. So it can potentially try to read of write to one byte
> past the buffer in all these functions.
it would if it tries to access that byte but it doesn't in convM2D.c or convD2M.c
it's checking that the resulting pointer after accessing the bytes will still be <= ebuf,
which (i think) is correct.
On 11/9/07, Charles Forsyth <forsyth@terzarima.net> wrote:
> > For example in convM2D() it sets ebuf as:
> > ebuf = buf + nbuf;
> >
> > and then checks if reads will go past ebuf. But ebuf will point to the
> > first byte after the buffer, so past ebuf will include the byte after
> > the buffer. So it can potentially try to read of write to one byte
> > past the buffer in all these functions.
>
> it would if it tries to access that byte but it doesn't in convM2D.c or convD2M.c
> it's checking that the resulting pointer after accessing the bytes will still be <= ebuf,
> which (i think) is correct.
>
On second thought I think you are correct. At the end of the function
the pointer might be one byte past the buffer size, but then it won't
do any reads or writes (But it could be a problem if the buffer is
right at the end of the virtual memory space :). Sorry about the buggy
bug report.
--
Erik Dalén
dalen@socialisterna.org
> (But it could be a problem if the buffer is
> right at the end of the virtual memory space :). Sorry about the buggy ...
that will be a problem if the hardware is sloppy, but it would be true regardless how
you wrote the test (because it's the resulting prefetch addresses that then matter).
i think hardware designers now know about this problem (since it's fairly old)
but that probably hasn't stopped a few from not including it in the processor manual
but slipping it instead into the errata.
> On second thought I think you are correct. At the end of the function
> the pointer might be one byte past the buffer size, but then it won't
> do any reads or writes (But it could be a problem if the buffer is
> right at the end of the virtual memory space :). Sorry about the buggy
> bug report.
The buffer can't be right at the end of the virtual memory space.
The C standard guarantees (or rather, requires) that whenever
you've got an allocated buffer, computing the pointer just past
(some would say at) the end of the buffer can be done without
address overflow, precisely because that kind of bounds check
is such a common idiom.
Russ
Erik Dalén wrote:
> On second thought I think you are correct. At the end of the function
> the pointer might be one byte past the buffer size, but then it won't
> do any reads or writes (But it could be a problem if the buffer is
> right at the end of the virtual memory space :).
The C standard requires that pointer arithmetic work properly
for one-past-the-end pointers. On some architectures that may
mean that each data segment has to have an extra (unused) byte
allocated, but on most architectures nothing special has to be
done.
> Erik Dalén wrote:
> > On second thought I think you are correct. At the end of the function
> > the pointer might be one byte past the buffer size, but then it won't
> > do any reads or writes (But it could be a problem if the buffer is
> > right at the end of the virtual memory space :).
>
> The C standard requires that pointer arithmetic work properly
> for one-past-the-end pointers. On some architectures that may
> mean that each data segment has to have an extra (unused) byte
> allocated, but on most architectures nothing special has to be
> done.
i think what he's saying is that for machines with unsigned ptr
arithmetic, on a 16-bit machine, ~0 (0xffff) is not a legal address;
on a 32-bit machine ~0 (0xffffff) is not a legal address; &c. on a
machine with page-based vm, i think this means the highest page
isn't kosher. (if signed, the problem is at 0x7f(ff)*.) this is because
for all addresses a except ~0 a < a+1. i suppose you could hand
out all but the last 2 bytes of the final page.
i don't think it means you have to allocate an extra byte. there's
no requirement that you may indirect the "one-past the end" address.
- erik
erik quanstrom wrote:
> i don't think it means you have to allocate an extra byte. there's
> no requirement that you may indirect the "one-past the end" address.
No, but (a) the arithmetic has to work properly, including
relations like "p < q", and on some architectures merely
loading a past-the-segment-end address into an address
register can cause an invalid-address trap. Thus, the C
implementation when it lays out the data objects in
segments may have to make sure that the segment contains
an extra unused byte at the end, just so its address will
be valid.